任务发布-发布新任务-添加照片

pull/1/head
张萌 3 years ago
parent b5bcee3842
commit fc22339a6e

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

File diff suppressed because it is too large Load Diff

@ -7,6 +7,7 @@
import 'package:audio_session/audio_session_web.dart';
import 'package:device_info_plus_web/device_info_plus_web.dart';
import 'package:flutter_sound_web/flutter_sound_web.dart';
import 'package:image_picker_for_web/image_picker_for_web.dart';
import 'package:just_audio_web/just_audio_web.dart';
import 'package:package_info_plus_web/package_info_plus_web.dart';
@ -18,6 +19,7 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void registerPlugins(Registrar registrar) {
AudioSessionWeb.registerWith(registrar);
DeviceInfoPlusPlugin.registerWith(registrar);
FlutterSoundPlugin.registerWith(registrar);
ImagePickerPlugin.registerWith(registrar);
JustAudioPlugin.registerWith(registrar);
PackageInfoPlugin.registerWith(registrar);

@ -218,7 +218,7 @@ class _HomePageState extends State<HomePage>
mainAxisSize: MainAxisSize.min,
children: [
head,
HomeSwiper(), //
// HomeSwiper(), //
// SizedBox(height: 100.w),
Container(
padding: EdgeInsets.only(top: 24.w, bottom: 32.w),

@ -39,6 +39,7 @@ class _HallViewState extends State<HallView> {
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w),
itemBuilder: (context, index) {
return HallCard(
key: ValueKey(models[index].id),
model: models[index],
refresh: () => _refreshController.callRefresh());
},

@ -1,19 +1,23 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:common_utils/common_utils.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:velocity_x/velocity_x.dart';
import 'dart:io';
import 'package:aku_new_community/base/base_style.dart';
import 'package:aku_new_community/gen/assets.gen.dart';
import 'package:aku_new_community/ui/service/task_func.dart';
import 'package:aku_new_community/ui/service/task_remark_page.dart';
import 'package:aku_new_community/utils/headers.dart';
import 'package:aku_new_community/widget/bee_divider.dart';
import 'package:aku_new_community/widget/bee_scaffold.dart';
import 'package:aku_new_community/widget/picker/bee_date_picker.dart';
import 'package:aku_new_community/widget/picker/bee_pick_image_widget.dart';
import 'package:aku_new_community/widget/picker/bee_picker_box.dart';
import 'package:aku_new_community/widget/voice_player.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:common_utils/common_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:velocity_x/velocity_x.dart';
class PublishTaskPage extends StatefulWidget {
const PublishTaskPage({Key? key}) : super(key: key);
@ -33,14 +37,16 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
int _rewardType = 0;
DateTime? _appointDate = DateTime.now();
TextEditingController _titleController = TextEditingController();
TextEditingController _contentController = TextEditingController();
TextEditingController _addressController = TextEditingController();
TextEditingController _rewardController = TextEditingController();
TextEditingController _nameController = TextEditingController();
TextEditingController _telController = TextEditingController();
String? _content;
List<File> _photos = [];
@override
void dispose() {
_titleController.dispose();
_contentController.dispose();
_addressController.dispose();
_rewardController.dispose();
super.dispose();
@ -50,49 +56,72 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
Widget build(BuildContext context) {
return BeeScaffold(
title: '发布任务',
body: SafeArea(
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w),
extendBody: true,
body: Stack(
children: [
Container(
ClipPath(
clipper: _taskBackgroundClip(),
child: Container(
width: double.infinity,
padding: EdgeInsets.only(left: 32.w, right: 32.w, bottom: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
Row(
height: 400.w,
color: kPrimaryColor,
)),
SafeArea(
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w),
children: [
SizedBox(
width: 170.w,
child: '标题'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
Expanded(
child: TextField(
controller: _titleController,
onChanged: (text) => setState(() {}),
autofocus: false,
decoration: InputDecoration(
hintStyle: TextStyle(
fontSize: 28.sp,
color: Colors.black.withOpacity(0.25),
),
border: InputBorder.none,
hintText: '请输入',
_baseInfo(context),
32.w.heightBox,
_dateAndAddress(),
24.w.heightBox,
_remarkWidget(),
24.w.heightBox,
_photoAndVoice(),
24.w.heightBox,
_rewardWidget(),
],
),
)
],
),
bottomNavi: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 32.w),
child: MaterialButton(
elevation: 0,
height: 93.w,
disabledColor: Colors.black.withOpacity(0.06),
disabledTextColor: Colors.black.withOpacity(0.25),
textColor: Colors.black.withOpacity(0.85),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(65.w)),
color: kPrimaryColor,
onPressed: !canTap
? null
: () async {
var cancel = BotToast.showLoading();
var re = await TaskFunc.publish(
title: _titleController.text,
taskType: _type,
taskSex: _sex,
serviceObject: _service,
taskContent: _content ?? '',
taskDate: _appointDate.toString(),
taskAddress: _addressController.text,
rewardType: _rewardType,
reward: _rewardController.text);
if (re) {
Get.back();
}
cancel();
},
child: '确认发布'.text.size(32.sp).bold.make(),
),
],
),
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
);
}
Container _baseInfo(BuildContext context) {
var type = GestureDetector(
onTap: () async {
_type = 1;
showModalBottomSheet(
@ -138,8 +167,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
'${_type == 0 ? '请选择分类' : _types[_type - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_type == 0 ? 0.25 : 0.85))
.color(Colors.black.withOpacity(_type == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
@ -149,11 +177,8 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
);
var sex = GestureDetector(
onTap: () async {
await Get.bottomSheet(CupertinoActionSheet(
cancelButton: CupertinoActionSheetAction(
@ -221,8 +246,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
'${_sex == 0 ? '请选择性别' : _sexStr[_sex - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_sex == 0 ? 0.25 : 0.85))
.color(Colors.black.withOpacity(_sex == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
@ -232,11 +256,8 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
);
var servicePersonnel = GestureDetector(
onTap: () async {
await Get.bottomSheet(CupertinoActionSheet(
cancelButton: CupertinoActionSheetAction(
@ -304,8 +325,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
'${_service == 0 ? '请选择服务人员' : _serviceObject[_service - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_service == 0 ? 0.25 : 0.85))
.color(Colors.black.withOpacity(_service == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
@ -315,57 +335,35 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
'任务内容'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
],
),
32.w.heightBox,
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 24.w),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.06),
borderRadius: BorderRadius.circular(16.w)),
child: TextField(
controller: _contentController,
autofocus: false,
onChanged: (text) => setState(() {}),
minLines: 5,
maxLength: 200,
maxLines: 20,
decoration: InputDecoration(
border: InputBorder.none,
),
),
),
],
),
),
32.w.heightBox,
Container(
);
return Container(
width: double.infinity,
padding: EdgeInsets.only(
left: 32.w, right: 32.w, bottom: 32.w, top: 32.w),
padding: EdgeInsets.only(left: 32.w, right: 32.w, bottom: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
GestureDetector(
32.w.heightBox,
type,
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
sex,
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
servicePersonnel,
],
),
);
}
Container _dateAndAddress() {
var date = GestureDetector(
onTap: () async {
_appointDate =
await BeeDatePicker.timePicker(DateTime.now());
_appointDate = await BeeDatePicker.timePicker(DateTime.now());
},
child: Material(
color: Colors.transparent,
@ -373,7 +371,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
children: [
SizedBox(
width: 170.w,
child: '预约时间'
child: '预计时间'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
@ -382,8 +380,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
'${DateUtil.formatDate(_appointDate)}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_type == 0 ? 0.25 : 0.85))
.color(Colors.black.withOpacity(_type == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
@ -393,40 +390,59 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
Row(
);
var contact = Row(
children: [
SizedBox(
width: 170.w,
child: '预约地址'
child: '联系人'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${S.of(context)!.tempPlotName}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.make(),
''
Expanded(
child: TextField(
textAlign: TextAlign.start,
onChanged: (text) => setState(() {}),
autofocus: false,
controller: _nameController,
style: TextStyle(color: Colors.red),
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
isDense: true,
border: InputBorder.none,
hintText: '请输入姓名',
hintStyle: TextStyle(
fontSize: 28.sp,
color: Colors.black.withOpacity(0.25),
)),
),
),
],
);
var tel = Row(
children: [
SizedBox(
width: 170.w,
child: '联系电话'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.25))
.color(Colors.black.withOpacity(0.45))
.make(),
),
Expanded(
child: TextField(
autofocus: false,
controller: _addressController,
textAlign: TextAlign.start,
onChanged: (text) => setState(() {}),
autofocus: false,
controller: _telController,
style: TextStyle(color: Colors.red),
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
isDense: true,
border: InputBorder.none,
hintText: '请输入',
hintText: '请输入电话',
hintStyle: TextStyle(
fontSize: 28.sp,
color: Colors.black.withOpacity(0.25),
@ -434,11 +450,217 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
),
),
],
);
return Container(
width: double.infinity,
padding:
EdgeInsets.only(left: 32.w, right: 32.w, bottom: 32.w, top: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
date,
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
contact,
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
tel,
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
onTap: () {},
child: Material(
color: Colors.transparent,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Container(
margin: EdgeInsets.only(left: 8.w),
width: 32.w,
height: 32.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: kPrimaryColor,
borderRadius: BorderRadius.circular(20.w)),
child: ''.text.size(20.w).black.bold.make(),
),
8.w.heightBox,
_connect(5),
8.w.heightBox,
],
),
20.w.widthBox,
SizedBox(
width: 430.w,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'鲍汁牛肉饭'.text.size(32.sp).black.bold.make(),
12.w.heightBox,
'江西省萍乡市莲花县良坊镇 19 幢 252 室daidjwoajdiowajdoiwa'
.text
.maxLines(1)
.overflow(TextOverflow.ellipsis)
.size(24.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
],
),
),
Spacer(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
20.hb,
Icon(
CupertinoIcons.chevron_right,
size: 40.w,
color: Colors.black.withOpacity(0.45),
)
],
)
],
),
),
),
Row(
children: [
Padding(
padding: EdgeInsets.only(left: 2.w),
child: Assets.icons.connect.image(width: 40.w, height: 40.w),
),
20.wb,
BeeDivider.horizontal().expand(),
],
),
GestureDetector(
onTap: () {},
child: Material(
color: Colors.transparent,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Column(
children: [
8.w.heightBox,
_connect(5),
8.w.heightBox,
Container(
margin: EdgeInsets.only(left: 8.w),
width: 32.w,
height: 32.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(20.w)),
child: ''.text.size(20.w).white.bold.make(),
),
],
),
20.w.widthBox,
SizedBox(
width: 430.w,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'鲍汁牛肉饭'
.text
.size(32.sp)
.black
.lineHeight(1.1)
.bold
.make(),
12.w.heightBox,
'江西省萍乡市莲花县良坊镇 19 幢 252 室daidjwoajdiowajdoiwa'
.text
.maxLines(1)
.overflow(TextOverflow.ellipsis)
.size(24.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
],
),
),
Spacer(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
20.hb,
Icon(
CupertinoIcons.chevron_right,
size: 40.w,
color: Colors.black.withOpacity(0.45),
)
],
)
],
),
),
)
],
),
);
}
Container _remarkWidget() {
return Container(
width: double.infinity,
padding:
EdgeInsets.only(left: 32.w, right: 32.w, bottom: 32.w, top: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
GestureDetector(
onTap: () async {
_content = await Get.to(() => TaskRemarkPage());
},
child: Material(
color: Colors.transparent,
child: Row(
children: [
SizedBox(
width: 170.w,
child: '任务备注'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${_content == null ? '请输入任务备注' : _content}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_rewardType == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
CupertinoIcons.chevron_right,
size: 24.w,
),
],
),
),
),
],
),
);
}
Container _rewardWidget() {
var type = GestureDetector(
onTap: () async {
await Get.bottomSheet(CupertinoActionSheet(
cancelButton: CupertinoActionSheetAction(
@ -494,8 +716,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
'${_rewardType == 0 ? '请选择报酬类型' : _rewardTypes[_rewardType - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_rewardType == 0 ? 0.25 : 0.85))
.color(Colors.black.withOpacity(_rewardType == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
@ -505,11 +726,8 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
Row(
);
var count = Row(
children: [
SizedBox(
width: 170.w,
@ -543,45 +761,91 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
.color(Colors.black.withOpacity(0.85))
.make(),
],
)
);
return Container(
width: double.infinity,
padding:
EdgeInsets.only(left: 32.w, right: 32.w, bottom: 32.w, top: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
type,
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
count,
],
),
);
}
Container _photoAndVoice() {
return Container(
width: double.infinity,
padding:
EdgeInsets.only(left: 32.w, right: 32.w, bottom: 32.w, top: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
Row(
children: [
'上传图片'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
Spacer(),
'建议上传图片不超过6张'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.25))
.make(),
],
),
),
bottomNavi: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 32.w),
child: MaterialButton(
elevation: 0,
height: 93.w,
disabledColor: Colors.black.withOpacity(0.06),
disabledTextColor: Colors.black.withOpacity(0.25),
textColor: Colors.black.withOpacity(0.85),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(65.w)),
color: kPrimaryColor,
onPressed: !canTap
? null
: () async {
var cancel = BotToast.showLoading();
var re = await TaskFunc.publish(
title: _titleController.text,
taskType: _type,
taskSex: _sex,
serviceObject: _service,
taskContent: _contentController.text,
taskDate: _appointDate.toString(),
taskAddress: _addressController.text,
rewardType: _rewardType,
reward: _rewardController.text);
if (re) {
Get.back();
}
cancel();
24.w.heightBox,
BeePickImageWidget(onChanged: (value) {
_photos = value;
}),
24.w.heightBox,
BeeDivider.horizontal(),
24.w.heightBox,
GestureDetector(
onTap: () async {
await Get.bottomSheet(Container());
},
child: '确认发布'.text.size(32.sp).bold.make(),
child: Material(
color: Colors.transparent,
child: Row(
children: [
SizedBox(
width: 170.w,
child: '上传语音'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
VoicePlayer(
url: '5d143e1b735b0.mp3',
showXmark: true,
onDelete: () {},
),
Spacer(),
Icon(
CupertinoIcons.chevron_right,
size: 24.w,
),
],
),
),
),
],
),
);
}
@ -602,7 +866,7 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
if (_appointDate == null) {
return false;
}
if (_contentController.text.isEmpty) {
if (_content == null) {
return false;
}
if (_addressController.text.isEmpty) {
@ -613,4 +877,38 @@ class _PublishTaskPageState extends State<PublishTaskPage> {
}
return true;
}
_connect(int num) {
return Column(
children: List.generate(
num,
(index) => Container(
width: 4.w,
height: 4.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2.w),
color: Colors.black.withOpacity(0.25)),
)).sepWidget(separate: 4.w.heightBox),
);
}
}
class _taskBackgroundClip extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var offset = size.height - 25.0;
var path = Path();
path.moveTo(0, offset);
path.quadraticBezierTo(size.width / 2, size.height, size.width, offset);
path.lineTo(size.width, 0);
path.lineTo(0, 0);
path.lineTo(0, offset);
path.close();
return path;
}
@override
bool shouldReclip(covariant CustomClipper oldClipper) {
return false;
}
}

@ -32,7 +32,7 @@ class TaskFunc {
static Future<bool> cancel({
required int taskId,
}) async {
var base = await NetUtil().get(API.manager.task.cancel, params: {
var base = await NetUtil().get(SARSAPI.task.cancel, params: {
'taskId': taskId,
});
return base.success;
@ -43,9 +43,11 @@ class TaskFunc {
static Future<bool> take({
required int taskId,
}) async {
var base = await NetUtil().get(API.manager.task.take, params: {
var base = await NetUtil().get(SARSAPI.task.receive,
params: {
'taskId': taskId,
});
},
showMessage: true);
return base.success;
}
@ -54,9 +56,40 @@ class TaskFunc {
static Future<bool> finish({
required int taskId,
}) async {
var base = await NetUtil().get(API.manager.task.finish, params: {
var base = await NetUtil().get(SARSAPI.task.finish, params: {
'taskId': taskId,
});
return base.success;
}
///
static Future<bool> confirm({
required int taskId,
}) async {
var base = await NetUtil().get(SARSAPI.task.confirm, params: {
'taskId': taskId,
});
return base.success;
}
///
static Future<bool> start({
required int taskId,
}) async {
var base = await NetUtil().get(SARSAPI.task.startService, params: {
'taskId': taskId,
});
return base.success;
}
///
static Future<bool> evaluate({
required int taskId,
required int star,
required String evaluation,
}) async {
var base = await NetUtil().get(SARSAPI.task.evaluation,
params: {'taskId': taskId, 'star': star, 'evaluation': evaluation});
return base.success;
}
}

@ -0,0 +1,82 @@
import 'package:aku_new_community/base/base_style.dart';
import 'package:aku_new_community/widget/bee_scaffold.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:velocity_x/src/extensions/num_ext.dart';
import 'package:velocity_x/src/extensions/string_ext.dart';
class TaskRemarkPage extends StatefulWidget {
const TaskRemarkPage({Key? key}) : super(key: key);
@override
_TaskRemarkPageState createState() => _TaskRemarkPageState();
}
class _TaskRemarkPageState extends State<TaskRemarkPage> {
TextEditingController _contentController = TextEditingController();
@override
void dispose() {
_contentController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BeeScaffold(
title: '添加备注',
body: ListView(
padding: EdgeInsets.all(32.w),
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
'任务内容'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
],
),
32.w.heightBox,
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 24.w),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.06),
borderRadius: BorderRadius.circular(16.w)),
child: TextField(
controller: _contentController,
autofocus: false,
onChanged: (text) => setState(() {}),
minLines: 5,
maxLength: 200,
maxLines: 20,
decoration: InputDecoration(
border: InputBorder.none,
),
),
)
],
),
bottomNavi: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 32.w),
child: MaterialButton(
elevation: 0,
height: 93.w,
disabledColor: Colors.black.withOpacity(0.06),
disabledTextColor: Colors.black.withOpacity(0.25),
textColor: Colors.black.withOpacity(0.85),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(65.w)),
color: kPrimaryColor,
onPressed: () async {
Get.back(result: _contentController.text);
},
child: '完成'.text.size(32.sp).bold.make(),
),
),
);
}
}

@ -0,0 +1,115 @@
// Dart imports:
import 'dart:io';
import 'package:aku_new_community/extensions/widget_list_ext.dart';
import 'package:aku_new_community/gen/assets.gen.dart';
import 'package:aku_new_community/widget/picker/bee_image_picker.dart';
// Package imports:
import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:velocity_x/velocity_x.dart';
class BeePickImageWidget extends StatefulWidget {
final double? size;
final Function(List<File> files) onChanged;
final String description;
BeePickImageWidget(
{Key? key, this.size, required this.onChanged, this.description = '上传照片'})
: super(key: key);
@override
_BeePickImageWidgetState createState() => _BeePickImageWidgetState();
}
class _BeePickImageWidgetState extends State<BeePickImageWidget> {
List<File> _files = [];
@override
Widget build(BuildContext context) {
return Row(
children: [
..._files.map((e) => showImage(e)).toList(),
GestureDetector(
onTap: () async {
await BeeImagePicker.pick(title: '选择图片').then(
(value) {
if (value != null) {
_files.add(
File(value.path),
);
}
},
);
widget.onChanged(_files);
setState(() {});
},
child: DottedBorder(
color: Colors.black.withOpacity(0.25),
borderType: BorderType.RRect,
strokeWidth: 2.w,
dashPattern: [6, 3],
radius: Radius.circular(8.w),
child: Container(
width: widget.size ?? 160.w,
height: widget.size ?? 160.w,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
Assets.icons.camera.path,
width: 60.w,
height: 60.w,
color: Color(0xFF999999),
),
4.w.heightBox,
widget.description.text
.color(Colors.black.withOpacity(0.45))
.size(22.sp)
.make(),
],
),
),
).material(color: Colors.transparent),
)
].sepWidget(separate: 10.w.widthBox),
);
}
Widget showImage(File file) {
return Stack(children: [
Container(
width: widget.size ?? 160.w,
height: widget.size ?? 160.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.w),
color: Colors.black.withOpacity(0.03)),
child: Image.file(file),
),
Positioned(
top: 8.w,
right: 8.w,
child: Container(
width: 40.w,
height: 40.w,
child: Icon(
CupertinoIcons.xmark,
size: 20.w,
color: Colors.white,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
color: Color(0xFF000000),
),
).onTap(() {
_files.remove(file);
widget.onChanged(_files);
setState(() {});
}),
)
]);
}
}

@ -3,14 +3,19 @@ import 'dart:math';
import 'package:aku_new_community/constants/sars_api.dart';
import 'package:aku_new_community/extensions/num_ext.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:just_audio/just_audio.dart';
class VoicePlayer extends StatefulWidget {
final String url;
final VoidCallback? onDelete;
final bool showXmark;
const VoicePlayer({Key? key, required this.url}) : super(key: key);
const VoicePlayer(
{Key? key, required this.url, this.onDelete, this.showXmark = false})
: super(key: key);
@override
_VoicePlayerState createState() => _VoicePlayerState();
@ -26,12 +31,13 @@ class _VoicePlayerState extends State<VoicePlayer>
bool inAnimate = false;
final player = AudioPlayer();
Timer? _timer;
int _voiceLength = 0;
Duration? _voiceLength;
int _currentLength = 0;
void stopPlay() {
inAnimate = false;
controller.stop();
player.stop();
player.pause();
_timer?.cancel();
_timer = null;
if (mounted) {
@ -39,23 +45,43 @@ class _VoicePlayerState extends State<VoicePlayer>
}
}
void startPlay() {
void startPlay() async {
inAnimate = true;
controller.forward();
player.play();
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
_voiceLength--;
if (_voiceLength <= 0) {
_voiceLength = (player.duration?.inSeconds) ?? 0;
_currentLength--;
if (_currentLength <= 0) {
resetPlay();
} else {
if (mounted) {
setState(() {});
}
}
});
}
Future initVoice() async {
await player.setUrl(SARSAPI.image(widget.url));
_voiceLength = await player.load();
_currentLength = _voiceLength?.inSeconds ?? 0;
await player.setClip(start: Duration(seconds: 0), end: _voiceLength);
if (mounted) {
setState(() {});
}
}
Future resetPlay() async {
_timer?.cancel();
_timer = null;
controller.stop();
inAnimate = false;
}
player.stop();
_currentLength = _voiceLength?.inSeconds ?? 0;
await player.setClip(start: Duration(seconds: 0), end: _voiceLength);
if (mounted) {
setState(() {});
}
});
}
@override
@ -80,17 +106,16 @@ class _VoicePlayerState extends State<VoicePlayer>
controller.forward();
}
});
Future.delayed(Duration(milliseconds: 0), () async {
await player.setUrl(SARSAPI.image(widget.url));
var length = await player.load();
_voiceLength = length?.inSeconds ?? 0;
if (mounted) {
setState(() {});
}
});
initVoice();
super.initState();
}
@override
void didUpdateWidget(covariant VoicePlayer oldWidget) {
resetPlay();
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
stopPlay();
@ -113,7 +138,11 @@ class _VoicePlayerState extends State<VoicePlayer>
},
child: Material(
color: Colors.transparent,
child: Container(
child: Stack(
fit: StackFit.passthrough,
clipBehavior: Clip.none,
children: [
Container(
width: width,
// height: height,
padding: EdgeInsets.symmetric(vertical: 14.w, horizontal: 20.w),
@ -123,13 +152,27 @@ class _VoicePlayerState extends State<VoicePlayer>
child: Row(
children: [
CustomPaint(
painter: VoicePlayerPainter(inAnimate ? animation.value : 3),
painter:
VoicePlayerPainter(inAnimate ? animation.value : 3),
),
40.wb,
Text('${_voiceLength}\"'),
Text('${_currentLength}\"'),
],
),
),
if (widget.showXmark)
Positioned(
top: -10.w,
right: -10.w,
child: GestureDetector(
onTap: widget.onDelete,
child: Icon(
CupertinoIcons.xmark_circle_fill,
size: 30.w,
),
))
],
),
),
);
}

@ -512,6 +512,27 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.6.0"
flutter_sound:
dependency: "direct main"
description:
name: flutter_sound
url: "https://pub.flutter-io.cn"
source: hosted
version: "9.1.3"
flutter_sound_platform_interface:
dependency: transitive
description:
name: flutter_sound_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "9.1.3"
flutter_sound_web:
dependency: transitive
description:
name: flutter_sound_web
url: "https://pub.flutter-io.cn"
source: hosted
version: "9.1.3"
flutter_test:
dependency: "direct dev"
description: flutter
@ -990,7 +1011,7 @@ packages:
name: provider
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.0"
version: "6.0.2"
pub_semver:
dependency: "direct dev"
description:
@ -1042,6 +1063,13 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
recase:
dependency: transitive
description:
name: recase
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.0"
rxdart:
dependency: transitive
description:

@ -18,7 +18,7 @@ dependencies:
#包信息
package_info: ^2.0.0
#状态管理
provider: ^5.0.0
provider: ^6.0.0
#屏幕适配
flutter_screenutil: ^5.0.0+2
#图标集合
@ -117,6 +117,8 @@ dependencies:
palette_generator: ^0.3.2
#音频播放
just_audio: ^0.9.20
#录音
flutter_sound: ^9.1.3
dev_dependencies:

Loading…
Cancel
Save