feat: 新增媒体通知
This commit is contained in:
@ -45,7 +45,7 @@
|
|||||||
android:fullBackupContent="false"
|
android:fullBackupContent="false"
|
||||||
tools:replace="android:allowBackup">
|
tools:replace="android:allowBackup">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name="com.ryanheise.audioservice.AudioServiceActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
@ -226,6 +226,24 @@
|
|||||||
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<service
|
||||||
|
android:name="com.ryanheise.audioservice.AudioService"
|
||||||
|
android:foregroundServiceType="mediaPlayback"
|
||||||
|
android:exported="true"
|
||||||
|
tools:ignore="Instantiatable">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.media.browse.MediaBrowserService" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name="com.ryanheise.audioservice.MediaButtonReceiver"
|
||||||
|
android:exported="true"
|
||||||
|
tools:ignore="Instantiatable">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
@ -238,6 +256,8 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
<!--
|
<!--
|
||||||
Media access permissions.
|
Media access permissions.
|
||||||
Android 13 or higher.
|
Android 13 or higher.
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
BIN
android/app/src/main/res/drawable-xxhdpi/ic_stat_replay_10.png
Normal file
BIN
android/app/src/main/res/drawable-xxhdpi/ic_stat_replay_10.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/ic_stat_forward_10.png
Normal file
BIN
android/app/src/main/res/drawable-xxxhdpi/ic_stat_forward_10.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/ic_stat_replay_10.png
Normal file
BIN
android/app/src/main/res/drawable-xxxhdpi/ic_stat_replay_10.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
@ -103,5 +103,9 @@
|
|||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
<key>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>audio</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -16,6 +16,7 @@ import 'package:pilipala/pages/search/index.dart';
|
|||||||
import 'package:pilipala/pages/video/detail/index.dart';
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/router/app_pages.dart';
|
import 'package:pilipala/router/app_pages.dart';
|
||||||
import 'package:pilipala/pages/main/view.dart';
|
import 'package:pilipala/pages/main/view.dart';
|
||||||
|
import 'package:pilipala/services/service_locator.dart';
|
||||||
import 'package:pilipala/utils/app_scheme.dart';
|
import 'package:pilipala/utils/app_scheme.dart';
|
||||||
import 'package:pilipala/utils/data.dart';
|
import 'package:pilipala/utils/data.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
@ -28,6 +29,7 @@ void main() async {
|
|||||||
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
|
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
|
||||||
.then((_) async {
|
.then((_) async {
|
||||||
await GStrorage.init();
|
await GStrorage.init();
|
||||||
|
await setupServiceLocator();
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
// 小白条、导航栏沉浸
|
// 小白条、导航栏沉浸
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||||
|
@ -12,6 +12,7 @@ import 'package:pilipala/common/widgets/stat/view.dart';
|
|||||||
import 'package:pilipala/models/video_detail_res.dart';
|
import 'package:pilipala/models/video_detail_res.dart';
|
||||||
import 'package:pilipala/pages/video/detail/introduction/controller.dart';
|
import 'package:pilipala/pages/video/detail/introduction/controller.dart';
|
||||||
import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart';
|
import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart';
|
||||||
|
import 'package:pilipala/services/service_locator.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
@ -51,12 +52,14 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
|||||||
_futureBuilderFuture = videoIntroController.queryVideoIntro();
|
_futureBuilderFuture = videoIntroController.queryVideoIntro();
|
||||||
videoIntroController.videoDetail.listen((value) {
|
videoIntroController.videoDetail.listen((value) {
|
||||||
videoDetail = value;
|
videoDetail = value;
|
||||||
|
videoPlayerServiceHandler.onVideoIntroChange(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
videoIntroController.onClose();
|
videoIntroController.onClose();
|
||||||
|
videoPlayerServiceHandler.onVideoIntroDispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:easy_debounce/easy_throttle.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
||||||
@ -14,6 +15,7 @@ import 'package:ns_danmaku/ns_danmaku.dart';
|
|||||||
import 'package:pilipala/http/video.dart';
|
import 'package:pilipala/http/video.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
||||||
|
import 'package:pilipala/services/service_locator.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:screen_brightness/screen_brightness.dart';
|
import 'package:screen_brightness/screen_brightness.dart';
|
||||||
@ -526,12 +528,24 @@ class PlPlayerController {
|
|||||||
}),
|
}),
|
||||||
videoPlayerController!.stream.buffering.listen((event) {
|
videoPlayerController!.stream.buffering.listen((event) {
|
||||||
isBuffering.value = event;
|
isBuffering.value = event;
|
||||||
|
videoPlayerServiceHandler.onStatusChange(
|
||||||
|
playerStatus.status.value, event);
|
||||||
}),
|
}),
|
||||||
// videoPlayerController!.stream.volume.listen((event) {
|
// videoPlayerController!.stream.volume.listen((event) {
|
||||||
// if (!mute.value && _volumeBeforeMute != event) {
|
// if (!mute.value && _volumeBeforeMute != event) {
|
||||||
// _volumeBeforeMute = event / 100;
|
// _volumeBeforeMute = event / 100;
|
||||||
// }
|
// }
|
||||||
// }),
|
// }),
|
||||||
|
// 媒体通知监听
|
||||||
|
onPlayerStatusChanged.listen((event) {
|
||||||
|
videoPlayerServiceHandler.onStatusChange(event, isBuffering.value);
|
||||||
|
}),
|
||||||
|
onPositionChanged.listen((event) {
|
||||||
|
EasyThrottle.throttle(
|
||||||
|
'mediaServicePositon',
|
||||||
|
const Duration(seconds: 1),
|
||||||
|
() => videoPlayerServiceHandler.onPositionChange(event));
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
116
lib/services/audio_handler.dart
Normal file
116
lib/services/audio_handler.dart
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import 'package:audio_service/audio_service.dart';
|
||||||
|
import 'package:pilipala/models/video_detail_res.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
|
|
||||||
|
Future<VideoPlayerServiceHandler> initAudioService() async {
|
||||||
|
return await AudioService.init(
|
||||||
|
builder: () => VideoPlayerServiceHandler(),
|
||||||
|
config: const AudioServiceConfig(
|
||||||
|
androidNotificationChannelId: 'com.guozhigq.pilipala.audio',
|
||||||
|
androidNotificationChannelName: 'Audio Service Pilipala',
|
||||||
|
androidNotificationOngoing: true,
|
||||||
|
androidStopForegroundOnPause: true,
|
||||||
|
fastForwardInterval: Duration(seconds: 10),
|
||||||
|
rewindInterval: Duration(seconds: 10),
|
||||||
|
androidNotificationChannelDescription: 'Media notification channel',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class VideoPlayerServiceHandler extends BaseAudioHandler
|
||||||
|
with QueueHandler, SeekHandler {
|
||||||
|
static final List<MediaItem> _item = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> play() async {
|
||||||
|
PlPlayerController.getInstance().play();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> pause() async {
|
||||||
|
PlPlayerController.getInstance().pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> seek(Duration position) async {
|
||||||
|
playbackState.add(playbackState.value.copyWith(
|
||||||
|
updatePosition: position,
|
||||||
|
));
|
||||||
|
await PlPlayerController.getInstance().seekTo(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setMediaItem(MediaItem newMediaItem) async {
|
||||||
|
mediaItem.add(newMediaItem);
|
||||||
|
addQueueItem(newMediaItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setPlaybackState(PlayerStatus status, bool isBuffering) async {
|
||||||
|
final AudioProcessingState processingState;
|
||||||
|
final playing = status == PlayerStatus.playing;
|
||||||
|
if (status == PlayerStatus.completed) {
|
||||||
|
processingState = AudioProcessingState.completed;
|
||||||
|
} else if (isBuffering) {
|
||||||
|
processingState = AudioProcessingState.buffering;
|
||||||
|
} else {
|
||||||
|
processingState = AudioProcessingState.ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
playbackState.add(playbackState.value.copyWith(
|
||||||
|
processingState:
|
||||||
|
isBuffering ? AudioProcessingState.buffering : processingState,
|
||||||
|
controls: [
|
||||||
|
MediaControl.rewind.copyWith(androidIcon: 'drawable/ic_stat_replay_10'),
|
||||||
|
if (playing) MediaControl.pause else MediaControl.play,
|
||||||
|
MediaControl.fastForward
|
||||||
|
.copyWith(androidIcon: 'drawable/ic_stat_forward_10'),
|
||||||
|
],
|
||||||
|
playing: playing,
|
||||||
|
systemActions: const {
|
||||||
|
MediaAction.seek,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
onStatusChange(PlayerStatus status, bool isBuffering) {
|
||||||
|
if (_item.isEmpty) return;
|
||||||
|
setPlaybackState(status, isBuffering);
|
||||||
|
}
|
||||||
|
|
||||||
|
onVideoIntroChange(VideoDetailData data) {
|
||||||
|
Map argMap = Get.arguments;
|
||||||
|
final heroTag = argMap['heroTag'];
|
||||||
|
|
||||||
|
final mediaItem = MediaItem(
|
||||||
|
id: heroTag,
|
||||||
|
title: data.title ?? "",
|
||||||
|
artist: data.owner?.name ?? "",
|
||||||
|
duration: Duration(seconds: data.duration ?? 0),
|
||||||
|
artUri: Uri.parse(data.pic ?? ""),
|
||||||
|
);
|
||||||
|
setMediaItem(mediaItem);
|
||||||
|
_item.add(mediaItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
onVideoIntroDispose() {
|
||||||
|
playbackState.add(playbackState.value.copyWith(
|
||||||
|
processingState: AudioProcessingState.idle,
|
||||||
|
playing: false,
|
||||||
|
));
|
||||||
|
stop();
|
||||||
|
_item.removeLast();
|
||||||
|
if (_item.isNotEmpty) {
|
||||||
|
setMediaItem(_item.last);
|
||||||
|
}
|
||||||
|
if (_item.isEmpty) {
|
||||||
|
playbackState
|
||||||
|
.add(playbackState.value.copyWith(updatePosition: Duration.zero));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositionChange(Duration position) {
|
||||||
|
playbackState.add(playbackState.value.copyWith(
|
||||||
|
updatePosition: position,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
8
lib/services/service_locator.dart
Normal file
8
lib/services/service_locator.dart
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import 'audio_handler.dart';
|
||||||
|
|
||||||
|
late VideoPlayerServiceHandler videoPlayerServiceHandler;
|
||||||
|
|
||||||
|
Future<void> setupServiceLocator() async {
|
||||||
|
final audio = await initAudioService();
|
||||||
|
videoPlayerServiceHandler = audio;
|
||||||
|
}
|
@ -5,6 +5,8 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import audio_service
|
||||||
|
import audio_session
|
||||||
import connectivity_plus
|
import connectivity_plus
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import dynamic_color
|
import dynamic_color
|
||||||
@ -20,6 +22,8 @@ import url_launcher_macos
|
|||||||
import wakelock_plus
|
import wakelock_plus
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
||||||
|
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||||
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
|
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
||||||
|
76
pubspec.lock
76
pubspec.lock
@ -57,6 +57,38 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
version: "2.11.0"
|
||||||
|
audio_service:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: audio_service
|
||||||
|
sha256: a4d989f1225ea9621898d60f23236dcbfc04876fa316086c23c5c4af075dbac4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.18.12"
|
||||||
|
audio_service_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: audio_service_platform_interface
|
||||||
|
sha256: "8431a455dac9916cc9ee6f7da5620a666436345c906ad2ebb7fa41d18b3c1bf4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.1"
|
||||||
|
audio_service_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: audio_service_web
|
||||||
|
sha256: "523e64ddc914c714d53eec2da85bba1074f08cf26c786d4efb322de510815ea7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.1"
|
||||||
|
audio_session:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: audio_session
|
||||||
|
sha256: "8a2bc5e30520e18f3fb0e366793d78057fb64cd5287862c76af0c8771f2a52ad"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.16"
|
||||||
audio_video_progress_bar:
|
audio_video_progress_bar:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -213,10 +245,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.1"
|
version: "1.17.2"
|
||||||
connectivity_plus:
|
connectivity_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -373,18 +405,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: extended_image
|
name: extended_image
|
||||||
sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767
|
sha256: b4d72a27851751cfadaf048936d42939db7cd66c08fdcfe651eeaa1179714ee6
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.2"
|
version: "8.1.1"
|
||||||
extended_image_library:
|
extended_image_library:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: extended_image_library
|
name: extended_image_library
|
||||||
sha256: bb8d08c504ebc73d476ec1c99451a61f12e95538869e734fc4f55a3a2d5c98ec
|
sha256: "8bf87c0b14dcb59200c923a9a3952304e4732a0901e40811428834ef39018ee1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.5.3"
|
version: "3.6.0"
|
||||||
extended_list:
|
extended_list:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -665,10 +697,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: intl
|
name: intl
|
||||||
sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
|
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.18.0"
|
version: "0.18.1"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -737,18 +769,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.5.0"
|
||||||
media_kit:
|
media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1191,10 +1223,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
sqflite:
|
sqflite:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1279,10 +1311,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.0"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1475,6 +1507,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.4-beta"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1564,5 +1604,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0 <4.0.0"
|
dart: ">=3.1.0-185.0.dev <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.13.0"
|
||||||
|
@ -49,7 +49,7 @@ dependencies:
|
|||||||
|
|
||||||
# 图片
|
# 图片
|
||||||
cached_network_image: ^3.3.0
|
cached_network_image: ^3.3.0
|
||||||
extended_image: ^8.0.2
|
extended_image: ^8.1.1
|
||||||
saver_gallery: ^2.0.1
|
saver_gallery: ^2.0.1
|
||||||
|
|
||||||
# 存储
|
# 存储
|
||||||
@ -86,7 +86,10 @@ dependencies:
|
|||||||
# 视频播放器
|
# 视频播放器
|
||||||
media_kit: ^1.1.10 # Primary package.
|
media_kit: ^1.1.10 # Primary package.
|
||||||
media_kit_video: ^1.2.4 # For video rendering.
|
media_kit_video: ^1.2.4 # For video rendering.
|
||||||
media_kit_libs_video: ^1.0.4
|
media_kit_libs_video: ^1.0.4
|
||||||
|
|
||||||
|
# 媒体通知
|
||||||
|
audio_service: ^0.18.12
|
||||||
|
|
||||||
# 音量、亮度、屏幕控制
|
# 音量、亮度、屏幕控制
|
||||||
flutter_volume_controller: ^1.3.0
|
flutter_volume_controller: ^1.3.0
|
||||||
|
Reference in New Issue
Block a user