Commit 07e3db1c3b51f6e6374b887e00fc4140081aba16

Authored by wdn127929
1 parent 7aa0e4bb

相机、相册单图 七牛传

... ... @@ -7,6 +7,7 @@
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
... ...
... ... @@ -50,6 +50,8 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要您的同意,APP才能访问您的相册来上传图片</string>
<key>NSAppleMusicUsageDescription</key>
<string>需要您的同意,APP才能访问媒体资料库</string>
<key>NSCalendarsUsageDescription</key>
... ...
import 'package:json_annotation/json_annotation.dart';
part 'qiniu_info_model.g.dart';
@JsonSerializable()
class QiniuInfoModel extends Object {
@JsonKey(name: 'ret')
int ret;
@JsonKey(name: 'data')
QiniuInfoSunModel data;
@JsonKey(name: 'msg')
String msg;
QiniuInfoModel(
this.ret,
this.data,
this.msg,
);
factory QiniuInfoModel.fromJson(Map<String, dynamic> srcJson) =>
_$QiniuInfoModelFromJson(srcJson);
Map<String, dynamic> toJson() => _$QiniuInfoModelToJson(this);
}
@JsonSerializable()
class QiniuInfoSunModel extends Object {
@JsonKey(name: 'token')
String token;
@JsonKey(name: 'domain')
String domain;
QiniuInfoSunModel(
this.token,
this.domain,
);
factory QiniuInfoSunModel.fromJson(Map<String, dynamic> srcJson) =>
_$QiniuInfoSunModelFromJson(srcJson);
Map<String, dynamic> toJson() => _$QiniuInfoSunModelToJson(this);
}
... ...
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'qiniu_info_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
QiniuInfoModel _$QiniuInfoModelFromJson(Map<String, dynamic> json) {
return QiniuInfoModel(
json['ret'] as int,
json['data'] == null
? null
: QiniuInfoSunModel.fromJson(json['data'] as Map<String, dynamic>),
json['msg'] as String);
}
Map<String, dynamic> _$QiniuInfoModelToJson(QiniuInfoModel instance) =>
<String, dynamic>{
'ret': instance.ret,
'data': instance.data,
'msg': instance.msg
};
QiniuInfoSunModel _$QiniuInfoSunModelFromJson(Map<String, dynamic> json) {
return QiniuInfoSunModel(json['token'] as String, json['domain'] as String);
}
Map<String, dynamic> _$QiniuInfoSunModelToJson(QiniuInfoSunModel instance) =>
<String, dynamic>{'token': instance.token, 'domain': instance.domain};
... ...
... ... @@ -63,4 +63,7 @@ class HttpUrl {
"?service=App.Advance.CreateOrder"; //顾客扫桌码点餐-扫码创建订单
static const String get_reserve_detail =
"?service=App.Reserve.Detail"; //订座详情页面
static const String get_qiniu_info =
"?service=App.Qiniu.GetUploadToken"; //获取七牛上传token信息
}
... ...
... ... @@ -126,6 +126,11 @@ class HomePageState extends State<HomePage> with WidgetsBindingObserver {
NavigatorUtil.goNotebookDetailPage(context, notifyParam['rid'],
mid: notifyParam['mid'], fromNotify: true);
break;
case "12":
//在线买单消息 去处理 跳转在线买单处理页面
NavigatorUtil.goOnlineCheckEditPage(context,
rid: notifyParam["rid"], fromNotify: true);
break;
case "1":
NavigatorUtil.goHasOrderFoodPage(context,
rid: notifyParam["rid"], fromNotify: true);
... ...
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:one_key/pages/online_check/photo_view_wiget.dart';
import 'package:one_key/provider/online_check_edit_provider.dart';
import 'package:one_key/res/colors.dart';
import 'package:one_key/utils/utils.dart';
import 'package:one_key/widgets/MyDivider.dart';
import 'package:one_key/widgets/v_empty_view.dart';
import 'package:provider/provider.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_player/video_player.dart';
import 'package:qiniu_flutter_sdk/qiniu_flutter_sdk.dart';
final int MAX_IMAGE_NUMBER = 9;
typedef void OnPickImageCallback(
double maxWidth, double maxHeight, int quality);
class ImgPickerWidget extends StatefulWidget {
final ScrollController scrollController;
final Color borderColor;
final ValueChanged onChange;
ImgPickerWidget(
{Key key,
this.scrollController,
this.borderColor = Colors.blue,
this.onChange})
: super(key: key);
@override
_ImgPickerWidgetState createState() => _ImgPickerWidgetState();
}
class _ImgPickerWidgetState extends State<ImgPickerWidget> {
File _image;
final picker = ImagePicker();
OnlineCheckEditProvider _onlineCheckEditProvider;
//相册 相机
// Future _getFromPictureOrCamera(context, imageSource) async {
// File image = await picker.getImage(
// source: imageSource,
// );
// if (image != null) {
// _provider.imageList.add(image);
// _provider.notifyListeners();
// }
// // _provider.uploadTravelReleaseImg(image);
// }
Future _getFromPictureOrCamera(imageSource) async {
final pickedFile = await picker.getImage(source: imageSource);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
_onlineCheckEditProvider.imageList.add(_image);
_onlineCheckEditProvider.notifyListeners();
} else {
print('No image selected.');
}
});
}
@override
void dispose() {
super.dispose();
}
Future _openModalBottomSheet(context) async {
final option = await showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (BuildContext context) {
return Container(
// height: ScreenUtil().setWidth(180 * 2),
decoration: BoxDecoration(
color: MyColours.color_ffffff,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(ScreenUtil().setWidth(24)),
topRight: Radius.circular(ScreenUtil().setWidth(24)))),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
InkWell(
onTap: () {
_getFromPictureOrCamera(ImageSource.camera);
Navigator.pop(context);
},
child: Padding(
padding: EdgeInsets.symmetric(
vertical: ScreenUtil().setWidth(18 * 2)),
child: Text(
'拍摄',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
),
),
MyDivider(
double.infinity,
ScreenUtil().setWidth(2),
color: MyColours.color_EEEEEE,
),
InkWell(
onTap: () {
_getFromPictureOrCamera(ImageSource.gallery);
Navigator.pop(context);
},
child: Padding(
padding: EdgeInsets.symmetric(
vertical: ScreenUtil().setWidth(18 * 2)),
child: Text(
'从相册选择',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
),
),
MyDivider(
double.infinity,
ScreenUtil().setWidth(10),
color: MyColours.color_EEEEEE,
),
InkWell(
onTap: () {
Navigator.pop(context, '取消');
},
child: Padding(
padding: EdgeInsets.symmetric(
vertical: ScreenUtil().setWidth(18 * 2)),
child: Text(
'取消',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
),
)
],
),
);
});
}
_getGridImg(count, context, isLinjie) {
OnlineCheckEditProvider _provider =
Provider.of<OnlineCheckEditProvider>(context, listen: false);
return GridView.builder(
controller: widget.scrollController,
// padding: EdgeInsets.only(top: ScreenUtil().getAdapterSize(10)),
shrinkWrap: true,
itemCount: count,
//SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//横轴元素个数
crossAxisCount: 3,
//纵轴间距
mainAxisSpacing: 20.0,
//横轴间距
crossAxisSpacing: 10.0,
//子组件宽高长度比例
childAspectRatio: 1.0),
itemBuilder: (BuildContext context, int index) {
//Widget Function(BuildContext context, int index)
var linjie = MAX_IMAGE_NUMBER;
if (isLinjie) {
linjie = MAX_IMAGE_NUMBER - 1;
}
if (index == count - 1 && index < linjie) {
return InkWell(
onTap: () {
_openModalBottomSheet(context);
},
child: Container(
width: ScreenUtil().setWidth(90 * 2),
height: ScreenUtil().setWidth(90 * 2),
decoration: BoxDecoration(
border: Border.all(
color: MyColours.color_E0E0E0,
width: ScreenUtil().setWidth(2)),
),
child: Column(
children: [
VEmptyView(74),
Image.asset(
Utils.getImgPath('add_image'),
width: ScreenUtil().setWidth(32),
height: ScreenUtil().setWidth(32),
),
VEmptyView(10),
Text(
'添加照片',
style: TextStyle(
fontSize: ScreenUtil().setSp(24),
color: MyColours.color_999999),
)
],
)),
);
}
return _provider.imageList.length < 1
? Text('')
: InkWell(
onTap: () {
_showPhotoView(context, index, _provider.imageList[index]);
},
child:
Image.file(_provider.imageList[index], fit: BoxFit.cover),
);
});
}
//查看大图
_showPhotoView(BuildContext context, int index, List imgs,
{isShow = false, List dashName}) async {
// if (imgs.length == 1 &&
// imgs[0] ==
// 'http://nosqn.colorcun.com/custom/lite-online/image/def-banner.png') {
// imgs[0] = 'http://nosqn.colorcun.com/app/seller-hj-empty.png';
// }
Utils.setBarStatus(false, color: Colors.black);
dynamic result = await showGeneralDialog(
context: context,
barrierDismissible: false,
// barrierColor: Colors.red,
barrierLabel:
MaterialLocalizations.of(context).modalBarrierDismissLabel,
transitionDuration: const Duration(milliseconds: 150),
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
Widget child = Stack(
children: <Widget>[
PhotoPreview(
initialIndex: index,
photoList: imgs,
isShow: isShow,
dashName: dashName)
],
);
return child;
});
Utils.setBarStatus(true, color: Colors.white);
}
@override
Widget build(BuildContext context) {
_onlineCheckEditProvider =
Provider.of<OnlineCheckEditProvider>(context, listen: true);
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: ScreenUtil().setWidth(53 * 2),
width: double.infinity,
decoration: BoxDecoration(
color: MyColours.color_FAFAFA,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10)),
),
child: Padding(
padding: EdgeInsets.fromLTRB(
ScreenUtil().setWidth(20),
ScreenUtil().setWidth(36),
ScreenUtil().setWidth(20),
ScreenUtil().setWidth(26)),
child: Text(
'消费清单(选填)',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
)),
Padding(
padding: EdgeInsets.all(ScreenUtil().setWidth(40)),
child: _getGridImg(
_onlineCheckEditProvider.imageList.length < MAX_IMAGE_NUMBER
? _onlineCheckEditProvider.imageList.length + 1
: _onlineCheckEditProvider.imageList.length,
context,
_onlineCheckEditProvider.imageList.length == MAX_IMAGE_NUMBER
? true
: false),
)
// _getGridImg(1, context)
],
),
);
}
}
import 'package:flutter/widgets.dart';
abstract class DisposableState<T extends StatefulWidget> extends State<T> {
List<Function> disposerList = [];
void addDisposer(Function disposer) {
disposerList.add(disposer);
}
@override
@mustCallSuper
void dispose() {
for (var disposer in disposerList) {
try {
disposer?.call();
} catch (error) {
rethrow;
}
}
super.dispose();
}
}
... ...
import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:one_key/pages/online_check/photo_view_wiget.dart';
import 'package:one_key/pages/online_check/progress.dart';
import 'package:one_key/provider/online_check_edit_provider.dart';
import 'package:one_key/res/colors.dart';
import 'package:one_key/utils/utils.dart';
import 'package:one_key/widgets/MyDivider.dart';
import 'package:one_key/widgets/v_empty_view.dart';
import 'package:path_provider/path_provider.dart';
import 'package:photo/photo.dart';
import 'package:provider/provider.dart';
import 'package:image_picker/image_picker.dart';
import 'package:qiniu_flutter_sdk/qiniu_flutter_sdk.dart';
import './dispose.dart';
import 'package:photo_manager/photo_manager.dart';
final int MAX_IMAGE_NUMBER = 5;
typedef void OnPickImageCallback(
double maxWidth, double maxHeight, int quality);
class ImgPickerWidget extends StatefulWidget {
final ScrollController scrollController;
final Color borderColor;
final ValueChanged onChange;
ImgPickerWidget(
{Key key,
this.scrollController,
this.borderColor = Colors.blue,
this.onChange})
: super(key: key);
@override
_ImgPickerWidgetState createState() => _ImgPickerWidgetState();
}
class _ImgPickerWidgetState extends DisposableState<ImgPickerWidget> {
final picker = ImagePicker();
OnlineCheckEditProvider _onlineCheckEditProvider;
// 控制器,可以用于取消任务、获取上述的状态,进度等信息
PutController putController;
// 用户输入的文件名
String key;
// 用户输入的 partSize
int partSize = 4;
// 用户输入的 token
String token;
/// storage 实例
Storage storage;
// 当前的进度
double progressValue = 0.01;
// 当前的任务状态
StorageStatus statusValue;
@override
void initState() {
storage = Storage();
super.initState();
}
@override
void dispose() {
super.dispose();
}
///#相机拍照,单图选择
Future _getFromPictureOrCamera(imageSource) async {
final pickedFile = await picker.getImage(source: imageSource);
setState(() {
if (pickedFile != null) {
_onlineCheckEditProvider.imageListFile.add(File(pickedFile.path));
_onlineCheckEditProvider.statusMap[pickedFile.path] = false;
} else {
print('No image selected.');
}
});
if (pickedFile != null) {
startUpload(File(pickedFile.path));
}
}
///多图片选择
void pickAsset(PickType type, {List<AssetPathEntity> pathList}) async {
/// context is required, other params is optional.
List<AssetEntity> imgList = await PhotoPicker.pickAsset(
// BuildContext required
context: context,
/// The following are optional parameters.
themeColor: MyColours.color_199095,
// the title color and bottom color
textColor: Colors.white,
// text color
padding: 1.0,
// item padding
dividerColor: Colors.grey,
// divider color
disableColor: Colors.grey.shade300,
// the check box disable color
itemRadio: 0.88,
// the content item radio
maxSelected:
MAX_IMAGE_NUMBER - _onlineCheckEditProvider.imageListFile.length,
// max picker image count
// provider: I18nProvider.english,
provider: I18nProvider.chinese,
// i18n provider ,default is chinese. , you can custom I18nProvider or use ENProvider()
rowCount: 3,
// item row count
thumbSize: 150,
// preview thumb size , default is 64
sortDelegate: SortDelegate.common,
// default is common ,or you make custom delegate to sort your gallery
checkBoxBuilderDelegate: DefaultCheckBoxBuilderDelegate(
activeColor: MyColours.color_353535,
unselectedColor: Colors.white,
checkColor: MyColours.color_199095,
),
// default is DefaultCheckBoxBuilderDelegate ,or you make custom delegate to create checkbox
// loadingDelegate: this,
// if you want to build custom loading widget,extends LoadingDelegate, [see example/lib/main.dart]
badgeDelegate: const DurationBadgeDelegate(),
// badgeDelegate to show badge widget
pickType: type,
photoPathList: pathList,
);
if (imgList == null || imgList.isEmpty) {
print("No pick item.");
return;
} else {
List<String> r = [];
for (var e in imgList) {
var file = await e.file;
r.add(file.absolute.path);
setState(() {
_onlineCheckEditProvider.imageListFile.add(File(file.absolute.path));
_onlineCheckEditProvider.statusMap[file.absolute.path] = false;
});
startUpload(File(file.absolute.path));
}
}
}
///七牛云sdk
void onStatus(StorageStatus status) {
print('状态变化: 当前任务状态:${status.toString()}');
setState(() => statusValue = status);
}
///任务进度变化:进度
void onProgress(double percent) {
setState(() => progressValue = percent);
print('任务进度变化:进度:${percent.toStringAsFixed(4)}');
}
///实际发送变化:进度
void onSendProgress(double percent) {
setState(() => progressValue = percent);
print('实际发送变化:进度:${percent.toStringAsFixed(4)}');
}
///上传到七牛云
void startUpload(File selectedFile) async {
print('创建 PutController');
putController = PutController();
// _onlineCheckEditProvider.statusMapProgress[selectedFile.path] =
// putController;
print('添加实际发送进度订阅');
addDisposer(putController.addSendProgressListener(onSendProgress));
print('添加任务进度订阅');
addDisposer(putController.addProgressListener(onProgress));
print('添加状态订阅');
addDisposer(putController.addStatusListener(onStatus));
if (token == null || token == '') {
await _onlineCheckEditProvider.getQiniuInfo(context, {});
}
var usedToken = _onlineCheckEditProvider.qiniuInfoSunModel.token;
if (usedToken == null || usedToken == '') {
print('token 不能为空');
return;
}
print('开始上传文件');
storage.putFile(
selectedFile,
usedToken,
options: PutOptions(
key: key,
partSize: partSize,
controller: putController,
),
)
..then((PutResponse response) {
print('上传已完成: 原始响应数据: ${jsonEncode(response.rawData)}');
print('------------------------');
String imgUrl = _onlineCheckEditProvider.qiniuInfoSunModel.domain +
'/' +
response.rawData['key'];
_onlineCheckEditProvider.imageListUrl.add(imgUrl);
// _image
_onlineCheckEditProvider.statusMap[selectedFile.path] = true;
_onlineCheckEditProvider.notifyListeners();
})
..catchError((dynamic error) {
if (error is StorageError) {
switch (error.type) {
case StorageErrorType.CONNECT_TIMEOUT:
print('发生错误: 连接超时');
break;
case StorageErrorType.SEND_TIMEOUT:
print('发生错误: 发送数据超时');
break;
case StorageErrorType.RECEIVE_TIMEOUT:
print('发生错误: 响应数据超时');
break;
case StorageErrorType.RESPONSE:
print('发生错误: ${error.message}');
break;
case StorageErrorType.CANCEL:
print('发生错误: 请求取消');
break;
case StorageErrorType.UNKNOWN:
print('发生错误: 未知错误');
break;
case StorageErrorType.NO_AVAILABLE_HOST:
print('发生错误: 无可用 Host');
break;
case StorageErrorType.IN_PROGRESS:
print('发生错误: 已在队列中');
break;
}
} else {
print('发生错误: ${error.toString()}');
}
print('------------------------');
});
}
///添加图片UI弹出
Future _openModalBottomSheet(context) async {
final option = await showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
isDismissible: false,
builder: (BuildContext context) {
return Container(
// height: ScreenUtil().setWidth(180 * 2),
decoration: BoxDecoration(
color: MyColours.color_ffffff,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(ScreenUtil().setWidth(24)),
topRight: Radius.circular(ScreenUtil().setWidth(24)))),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
InkWell(
onTap: () {
_getFromPictureOrCamera(ImageSource.camera);
Navigator.pop(context);
},
child: Container(
width: double.infinity,
height: ScreenUtil().setWidth(58 * 2),
child: Center(
child: Text(
'拍摄',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
)),
),
MyDivider(
double.infinity,
ScreenUtil().setWidth(2),
color: MyColours.color_EEEEEE,
),
InkWell(
onTap: () {
// pickAsset(PickType.onlyImage);
_getFromPictureOrCamera(ImageSource.gallery);
Navigator.pop(context);
},
child: Container(
width: double.infinity,
height: ScreenUtil().setWidth(58 * 2),
child: Center(
child: Text(
'从相册选择',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
)),
),
MyDivider(
double.infinity,
ScreenUtil().setWidth(10),
color: MyColours.color_EEEEEE,
),
InkWell(
onTap: () {
Navigator.pop(context, '取消');
},
child: Container(
width: double.infinity,
height: ScreenUtil().setWidth(58 * 2),
child: Center(
child: Text(
'取消',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
)))
],
),
);
});
}
//查看大图
_showPhotoView(BuildContext context, int index, List imgs,
{isShow = false, List dashName}) async {
// if (imgs.length == 1 &&
// imgs[0] ==
// 'http://nosqn.colorcun.com/custom/lite-online/image/def-banner.png') {
// imgs[0] = 'http://nosqn.colorcun.com/app/seller-hj-empty.png';
// }
Utils.setBarStatus(false, color: Colors.black);
dynamic result = await showGeneralDialog(
context: context,
barrierDismissible: false,
// barrierColor: Colors.red,
barrierLabel:
MaterialLocalizations.of(context).modalBarrierDismissLabel,
transitionDuration: const Duration(milliseconds: 150),
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
Widget child = Stack(
children: <Widget>[
PhotoPreview(
initialIndex: index,
photoList: imgs,
isShow: isShow,
dashName: dashName)
],
);
return child;
});
Utils.setBarStatus(true, color: Colors.white);
}
@override
Widget build(BuildContext context) {
_onlineCheckEditProvider =
Provider.of<OnlineCheckEditProvider>(context, listen: true);
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: ScreenUtil().setWidth(53 * 2),
width: double.infinity,
decoration: BoxDecoration(
color: MyColours.color_FAFAFA,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10)),
),
child: Padding(
padding: EdgeInsets.fromLTRB(
ScreenUtil().setWidth(20),
ScreenUtil().setWidth(36),
ScreenUtil().setWidth(20),
ScreenUtil().setWidth(26)),
child: Text(
'消费清单(选填)',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
)),
Padding(
padding: EdgeInsets.all(ScreenUtil().setWidth(40)),
child: _getGridImg(
_onlineCheckEditProvider.imageListFile.length < MAX_IMAGE_NUMBER
? _onlineCheckEditProvider.imageListFile.length + 1
: _onlineCheckEditProvider.imageListFile.length,
context,
_onlineCheckEditProvider.imageListFile.length ==
MAX_IMAGE_NUMBER
? true
: false),
)
// _getGridImg(1, context)
],
),
);
}
/// 九宫格
Widget _getGridImg(count, context, isLinjie) {
OnlineCheckEditProvider _provider =
Provider.of<OnlineCheckEditProvider>(context, listen: false);
return GridView.builder(
controller: widget.scrollController,
// padding: EdgeInsets.only(top: ScreenUtil().getAdapterSize(10)),
shrinkWrap: true,
itemCount: count,
//SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//横轴元素个数
crossAxisCount: 3,
//纵轴间距
mainAxisSpacing: ScreenUtil().setWidth(30),
//横轴间距
crossAxisSpacing: ScreenUtil().setWidth(30),
//子组件宽高长度比例
childAspectRatio: 1.0),
itemBuilder: (BuildContext context, int index) {
//Widget Function(BuildContext context, int index)
var linjie = MAX_IMAGE_NUMBER;
if (isLinjie) {
linjie = MAX_IMAGE_NUMBER - 1;
}
if (index == count - 1 && index < linjie) {
return InkWell(
onTap: () {
_openModalBottomSheet(context);
},
child: Container(
width: ScreenUtil().setWidth(90 * 2),
height: ScreenUtil().setWidth(90 * 2),
decoration: BoxDecoration(
border: Border.all(
color: MyColours.color_E0E0E0,
width: ScreenUtil().setWidth(2)),
),
child: Column(
children: [
VEmptyView(74),
Image.asset(
Utils.getImgPath('add_image'),
width: ScreenUtil().setWidth(32),
height: ScreenUtil().setWidth(32),
),
VEmptyView(10),
Text(
'添加照片',
style: TextStyle(
fontSize: ScreenUtil().setSp(24),
color: MyColours.color_999999),
)
],
)),
);
}
return _provider.imageListFile.length < 1
? Text('')
: InkWell(
onTap: () {
///没有上传完成的不可以点击
_showPhotoView(
context, index, _provider.imageListUrl[index]);
},
child: Stack(
children: [
Stack(
alignment: Alignment.topRight,
children: [
Image.file(
_provider.imageListFile[index],
fit: BoxFit.cover,
width: ScreenUtil().setWidth(100 * 2),
height: ScreenUtil().setWidth(100 * 2),
),
Offstage(
offstage: !_provider
.statusMap[_provider.imageListFile[index].path],
child: GestureDetector(
child: Image.asset(
Utils.getImgPath("delete"),
width: ScreenUtil().setWidth(40),
height: ScreenUtil().setWidth(40),
),
onTap: () {
//点击删除按钮
setState(() {
_provider.imageListFile.removeWhere(
(element) =>
element ==
_provider.imageListFile[index]);
});
},
),
),
],
),
Offstage(
offstage: _provider
.statusMap[_provider.imageListFile[index].path],
child: Progress(progressValue),
)
],
));
});
}
}
... ...
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/screenutil.dart';
import 'package:one_key/pages/online_check/ImgPickerWidget.dart';
import 'package:one_key/pages/online_check/img_picker_widget.dart';
import 'package:one_key/provider/online_check_edit_provider.dart';
import 'package:one_key/res/colors.dart';
import 'package:one_key/utils/navigator_util.dart';
import 'package:one_key/utils/utils.dart';
import 'package:one_key/widgets/MyDivider.dart';
import 'package:one_key/widgets/h_empty_view.dart';
import 'package:one_key/widgets/my_item.dart';
import 'package:one_key/widgets/system_app_bar.dart';
import 'package:one_key/widgets/v_empty_view.dart';
import 'package:provider/provider.dart';
class OnlineCheckEditPage extends StatefulWidget {
final bool fromNotify;
... ... @@ -21,10 +24,14 @@ class _OnlineCheckEditPageState extends State<OnlineCheckEditPage> {
ScrollController _scrollController = ScrollController();
TextEditingController _editingController = TextEditingController();
FocusNode _focusNode = FocusNode();
OnlineCheckEditProvider _onlineCheckEditProvider;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_getQiniuInfo();
});
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
//有焦点
... ... @@ -36,6 +43,18 @@ class _OnlineCheckEditPageState extends State<OnlineCheckEditPage> {
});
}
@override
void dispose() {
super.dispose();
// _onlineCheckEditProvider
}
///获取七牛云token
///
_getQiniuInfo() async {
await _onlineCheckEditProvider.getQiniuInfo(context, {});
}
///顶部logo
Widget _getLogoWidget() {
return Column(
... ... @@ -156,9 +175,87 @@ class _OnlineCheckEditPageState extends State<OnlineCheckEditPage> {
);
}
///消费清单
///顾客信息
Widget _customInfoItemWidget(String title, String subTitle) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: TextStyle(
fontSize: ScreenUtil().setSp(28), color: MyColours.color_707070),
),
Text(
subTitle,
style: TextStyle(
fontSize: ScreenUtil().setSp(28),
color: MyColours.color_707070,
fontWeight: FontWeight.bold),
)
],
);
}
Widget _customInfoWidget() {
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: ScreenUtil().setWidth(53 * 2),
width: double.infinity,
decoration: BoxDecoration(
color: MyColours.color_FAFAFA,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10)),
),
child: Padding(
padding: EdgeInsets.fromLTRB(
ScreenUtil().setWidth(20),
ScreenUtil().setWidth(36),
ScreenUtil().setWidth(20),
ScreenUtil().setWidth(26)),
child: Text(
'顾客信息',
style: TextStyle(
fontSize: ScreenUtil().setSp(32),
color: MyColours.color_353535,
fontWeight: FontWeight.bold),
),
)),
Container(
color: Colors.white,
padding: EdgeInsets.fromLTRB(
ScreenUtil().setWidth(40),
ScreenUtil().setWidth(24),
ScreenUtil().setWidth(40),
ScreenUtil().setWidth(36)),
child: Column(
children: [
_customInfoItemWidget('买单顾客', 'ffff'),
VEmptyView(24),
_customInfoItemWidget('顾客电话', 'ffff'),
VEmptyView(24),
_customInfoItemWidget('到店时间', 'ffff'),
VEmptyView(24),
_customInfoItemWidget('申请时间', 'ffff')
],
),
)
// _getGridImg(1, context)
],
),
);
}
@override
Widget build(BuildContext context) {
_onlineCheckEditProvider =
Provider.of<OnlineCheckEditProvider>(context, listen: true);
return Scaffold(
backgroundColor: MyColours.color_f5f5f5,
appBar: SystemAppBar(
... ... @@ -197,7 +294,9 @@ class _OnlineCheckEditPageState extends State<OnlineCheckEditPage> {
),
),
VEmptyView(20),
ImgPickerWidget()
ImgPickerWidget(scrollController: _scrollController),
VEmptyView(20),
_customInfoWidget()
],
)),
),
... ...
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:one_key/res/colors.dart';
class Progress extends StatelessWidget {
final double value;
Progress(this.value);
Widget get progress {
return Container(
width: ScreenUtil().setWidth(30),
height: ScreenUtil().setWidth(30),
padding: EdgeInsets.all(10),
color: Colors.red,
child: CircularProgressIndicator(
value: value,
// strokeWidth: 14,
backgroundColor: Colors.grey[200],
),
);
}
Widget get progressText {
final integer = (value * 100).toInt(); //当前上传进度
final decimal = (((value * 100) - integer) * 100).toInt(); //剩余进度
final unit = '%';
return DefaultTextStyle(
style: TextStyle(
color: Colors.black87,
// fontWeight: FontWeight.bold,
),
child:
// Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Text(
// integer.toString(),
// style: TextStyle(fontSize: ScreenUtil().setSp(13)),
// ),
// Column(
// children: [
Container(
width: ScreenUtil().setWidth(100 * 2),
height: ScreenUtil().setWidth(100 * 2),
color: Color.fromRGBO(0, 0, 0, 0.5),
child: Center(
child: Text('${integer}${unit}',
style: TextStyle(
fontSize: ScreenUtil().setSp(24),
color: MyColours.color_fefefe)),
))
// Text('.$decimal',
// style: TextStyle(fontSize: ScreenUtil().setSp(13))),
// ],
// )
// ],
);
}
@override
Widget build(BuildContext context) {
// return Stack(
// alignment: AlignmentDirectional.center,
// children: [progress, progressText],
// );
return progressText;
}
}
... ...
import 'package:flutter/material.dart';
import 'package:one_key/constant/constant.dart';
import 'package:one_key/models/qiniu_info_model.dart';
import 'package:one_key/net/base_resp.dart';
import 'package:one_key/net/dio_util.dart';
import 'package:one_key/net/http_url.dart';
import 'package:one_key/utils/utils.dart';
class OnlineCheckEditProvider extends ChangeNotifier {
List imageList = []; //图片数组
List imageListFile = []; //本地图片显示
List imageListUrl = []; //七牛云地址
Map statusMap = {}; //图片上传状态 <bool> true显示图片 ******* false显示进度
QiniuInfoSunModel qiniuInfoSunModel;
// Map statusMapProgress = {}; //图片上传状态 <bool> true显示图片 ******* false显示进度
/// 获取七牛上传token信息
Future<QiniuInfoSunModel> getQiniuInfo(
BuildContext context, Map<String, String> params,
{isShowLoading = true}) async {
BaseResp<Map<String, dynamic>> baseResp = await DioUtil()
.request<Map<String, dynamic>>(
context, Method.get, HttpUrl.get_qiniu_info,
data: params, showLoading: false)
.catchError((error) {});
if (baseResp.code == Constant.status_success) {
if (baseResp.data.isEmpty) {
} else {
//解析解析
qiniuInfoSunModel = QiniuInfoModel.fromJson(baseResp.responseData).data;
return qiniuInfoSunModel;
}
} else {
if (baseResp != null) {
Utils.showToast(baseResp.msg ?? "");
}
}
}
}
... ...
... ... @@ -57,4 +57,5 @@ class MyColours {
static const Color color_9C9C9C = Color(0xff9C9C9C);
static const Color color_FD5656 = Color(0xffFD5656);
static const Color color_FAFAFA = Color(0xffFAFAFA);
static const Color color_0D0D0D = Color(0xff0D0D0D);
}
... ...
... ... @@ -667,6 +667,20 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
photo:
dependency: "direct main"
description:
name: photo
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.4.8"
photo_manager:
dependency: transitive
description:
name: photo_manager
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.4.8"
photo_view:
dependency: "direct main"
description:
... ... @@ -996,27 +1010,6 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0-nullsafety.3"
video_player:
dependency: "direct main"
description:
name: video_player
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.10.12+5"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.0"
video_player_web:
dependency: transitive
description:
name: video_player_web
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.4+1"
watcher:
dependency: transitive
description:
... ...
... ... @@ -90,11 +90,14 @@ dependencies:
easy_contact_picker: ^0.0.2
flutter_app_badger: ^1.1.2
scrollable_positioned_list: ^0.1.8
image_picker: ^0.6.7+21
video_player: ^0.10.3
#查看大图
photo_view: ^0.9.2
#七牛云sdk
qiniu_flutter_sdk: ^0.2.0
#相机拍照,单图选择
image_picker: ^0.6.7+21
#多图选择
photo: ^0.4.8
... ...