Reason Pun

重构了录音页面功能

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:one_poem/extension/int_extension.dart';
import 'package:one_poem/widgets/my_app_bar.dart';
import 'package:flutter_gen/gen_l10n/one_poem_localizations.dart';
......
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:one_poem/category/models/category_item_entity.dart';
import 'package:one_poem/poem/poem_router.dart';
......
......@@ -4,11 +4,8 @@
// This file is automatically generated. DO NOT EDIT, all your changes would be lost.
import 'package:one_poem/account/models/user_entity.dart';
import 'package:one_poem/generated/json/user_entity.g.dart';
import 'package:one_poem/category/models/category_item_entity.dart';
import 'package:one_poem/generated/json/category_item_entity.g.dart';
import 'package:one_poem/timeline/models/friend_entity.dart';
import 'package:one_poem/generated/json/friend_entity.g.dart';
JsonConvert jsonConvert = JsonConvert();
......
......@@ -71,8 +71,10 @@ class _LoginPageState extends State<LoginPage>
"其他错误"
];
Future.delayed(Duration.zero, () {
NavigatorUtils.pushPageByFade(
Future.delayed(
Duration.zero,
() {
NavigatorUtils.pushPageByFade(
context: context,
//目标页面
targetPage: PermissionRequestWidget(
......@@ -86,8 +88,10 @@ class _LoginPageState extends State<LoginPage>
//权限申请结果
dismissCallBack: (value) {
showPrivacyPage();
});
});
},
);
},
);
}
void showPrivacyPage() async {
......
......@@ -2,18 +2,24 @@ import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:one_poem/poem/widgets/poem_content.dart';
import 'package:one_poem/recorder/audio/widgets/poem_voice_widget.dart';
import 'package:one_poem/routers/fluro_navigator.dart';
import 'package:one_poem/util/toast_utils.dart';
import 'package:one_poem/widgets/bars/home_action_bar.dart';
import 'package:one_poem/widgets/bars/home_menu_bar.dart';
import 'package:one_poem/widgets/my_app_bar.dart';
import 'package:one_poem/extension/int_extension.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pausable_timer/pausable_timer.dart';
import 'package:flutter_sound_platform_interface/flutter_sound_recorder_platform_interface.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:permission_handler/permission_handler.dart';
import '../poem_router.dart';
const theSource = AudioSource.microphone;
class PoemRecordAudioPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _PoemRecordAudioPageState();
......@@ -29,20 +35,33 @@ class PoemRecordAudioPage extends StatefulWidget {
}
class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> {
startRecord() {
print("开始录制");
bool _isGetPoemInProgress = false;
String poemStr = '';
@override
void initState() {
super.initState();
getPoem();
}
stopRecord(String path, double audioTimeLength) {
print("结束束录制");
print("音频文件位置" + path);
print("音频录制时长" + audioTimeLength.toString());
Future<void> getPoem() async {
// TODO 等待套入正式接口发布临境
_isGetPoemInProgress = true;
await Future.delayed(const Duration(seconds: 2), () {
poemStr =
"qīng chén rù gǔ sì\n清晨入古寺,\nchū rì zhào gāo lín\n初日照高林。\nzhú jìng tōng yōu chù\n竹径通幽处,\nchán fáng huā mù shēn\n禅房花木深。\nshān guāng yuè niǎo xìng\n山光悦鸟性,\ntán yǐng kōng rén xīn\n潭影空人心。\nwàn lài cǐ dōu jì\n万籁此都寂,\ndàn yú zhōng qìng yīn\n但余钟磬音。";
_isGetPoemInProgress = false;
setState(() {});
});
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
const poemStr =
"qīng chén rù gǔ sì\n清晨入古寺,\nchū rì zhào gāo lín\n初日照高林。\nzhú jìng tōng yōu chù\n竹径通幽处,\nchán fáng huā mù shēn\n禅房花木深。\nshān guāng yuè niǎo xìng\n山光悦鸟性,\ntán yǐng kōng rén xīn\n潭影空人心。\nwàn lài cǐ dōu jì\n万籁此都寂,\ndàn yú zhōng qìng yīn\n但余钟磬音。";
return Scaffold(
appBar: MyAppBar(
isBack: true,
......@@ -71,106 +90,349 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> {
),
),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin:
EdgeInsets.symmetric(vertical: 20.px, horizontal: 20.px),
height: MediaQuery.of(context).size.height -
125.px -
widget.poemPanelHeight,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.1),
border: Border.all(
color: Colors.grey.shade50, width: 0.5), // 边色与边宽度
),
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10.0,
sigmaY: 10.0,
),
child: Container(
child: _isGetPoemInProgress
? const Center(
child: CupertinoActivityIndicator(
radius: 16.0,
),
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.symmetric(
vertical: 20.px, horizontal: 20.px),
height: MediaQuery.of(context).size.height -
100.px -
widget.poemPanelHeight,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.1),
border: Border.all(
color: Colors.grey.shade50,
width: 0.5,
), // 边色与边宽度
),
child: Padding(
padding: EdgeInsets.all(10.px),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
PoemContent(
title: "题破山寺后禅院",
author: "常建",
poemStr: poemStr,
fontSize: 22.px,
),
Stack(
alignment: Alignment.center,
children: [
Positioned(
left: 10.px,
child: IconButton(
icon: Icon(
Icons.camera_alt_outlined,
size: 28.px,
),
onPressed: () {
Toast.show("不要着急吖,正在开发ing....");
},
),
),
SizedBox(
width: double.infinity,
height: 80.px,
child: PoemVoiceWidget(
startRecord: startRecord,
stopRecord: stopRecord,
// 加入定制化Container的相关属性
height: 40.px,
),
),
],
),
Container(
padding: const EdgeInsets.all(10.0),
alignment: Alignment.centerRight,
height: 54.0,
width: double.infinity,
child: TextButton(
style: ButtonStyle(
side: MaterialStateProperty.all(
const BorderSide(
color: Colors.black54, width: 1),
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10.0,
sigmaY: 10.0,
),
child: Container(
decoration: BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.1),
),
child: Padding(
padding: EdgeInsets.all(10.px),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
PoemContent(
title: "题破山寺后禅院",
author: "常建",
poemStr: poemStr,
fontSize: 22.px,
),
),
onPressed: () {
NavigatorUtils.push(
context,
'${PoemRouter.poemPublish}?data=100',
);
},
child: const Text(
"下一步",
style: TextStyle(color: Colors.white),
),
const AudioToolBar(),
],
),
),
],
),
),
),
),
),
),
],
),
),
],
),
),
),
);
}
}
class AudioToolBar extends StatefulWidget {
const AudioToolBar({
Key? key,
}) : super(key: key);
@override
_AudioToolBarState createState() => _AudioToolBarState();
}
class _AudioToolBarState extends State<AudioToolBar> {
late final PausableTimer _timer;
int currentTimer = 0;
int duration = 10 * 1000; //TODO 60 * 1000;
Codec _codec = Codec.aacMP4;
String _mPath = 'tau_file.mp4';
FlutterSoundPlayer? _mPlayer = FlutterSoundPlayer();
FlutterSoundRecorder? _mRecorder = FlutterSoundRecorder();
bool _mPlayerIsInited = false;
bool _mRecorderIsInited = false;
bool _mPlaybackReady = false;
bool _mRecorderIsRecording = false;
bool _mRecorderIsPaused = false;
@override
void initState() {
super.initState();
_mPlayer!.openAudioSession().then((value) {
setState(() {
_mPlayerIsInited = true;
});
});
openTheRecorder().then((value) {
setState(() {
_mRecorderIsInited = true;
});
});
_timer = PausableTimer(
const Duration(milliseconds: 100),
() {
currentTimer += 100;
_timer
..reset()
..start();
if (currentTimer >= duration) {
_mRecorderIsRecording = false;
stopRecorder();
}
setState(() {});
},
);
}
@override
void dispose() {
_mPlayer!.closeAudioSession();
_mPlayer = null;
_mRecorder!.closeAudioSession();
_mRecorder = null;
super.dispose();
}
Future<void> openTheRecorder() async {
if (!kIsWeb) {
var status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
//TODO 弹出授权提示框
throw RecordingPermissionException('Microphone permission not granted');
}
}
await _mRecorder!.openAudioSession();
if (!await _mRecorder!.isEncoderSupported(_codec) && kIsWeb) {
final directory = await getApplicationDocumentsDirectory();
int currentUnix = DateTime.now().millisecondsSinceEpoch;
_codec = Codec.opusWebM; //TODO 音频保存格式,mp3?
_mPath = '${directory.path}/$currentUnix.webm';
if (!await _mRecorder!.isEncoderSupported(_codec) && kIsWeb) {
_mRecorderIsInited = true;
return;
}
}
_mRecorderIsInited = true;
}
void record() {
if (_mRecorderIsInited && _mPlayer!.isStopped) {
currentTimer = 0;
_timer
..reset()
..start();
_mRecorderIsRecording = true;
_mRecorder!
.startRecorder(
toFile: _mPath,
codec: _codec,
audioSource: theSource,
)
.then((value) {
setState(() {});
});
}
}
void pauseRecorder() async {
if (_mRecorderIsInited && _mPlayer!.isStopped) {
_timer.pause();
_mRecorderIsPaused = true;
await _mRecorder!.pauseRecorder().then((value) {
setState(() {});
});
}
}
void resumeRecorder() async {
if (_mRecorderIsInited && _mPlayer!.isStopped) {
_timer.start();
await _mRecorder!.resumeRecorder().then((value) {
_mRecorderIsPaused = false;
setState(() {});
});
}
}
void stopRecorder() async {
if (_mRecorderIsInited && _mPlayer!.isStopped) {
print("### stop record");
_timer.pause();
await _mRecorder!.stopRecorder().then((value) {
_mRecorderIsRecording = false;
setState(() {
_mPlaybackReady = true;
});
});
}
}
void play() {
if (_mPlayerIsInited && _mPlaybackReady && _mRecorder!.isStopped) {
_mPlayer!
.startPlayer(
fromURI: _mPath,
whenFinished: () {
setState(() {});
})
.then((value) {
setState(() {});
});
}
}
void stopPlayer() {
if (_mPlayerIsInited && _mPlaybackReady && _mRecorder!.isStopped) {
_mPlayer!.stopPlayer().then((value) {
setState(() {});
});
}
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(
16.px,
8.px,
16.px,
8.px,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
InkWell(
onTap: () {
if (_mRecorderIsRecording) {
_mRecorderIsPaused ? resumeRecorder() : pauseRecorder();
} else {
NavigatorUtils.push(
context,
'${PoemRouter.poemRecordVideoPage}?id=100',
);
}
},
child: Stack(
alignment: Alignment.center,
children: [
Icon(
Icons.circle,
color: Colors.black38,
size: 60.px,
),
_mRecorderIsRecording
? _mRecorderIsPaused
? Icon(
Icons.play_arrow,
color: Colors.white,
size: 30.px,
)
: Icon(
Icons.pause,
color: Colors.white,
size: 30.px,
)
: Icon(
Icons.camera_alt_outlined,
color: Colors.white,
size: 30.px,
),
],
),
),
InkWell(
onTap: () {
_mRecorderIsRecording ? stopRecorder() : record();
},
child: Stack(
alignment: Alignment.center,
children: [
Icon(
Icons.circle,
color: Colors.white,
size: 80.px,
),
_mRecorderIsRecording
? SizedBox(
width: 60.px,
height: 60.px,
child: CircularProgressIndicator(
strokeWidth: 5.px,
value: currentTimer / duration,
),
)
: Container(),
Icon(
Icons.circle,
color: Colors.red,
size: 65.px,
),
_mRecorderIsRecording
? Container()
: Text(
"60s",
style: TextStyle(
fontSize: 12.px,
color: Colors.white,
),
),
_mRecorderIsRecording
? Icon(
Icons.stop_rounded,
color: Colors.white,
size: 32.px,
)
: Container(),
],
),
),
InkWell(
onTap: () {},
child: Stack(
alignment: Alignment.center,
children: [
Icon(
Icons.circle,
color: Colors.black38,
size: 60.px,
),
Icon(
Icons.arrow_right_alt,
color: Colors.white,
size: 30.px,
),
],
),
),
],
),
);
}
}
......
......@@ -42,10 +42,7 @@ class _PoemRecordVideoPageState extends State<PoemRecordVideoPage>
List<CameraDescription>? cameras = [];
///声明变量
late final PausableTimer _timer;
///记录当前的时间
int currentTimer = 0;
int duration = 10 * 1000; //TODO 60 * 1000;
......
import 'package:flutter/material.dart';
class CustomOverlay extends StatelessWidget {
final Widget? icon;
final BoxDecoration decoration;
final double width;
final double height;
const CustomOverlay({
Key? key,
this.icon,
this.decoration = const BoxDecoration(
color: Color(0xff77797A),
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
this.width = 160,
this.height = 160,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Positioned(
top: MediaQuery.of(context).size.height * 0.5 - width / 2,
left: MediaQuery.of(context).size.width * 0.5 - height / 2,
child: Material(
type: MaterialType.transparency,
child: Center(
child: Opacity(
opacity: 0.8,
child: Container(
width: width,
height: height,
decoration: decoration,
child: icon,
),
),
),
),
);
}
}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_plugin_record/flutter_plugin_record.dart';
import 'package:flutter_plugin_record/utils/common_toast.dart';
import 'custom_overlay.dart';
import 'package:one_poem/extension/int_extension.dart';
typedef StartRecord = Future Function();
typedef StopRecord = Future Function();
class PoemVoiceWidget extends StatefulWidget {
final Function? startRecord;
final Function? stopRecord;
final double? height;
final EdgeInsets? margin;
final Decoration? decoration;
/// startRecord 开始录制回调 stopRecord回调
const PoemVoiceWidget(
{Key? key,
this.startRecord,
this.stopRecord,
this.height,
this.decoration,
this.margin})
: super(key: key);
@override
_PoemVoiceWidgetState createState() => _PoemVoiceWidgetState();
}
class _PoemVoiceWidgetState extends State<PoemVoiceWidget> {
// 倒计时总时长
final int _countTotal = 12;
double startY = 0.0;
double offset = 0.0;
bool isUp = false;
String textShow = "按住说话";
String toastShow = "手指上滑,取消发送";
String voiceIco = "images/voice_volume_1.png";
///默认隐藏状态
bool voiceState = true;
FlutterPluginRecord? recordPlugin;
Timer? _timer;
int _count = 0;
OverlayEntry? overlayEntry;
String audioFilePath = "";
@override
void initState() {
super.initState();
recordPlugin = FlutterPluginRecord();
_init();
///初始化方法的监听
recordPlugin?.responseFromInit.listen((data) {
// if (data) {
// print("初始化成功");
// } else {
// print("初始化失败");
// }
});
/// 开始录制或结束录制的监听
recordPlugin?.response.listen((data) {
if (data.msg == "onStop") {
///结束录制时会返回录制文件的地址方便上传服务器
if (widget.stopRecord != null) {
audioFilePath = data.path!;
widget.stopRecord!(data.path, data.audioTimeLength);
}
} else if (data.msg == "onStart") {
if (widget.startRecord != null) widget.startRecord!();
}
});
///录制过程监听录制的声音的大小 方便做语音动画显示图片的样式
recordPlugin!.responseFromAmplitude.listen((data) {
var voiceData = double.parse(data.msg ?? '');
setState(() {
if (voiceData > 0 && voiceData < 0.1) {
voiceIco = "images/voice_volume_2.png";
} else if (voiceData > 0.2 && voiceData < 0.3) {
voiceIco = "images/voice_volume_3.png";
} else if (voiceData > 0.3 && voiceData < 0.4) {
voiceIco = "images/voice_volume_4.png";
} else if (voiceData > 0.4 && voiceData < 0.5) {
voiceIco = "images/voice_volume_5.png";
} else if (voiceData > 0.5 && voiceData < 0.6) {
voiceIco = "images/voice_volume_6.png";
} else if (voiceData > 0.6 && voiceData < 0.7) {
voiceIco = "images/voice_volume_7.png";
} else if (voiceData > 0.7 && voiceData < 1) {
voiceIco = "images/voice_volume_7.png";
} else {
voiceIco = "images/voice_volume_1.png";
}
if (overlayEntry != null) {
overlayEntry!.markNeedsBuild();
}
});
});
}
///显示录音悬浮布局
buildOverLayView(BuildContext context) {
if (overlayEntry == null) {
overlayEntry = OverlayEntry(builder: (content) {
return CustomOverlay(
icon: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 10.px),
child: _countTotal - _count < 11
? Center(
child: Padding(
padding: EdgeInsets.only(bottom: 15.px),
child: Text(
(_countTotal - _count).toString(),
style: TextStyle(
fontSize: 70.px,
color: Colors.white,
),
),
),
)
: Image.asset(
voiceIco,
width: 100.px,
height: 100.px,
package: 'flutter_plugin_record',
),
),
Text(
toastShow,
style: TextStyle(
fontStyle: FontStyle.normal,
color: Colors.white,
fontSize: 14.px,
),
)
],
),
);
});
Overlay.of(context)!.insert(overlayEntry!);
}
}
showVoiceView() {
setState(() {
textShow = "松开结束";
voiceState = false;
});
///显示录音悬浮布局
buildOverLayView(context);
start();
}
hideVoiceView() {
if (_timer!.isActive) {
if (_count < 1) {
CommonToast.showView(
context: context,
msg: '说话时间太短',
icon: Text(
'!',
style: TextStyle(fontSize: 80.px, color: Colors.white),
));
isUp = true;
}
_timer?.cancel();
_count = 0;
}
setState(() {
textShow = "按住说话";
voiceState = true;
});
stop();
if (overlayEntry != null) {
overlayEntry?.remove();
overlayEntry = null;
}
// if (isUp) {
// print("取消发送");
// } else {
// print("进行发送");
// }
}
moveVoiceView() {
setState(() {
isUp = startY - offset > 100 ? true : false;
if (isUp) {
textShow = "松开手指,取消发送";
toastShow = textShow;
} else {
textShow = "松开结束";
toastShow = "手指上滑,取消发送";
}
});
}
///初始化语音录制的方法
void _init() async {
recordPlugin?.initRecordMp3();
}
///开始语音录制的方法
void start() async {
recordPlugin?.start();
}
///停止语音录制的方法
void stop() {
recordPlugin?.stop();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(right: 10.px),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onLongPressStart: (details) {
startY = details.globalPosition.dy;
_timer = Timer.periodic(const Duration(milliseconds: 1000), (t) {
_count++;
if (_count == _countTotal) {
hideVoiceView();
}
});
showVoiceView();
},
onLongPressEnd: (details) {
hideVoiceView();
},
onLongPressMoveUpdate: (details) {
offset = details.globalPosition.dy;
moveVoiceView();
},
child: Container(
height: widget.height ?? 60.px,
margin:
widget.margin ?? EdgeInsets.fromLTRB(50.px, 0, 50.px, 20.px),
child: Icon(
Icons.mic_none,
size: 70.px,
color: Colors.black45.withOpacity(0.6),
),
),
),
IconButton(
icon: Icon(
Icons.play_circle_outline,
size: 28.px,
),
onPressed: () {
print("######:" + audioFilePath);
recordPlugin!.playByPath(audioFilePath, "file");
},
),
],
),
);
}
@override
void dispose() {
recordPlugin?.dispose();
_timer?.cancel();
super.dispose();
}
}
import 'dart:io';
import 'package:flutter/material.dart';
import 'preview_screen.dart';
class CapturesScreen extends StatelessWidget {
final List<File> imageFileList;
const CapturesScreen({
Key? key,
required this.imageFileList,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'Captures',
style: TextStyle(
fontSize: 32.0,
color: Colors.white,
),
),
),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
children: [
for (File imageFile in imageFileList)
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 2,
),
),
child: InkWell(
onTap: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => PreviewScreen(
fileList: imageFileList,
imageFile: imageFile,
),
),
);
},
child: Image.file(
imageFile,
fit: BoxFit.cover,
),
),
),
],
),
],
),
),
);
}
}
import 'dart:io';
import 'package:flutter/material.dart';
import 'captures_screen.dart';
class PreviewScreen extends StatelessWidget {
final File imageFile;
final List<File> fileList;
const PreviewScreen({
Key? key,
required this.imageFile,
required this.fileList,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextButton(
onPressed: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => CapturesScreen(
imageFileList: fileList,
),
),
);
},
child: const Text('打开全部视频'),
style: TextButton.styleFrom(
primary: Colors.black,
backgroundColor: Colors.white,
),
),
),
Expanded(
child: Image.file(imageFile),
),
],
),
);
}
}
......@@ -21,7 +21,7 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.2"
version: "3.1.6"
args:
dependency: transitive
description:
......@@ -35,7 +35,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.1"
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
......@@ -126,14 +126,14 @@ packages:
name: camera
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.4+6"
version: "0.9.4+7"
camera_platform_interface:
dependency: transitive
description:
name: camera_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
version: "2.1.5"
camera_web:
dependency: transitive
description:
......@@ -147,7 +147,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
charcode:
dependency: transitive
description:
......@@ -400,7 +400,7 @@ packages:
name: flutter_native_splash
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.2"
version: "1.3.3"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
......@@ -408,20 +408,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
flutter_plugin_record:
flutter_slidable:
dependency: "direct main"
description:
name: flutter_plugin_record
name: flutter_slidable
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
flutter_slidable:
version: "1.2.0"
flutter_sound:
dependency: "direct main"
description:
name: flutter_slidable
name: flutter_sound
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "8.5.0"
flutter_sound_platform_interface:
dependency: transitive
description:
name: flutter_sound_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "8.5.0"
flutter_sound_web:
dependency: transitive
description:
name: flutter_sound_web
url: "https://pub.dartlang.org"
source: hosted
version: "8.5.0"
flutter_spinkit:
dependency: "direct main"
description:
......@@ -513,7 +527,7 @@ packages:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.4+4"
version: "0.8.4+5"
image_picker_for_web:
dependency: transitive
description:
......@@ -582,6 +596,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logger:
dependency: transitive
description:
name: logger
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
logging:
dependency: transitive
description:
......@@ -595,7 +616,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
version: "0.12.11"
meta:
dependency: transitive
description:
......@@ -742,7 +763,7 @@ packages:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
version: "3.0.2"
plugin_platform_interface:
dependency: transitive
description:
......@@ -763,7 +784,7 @@ packages:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.3"
version: "4.2.4"
provider:
dependency: "direct main"
description:
......@@ -820,6 +841,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
recase:
dependency: transitive
description:
name: recase
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
rxdart:
dependency: "direct main"
description:
......@@ -985,7 +1013,7 @@ packages:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1+1"
version: "2.2.0"
stack_trace:
dependency: transitive
description:
......@@ -1055,21 +1083,21 @@ packages:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.17.10"
version: "1.17.12"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
version: "0.4.3"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
version: "0.4.2"
timing:
dependency: transitive
description:
......@@ -1097,7 +1125,7 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.17"
version: "6.0.18"
url_launcher_android:
dependency: transitive
description:
......@@ -1167,7 +1195,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
vibration:
dependency: "direct main"
description:
......@@ -1209,7 +1237,7 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "7.1.1"
version: "7.3.0"
watcher:
dependency: transitive
description:
......@@ -1272,7 +1300,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.6"
version: "2.3.8"
xdg_directories:
dependency: transitive
description:
......@@ -1295,5 +1323,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.14.0 <3.0.0"
dart: ">=2.15.1 <3.0.0"
flutter: ">=2.5.0"
......
......@@ -50,9 +50,9 @@ dependencies:
# Flutter 轮播图 https://github.com/lianyagang/flutter_swiper_null_safety
flutter_swiper_null_safety: ^1.0.2 # flutter_swiper很久不维护,可以使用空安全版本:flutter_swiper_null_safety
# 启动URL的插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/url_launcher
url_launcher: 6.0.17
url_launcher: ^6.0.18
# 图片选择插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/image_picker
image_picker: 0.8.4+4
image_picker: ^0.8.4+5
# 侧滑删除 https://github.com/letsar/flutter_slidable
flutter_slidable: ^1.1.0
# WebView插件 https://github.com/flutter/plugins/tree/master/packages/webview_flutter
......@@ -91,12 +91,12 @@ dependencies:
flutter_spinkit: ^5.0.0
json_annotation: ^4.4.0
flutter_plugin_record: ^1.0.1
flutter_sound: ^8.5.0
# fijkplayer (Video player plugin for Flutter) Flutter 媒体播放器
fijkplayer: ^0.10.1
camera: ^0.9.4+5
camera: ^0.9.4+7
path_provider: ^2.0.8
# A Dart timer that can be paused, resumed and reset.
......