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,7 +71,9 @@ class _LoginPageState extends State<LoginPage>
"其他错误"
];
Future.delayed(Duration.zero, () {
Future.delayed(
Duration.zero,
() {
NavigatorUtils.pushPageByFade(
context: context,
//目标页面
......@@ -86,8 +88,10 @@ class _LoginPageState extends State<LoginPage>
//权限申请结果
dismissCallBack: (value) {
showPrivacyPage();
});
});
},
);
},
);
}
void showPrivacyPage() async {
......
This diff is collapsed. Click to expand it.
......@@ -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.
......