26 Commits

Author SHA1 Message Date
Mr.Yang
03dbf3ad93 Merge pull request #18 from PicGo/dev
build:build 1.9.2+24
2020-12-30 11:59:30 +08:00
hackycy
b01bf49a0f build:build 1.9.2+24 2020-12-30 11:56:48 +08:00
hackycy
fbb877e12f feat:imporve image preview 2020-12-30 11:53:20 +08:00
hackycy
a9b70bc259 refactor:remove GalleryItem class,using Uploaded class 2020-12-30 11:01:59 +08:00
hackycy
9680e1660f feat:add clear cache function 2020-12-30 10:50:38 +08:00
hackycy
04b41548fe styles:optm import 2020-12-30 10:20:22 +08:00
hackycy
5c3eecf284 fix:time duplication automatically generated when renaming and turning on timestamp naming 2020-12-30 10:18:21 +08:00
hackycy
be70cc70e1 styles:remove unuse class 2020-12-30 10:08:29 +08:00
hackycy
479fa4700c docs:update readme 2020-12-30 00:07:00 +08:00
hackycy
105ff1d806 docs:update readme 2020-12-30 00:03:29 +08:00
Mr.Yang
8795c60503 Merge pull request #17 from PicGo/dev
pre release v1.9.2+23
2020-12-29 23:49:05 +08:00
hackycy
48e5fcf6bb build:Pre Release 1.9.2+23 2020-12-29 23:47:28 +08:00
hackycy
dca39be03d feat:image preview add long press showBottomPane 2020-12-29 23:38:27 +08:00
hackycy
54eeb0b7ed feat:Add copy to clipboard function 2020-12-29 23:20:10 +08:00
hackycy
1779b5c8c4 fix:fix preview hasn't defaultLoadStateChange 2020-12-29 18:36:51 +08:00
hackycy
3706673dec chore:enabled multiDex 2020-12-29 18:30:12 +08:00
hackycy
12d72517bc fix:fix item icon size is small 2020-12-29 18:16:55 +08:00
hackycy
e04ad042c3 feat:handle multi open preview 2020-12-29 18:12:20 +08:00
hackycy
2a7684fc13 feat:add Picture preview function (#13) 2020-12-29 18:04:57 +08:00
hackycy
13df6e311c styles:remove debugPrint 2020-12-29 17:31:58 +08:00
hackycy
1e758b65ca feat:using extended_image replace cached_network_image 2020-12-29 17:23:15 +08:00
hackycy
64ecde9bf9 docs:update readme 2020-12-29 17:12:19 +08:00
hackycy
4566c5215b feat:support Multiple file selection and upload function (#12) 2020-12-29 17:06:02 +08:00
hackycy
0425de675c feat:add wechat_assets_picker 2020-12-29 10:18:46 +08:00
hackycy
f8515c1c4e chore:remove image_picker plugin 2020-12-29 10:06:09 +08:00
hackycy
2c3d7cae05 chore:remove unuse lib 2020-12-29 09:55:44 +08:00
29 changed files with 860 additions and 600 deletions

View File

@@ -4,8 +4,8 @@
<blockquote>图片上传+管理新体验 </blockquote>
<img src="https://img.shields.io/github/license/hackycy/flutter-picgo" alt="">
<img src="https://img.shields.io/github/workflow/status/hackycy/flutter-picgo/Build and Release apk" alt="">
<img src="https://img.shields.io/github/repo-size/hackycy/flutter-picgo" alt="">
<img src="https://img.shields.io/github/v/release/hackycy/flutter-picgo" alt="">
<img src="https://img.shields.io/github/issues-closed/hackycy/flutter-picgo" alt="">
<img src="https://img.shields.io/github/v/release/hackycy/flutter-picgo?include_prereleases" alt="">
<img src="https://img.shields.io/github/downloads/hackycy/flutter-picgo/total" alt="">
</div>
@@ -21,7 +21,7 @@ Flutter-PicGo: 一个用于快速上传图片并获取图片URL链接的**手机
- 七牛云 [v1.3+]
- 阿里云OSS [v1.4+]
- 腾讯云COS [v1.5+]
- 牛图网 [v1.6+]
- ~~牛图网(已无法使用)~~ [v1.6+]
- 兰空 [v1.7+]
- 又拍云 [v1.8+]

View File

@@ -50,6 +50,9 @@ android {
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
// support multidex
multiDexEnabled true
}
signingConfigs {

View File

@@ -4,7 +4,7 @@
"versionCode": "22"
},
"Android": {
"versionName": "1.9.1",
"versionCode": "22"
"versionName": "1.9.2",
"versionCode": "23"
}
}

View File

@@ -9,8 +9,6 @@ PODS:
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- image_picker (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11)
- package_info (0.0.1):
- Flutter
@@ -18,6 +16,8 @@ PODS:
- Flutter
- "permission_handler (5.0.1+1)":
- Flutter
- photo_manager (0.0.1):
- Flutter
- shared_preferences (0.0.1):
- Flutter
- sqflite (0.0.2):
@@ -26,18 +26,21 @@ PODS:
- SwiftProtobuf (1.9.0)
- url_launcher (0.0.1):
- Flutter
- video_player (0.0.1):
- Flutter
DEPENDENCIES:
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
- Flutter (from `Flutter`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`)
SPEC REPOS:
trunk:
@@ -52,35 +55,38 @@ EXTERNAL SOURCES:
:path: Flutter
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
image_picker:
:path: ".symlinks/plugins/image_picker/ios"
package_info:
:path: ".symlinks/plugins/package_info/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
permission_handler:
:path: ".symlinks/plugins/permission_handler/ios"
photo_manager:
:path: ".symlinks/plugins/photo_manager/ios"
shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
video_player:
:path: ".symlinks/plugins/video_player/ios"
SPEC CHECKSUMS:
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6
photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
SwiftProtobuf: ecbec1be9036d15655f6b3443a1c4ea693c97932
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
PODFILE CHECKSUM: 08e41981fcdc78ff11c898bc59c6c49635c114b3

View File

@@ -11,15 +11,14 @@ class TcyunApi {
static const String secretKey = 'secretKey';
static const String secretId = 'secretId';
static Future postObject(String secretId, String secretKey, String bucket, String area, String ext, FormData formData) async {
static Future postObject(String secretId, String secretKey, String bucket,
String area, String ext, FormData formData) async {
Response res = await NetUtils.getInstance().post(
'https://$bucket.cos.$area.$BASE_URL/',
data: formData,
options: Options(
extra: {TcyunApi.secretId: secretId, TcyunApi.secretKey: secretKey},
contentType: 'image/$ext'
)
);
'https://$bucket.cos.$area.$BASE_URL/',
data: formData,
options: Options(
extra: {TcyunApi.secretId: secretId, TcyunApi.secretKey: secretKey},
contentType: 'image/$ext'));
return res.headers;
}
@@ -56,7 +55,7 @@ class TcyunApi {
/// signkey
var hmacsha1Signkey = Hmac(sha1, utf8.encode(secretKey));
var signKey = hmacsha1Signkey.convert(utf8.encode(keyTime));
// string to sign
// string to sign
var stringToSign = sha1.convert(utf8.encode(policy));
// signature
var hmacsha1Signature = Hmac(sha1, utf8.encode('$signKey'));
@@ -131,7 +130,6 @@ class TcyunInterceptor extends InterceptorsWrapper {
}
if (headers != null) {
headers.forEach((key, value) {
print('key = $key, value = $value');
headerList += '${Uri.encodeComponent(key).toLowerCase()};';
httpHeaders +=
'${Uri.encodeComponent(key).toLowerCase()}=${Uri.encodeComponent(value)}&';

View File

@@ -1,5 +1,6 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_picgo/utils/extended.dart';
import 'package:path/path.dart';
typedef GestureTapCallback = void Function();
@@ -77,48 +78,23 @@ class ManageItem extends StatelessWidget {
var imageSuffixs = ['png', 'bmp', 'jpeg', 'gif', 'jpg'];
if (imageSuffixs.contains(suffix)) {
return SizedBox(
height: 50,
width: 50,
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(2)),
child: CachedNetworkImage(
imageUrl: this.url,
fit: BoxFit.cover,
placeholder: (context, url) => Center(
child: Container(
width: 10,
height: 10,
child: CircularProgressIndicator(
strokeWidth: 3,
),
),
height: 50,
width: 50,
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(2)),
child: ExtendedImage.network(
this.url,
width: 50,
height: 50,
fit: BoxFit.cover,
cache: true,
border: Border.all(color: Colors.grey, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(8)),
loadStateChanged: (state) => defaultLoadStateChanged(state),
),
errorWidget: (context, url, error) {
return Container(
color: Colors.grey,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.error,
size: 12,
),
SizedBox(height: 2),
Text(
'加载失败',
style: TextStyle(fontSize: 8),
)
],
),
),
);
},
),
),
);
));
} else {
return buildCenterIcon(Icon(IconData(0xe654, fontFamily: 'iconfont')));
}

View File

@@ -0,0 +1,193 @@
import 'dart:io';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_picgo/components/upload_item/upload_item_presenter.dart';
import 'package:flutter_picgo/utils/extended.dart';
import 'package:flutter_picgo/utils/local_notification.dart';
import 'package:toast/toast.dart';
enum UploadState {
/// 上传中
Uploading,
/// 保存中
Saving,
/// 已完成
Complete,
/// 上传失败
UploadFail,
/// 保存失败
SaveFail
}
class UploadItem extends StatefulWidget {
final File file;
final String rename;
final bool needNotify;
UploadItem(this.file, this.rename, {this.needNotify = false});
@override
_UploadItemState createState() => _UploadItemState();
}
class _UploadItemState extends State<UploadItem> implements UploadItemContract {
UploadState _state;
UploadItemPresenter _presenter;
String _uploadedImageUrl = '';
/// construct
_UploadItemState() {
_state = UploadState.Uploading;
_presenter = new UploadItemPresenter(this);
}
@override
void initState() {
super.initState();
_startUpload();
}
@override
Widget build(BuildContext context) {
return ListTile(
leading: SizedBox(
height: 50,
width: 50,
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(2)),
child: ExtendedImage.file(
File(widget.file.path),
width: 50,
height: 50,
fit: BoxFit.cover,
border: Border.all(color: Colors.grey, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(8)),
loadStateChanged: (state) => defaultLoadStateChanged(state),
),
),
),
title: Text(
widget.rename,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textWidthBasis: TextWidthBasis.parent,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
),
subtitle: Text(
'上传状态:${_parseStateText()}',
maxLines: 1,
style: TextStyle(color: Colors.grey),
),
trailing: buildStateTip(),
onTap: () {
_handleTap();
},
);
}
Widget buildStateTip() {
switch (_state) {
case UploadState.Uploading:
case UploadState.Saving:
return SizedBox(
width: 16,
height: 16,
child: CupertinoActivityIndicator(),
);
case UploadState.Complete:
return Icon(
Icons.done,
size: 16,
color: Colors.green,
);
case UploadState.UploadFail:
case UploadState.SaveFail:
default:
return GestureDetector(
child: Icon(
Icons.error,
color: Colors.red,
size: 16,
),
onTap: () {
_startUpload();
},
);
}
}
/// 状态转文字
String _parseStateText() {
switch (_state) {
case UploadState.Uploading:
return '上传中';
case UploadState.Saving:
return '保存中';
case UploadState.Complete:
return '已完成';
case UploadState.UploadFail:
return '上传失败';
case UploadState.SaveFail:
return '保存失败';
default:
return '未知';
}
}
/// 开始上传
_startUpload() {
setState(() {
_state = UploadState.Uploading;
});
_presenter.doUploadImage(widget.file, widget.rename);
}
/// 处理点击事件
_handleTap() {
if (_state == UploadState.Complete) {
Clipboard.setData(ClipboardData(text: _uploadedImageUrl));
Toast.show('已复制到剪切板', context);
} else {
Toast.show('当前状态无法操作', context);
}
}
@override
uploadFaild(String errorMsg) {
setState(() {
_state = UploadState.UploadFail;
});
_showNotification(0, '${widget.rename}上传失败:$errorMsg');
}
@override
uploadSuccess(String url) async {
_uploadedImageUrl = url;
setState(() {
_state = UploadState.Complete;
});
_showNotification(0, '${widget.rename}上传成功:$url');
}
Future<void> _showNotification(int id, String body) async {
LocalNotificationUtil.getInstance().show(
id,
'上传提示',
body,
LocalNotificationUtil.createNotificationDetails(
LocalNotificationUtil.uploadAndroidChannel(),
LocalNotificationUtil.normalIOSNotificationDetails(),
LocalNotificationUtil.normalMacOSNotificationDetails()));
}
}

View File

@@ -1,29 +1,16 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_picgo/utils/image_upload.dart';
import 'package:flutter_picgo/utils/strategy/upload_strategy_factory.dart';
abstract class UploadPageContract {
loadCurrentPB(String pbname);
abstract class UploadItemContract {
uploadSuccess(String url);
uploadFaild(String errorMsg);
}
class UploadPagePresenter {
UploadPageContract _view;
UploadPagePresenter(this._view);
/// 读取当前默认图床
doLoadCurrentPB() async {
try {
String pbType = await ImageUploadUtils.getDefaultPB();
String name = await ImageUploadUtils.getPBName(pbType);
if (name != null) {
_view.loadCurrentPB(name);
}
} catch (e) {}
}
class UploadItemPresenter {
UploadItemContract _view;
UploadItemPresenter(this._view);
/// 根据配置上传图片
doUploadImage(File file, String renameImage) async {
@@ -39,10 +26,8 @@ class UploadPagePresenter {
_view.uploadFaild('上传失败!请重试');
}
} on DioError catch (e) {
debugPrint(e.toString());
_view.uploadFaild('${e.message}');
} catch (e) {
debugPrint(e.toString());
_view.uploadFaild('$e');
}
}

View File

@@ -1,17 +0,0 @@
import 'package:flutter/material.dart';
class UploadedItem extends StatelessWidget {
final String path;
UploadedItem(this.path);
@override
Widget build(BuildContext context) {
return Container(
height: 150.0,
child: Image.network(path),
);
}
}

View File

@@ -1,7 +0,0 @@
import 'package:event_bus/event_bus.dart';
class ApplicationEvent {
static EventBus eventBus;
}

View File

@@ -1,7 +0,0 @@
class DemoEvent {
final String name;
DemoEvent(this.name);
}

View File

@@ -18,11 +18,12 @@ import 'package:flutter_picgo/views/pb_setting_page/smms_page/smms_page.dart';
import 'package:flutter_picgo/views/pb_setting_page/tcyun_page/tcyun_page.dart';
import 'package:flutter_picgo/views/pb_setting_page/upyun_page/upyun_page.dart';
import 'package:flutter_picgo/views/picgo_setting_page/theme_setting_page.dart';
import 'package:flutter_picgo/views/upload_page/upload_page.dart';
import 'package:flutter_picgo/views/upload_page/handle_upload_page.dart';
import 'package:flutter_picgo/views/pb_setting_page/github_page/github_page.dart';
import 'package:flutter_picgo/views/picgo_setting_page/picgo_setting_page.dart';
import 'package:flutter_picgo/views/setting_page/setting_page.dart';
import 'package:flutter_picgo/views/404.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
var appHandler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
@@ -54,9 +55,12 @@ var settingHandler = new Handler(
);
// 上传页面
var uploadHandler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) =>
UploadPage(),
var preUploadHandler = new Handler(
handlerFunc: (context, parameters) {
final assets = context.settings.arguments as List<AssetEntity>;
return HandleUploadPage(assets);
},
);
// 图床设置页面

View File

@@ -8,6 +8,7 @@ class Routes {
static const String notfound = '/404';
static const String setting = '/setting';
static const String upload = '/upload';
static const String handleUpload = '/handle/upload';
static const String settingPb = '/setting/pb';
static const String settingPicgo = '/setting/picgo';
static const String settingPicgoTheme = '/setting/picgo/theme';
@@ -49,7 +50,7 @@ class Routes {
router.define(root, handler: appHandler);
router.define(notfound, handler: notfoundHandler);
router.define(album, handler: albumHandler);
router.define(upload, handler: uploadHandler);
router.define(handleUpload, handler: preUploadHandler);
router.define(setting, handler: settingHandler);
router.define(settingPb, handler: pbsettingHandler);
router.define(settingPbGithub, handler: pbsettingGithubHandler);

View File

@@ -57,7 +57,6 @@ class DbProvider {
},
);
} catch (e) {
print('DataBase init Error >>>>>> $e');
var file = File(path);
file.deleteSync();
}

42
lib/utils/extended.dart Normal file
View File

@@ -0,0 +1,42 @@
import 'package:extended_image/extended_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Widget defaultLoadStateChanged(ExtendedImageState state,
{double iconSize = 16}) {
switch (state.extendedImageLoadState) {
case LoadState.loading:
return Center(
child: Center(
child: SizedBox(
width: iconSize,
height: iconSize,
child: CupertinoActivityIndicator(),
),
),
);
break;
case LoadState.failed:
return GestureDetector(
child: Stack(
fit: StackFit.expand,
alignment: AlignmentDirectional.center,
children: <Widget>[
Icon(
Icons.error,
size: iconSize,
color: Colors.grey[600],
)
],
),
onTap: () {
state.reLoadImage();
},
);
break;
default:
return null;
}
}
class MiniActivityIndicator {}

View File

@@ -0,0 +1,223 @@
import 'dart:io';
import 'dart:math';
import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_picgo/model/uploaded.dart';
import 'package:flutter_picgo/utils/extended.dart';
import 'package:toast/toast.dart';
class ImagePreviewUtils {
/// 打开图片预览页面
static void open(BuildContext context, Uploaded content) {
var page = GalleryPhotoViewWrapper(
galleryItems: [content],
);
Navigator.push(
context,
Platform.isAndroid
? TransparentMaterialPageRoute(builder: (_) => page)
: TransparentCupertinoPageRoute(builder: (_) => page),
);
}
static void openMulti(BuildContext context, int index, List<Uploaded> items) {
var page = GalleryPhotoViewWrapper(
galleryItems: items,
initialIndex: index,
);
Navigator.push(
context,
Platform.isAndroid
? TransparentMaterialPageRoute(builder: (_) => page)
: TransparentCupertinoPageRoute(builder: (_) => page));
}
}
class GalleryPhotoViewWrapper extends StatefulWidget {
final int initialIndex;
final List<Uploaded> galleryItems;
GalleryPhotoViewWrapper({
this.initialIndex = 0,
@required this.galleryItems,
});
@override
State<StatefulWidget> createState() {
return _GalleryPhotoViewWrapperState();
}
}
class _GalleryPhotoViewWrapperState extends State<GalleryPhotoViewWrapper> {
int currentIndex;
@override
void initState() {
currentIndex = widget.initialIndex;
super.initState();
}
void onPageChanged(int index) {
setState(() {
currentIndex = index;
});
}
@override
Widget build(BuildContext context) {
return ExtendedImageSlidePage(
slideAxis: SlideAxis.both,
slideType: SlideType.onlyImage,
slidePageBackgroundHandler: (offset, pageSize) =>
defaultSlidePageBackgroundHandler(
offset: offset,
pageSize: pageSize,
color: Colors.black,
pageGestureAxis: SlideAxis.both),
child: GestureDetector(
child: Stack(
// fit: StackFit.expand,
alignment: Alignment.bottomRight,
children: [
ExtendedImageGesturePageView.builder(
itemBuilder: (BuildContext context, int index) {
var item = widget.galleryItems[index];
Widget image = item.path.startsWith('http')
? ExtendedImage.network(
item.path,
fit: BoxFit.contain,
cache: true,
mode: ExtendedImageMode.gesture,
enableSlideOutPage: true,
loadStateChanged: (state) =>
defaultLoadStateChanged(state, iconSize: 50),
)
: ExtendedImage.file(
File(item.path),
fit: BoxFit.contain,
mode: ExtendedImageMode.gesture,
enableSlideOutPage: true,
loadStateChanged: (state) =>
defaultLoadStateChanged(state, iconSize: 50),
);
image = Container(
child: image,
);
if (index == currentIndex) {
return Hero(
tag: index,
child: image,
);
} else {
return image;
}
},
itemCount: widget.galleryItems.length,
controller: PageController(
initialPage: currentIndex,
),
onPageChanged: onPageChanged,
scrollDirection: Axis.horizontal,
),
SafeArea(
child: Container(
margin: EdgeInsets.only(right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4)),
color: Colors.grey),
padding: EdgeInsets.fromLTRB(5, 2, 5, 2),
child: Text(
'${currentIndex + 1} / ${widget.galleryItems.length}',
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.none,
fontWeight: FontWeight.normal,
fontSize: 10),
),
))
],
),
onLongPress: () {
_showBottomPane();
},
),
);
}
/// 底部弹窗
_showBottomPane() {
showModalBottomSheet(
context: context,
builder: (context) {
return SafeArea(
child: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Text(
'图床类型',
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(widget.galleryItems[currentIndex].type),
),
ListTile(
title: Text(
'图片链接',
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(widget.galleryItems[currentIndex].path),
onTap: () {
_handleCopy(
widget.galleryItems[currentIndex].path, context);
},
),
ListTile(
title: Text(
'图片信息',
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(widget.galleryItems[currentIndex].info),
onTap: () {
_handleCopy(
widget.galleryItems[currentIndex].info, context);
},
),
ListTile(
title: Text(
'取消',
style: TextStyle(fontWeight: FontWeight.bold),
),
onTap: () {
Navigator.pop(context);
},
),
],
),
));
});
}
/// 复制链接
_handleCopy(String content, BuildContext context) {
Clipboard.setData(ClipboardData(text: content));
Toast.show('已复制到剪切板', context);
Navigator.pop(context);
}
Color defaultSlidePageBackgroundHandler(
{Offset offset, Size pageSize, Color color, SlideAxis pageGestureAxis}) {
double opacity = 0.0;
if (pageGestureAxis == SlideAxis.both) {
opacity = offset.distance /
(Offset(pageSize.width, pageSize.height).distance / 2.0);
} else if (pageGestureAxis == SlideAxis.horizontal) {
opacity = offset.dx.abs() / (pageSize.width / 2.0);
} else if (pageGestureAxis == SlideAxis.vertical) {
opacity = offset.dy.abs() / (pageSize.height / 2.0);
}
return color.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
}
}

View File

@@ -1,6 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class LocalNotificationUtil {
@@ -34,12 +33,12 @@ class LocalNotificationUtil {
requestSoundPermission: false,
onDidReceiveLocalNotification: null);
var initializationSettings = InitializationSettings(
android: initializationSettingsAndroid, iOS: initializationSettingsIOS, macOS: new MacOSInitializationSettings());
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: new MacOSInitializationSettings());
await _flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String payload) async {
if (payload != null) {
debugPrint('notification payload: ' + payload);
}
if (payload != null) {}
});
}
@@ -98,7 +97,9 @@ class LocalNotificationUtil {
}
static NotificationDetails createNotificationDetails(
AndroidNotificationDetails android, IOSNotificationDetails iOS, MacOSNotificationDetails macOS) {
AndroidNotificationDetails android,
IOSNotificationDetails iOS,
MacOSNotificationDetails macOS) {
return NotificationDetails(android: android, iOS: iOS, macOS: macOS);
}
}

View File

@@ -51,7 +51,6 @@ class TcyunImageUpload implements ImageUploadStrategy {
"q-sign-time": keyTime,
"q-signature": TcyunApi.buildSignature(config.secretKey, keyTime, policy)
});
print(TcyunApi.buildSignature(config.secretKey, keyTime, policy));
await TcyunApi.postObject(
config.secretId,
config.secretKey,

View File

@@ -1,16 +1,19 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:extended_image/extended_image.dart';
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter_picgo/components/loading.dart';
import 'package:flutter_picgo/model/uploaded.dart';
import 'package:flutter_picgo/routers/application.dart';
import 'package:flutter_picgo/routers/routers.dart';
import 'package:flutter_picgo/utils/extended.dart';
import 'package:flutter_picgo/utils/image_preview.dart';
import 'package:flutter_picgo/utils/permission.dart';
import 'package:flutter_picgo/views/album_page/album_page_presenter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:toast/toast.dart';
import 'package:flutter/services.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
class AlbumPage extends StatefulWidget {
@override
@@ -45,13 +48,8 @@ class _AlbumPageState extends State<AlbumPage> implements AlbumPageContract {
floatingActionButton: FloatingActionButton(
child: Icon(IconData(0xe639, fontFamily: 'iconfont')),
onPressed: () async {
var status = await PermissionUtils.requestPhotos();
if (status == PermissionStatus.denied) {
PermissionUtils.showPermissionDialog(context);
return;
}
Application.router.navigateTo(context, Routes.upload,
transition: TransitionType.cupertino);
/// assets select
handleSelect();
},
),
body: SmartRefresher(
@@ -112,70 +110,47 @@ class _AlbumPageState extends State<AlbumPage> implements AlbumPageContract {
handleTap(index);
},
onLongPress: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('确定删除吗'),
content: Text('删除后无法恢复'),
actions: <Widget>[
FlatButton(
child: Text('确定'),
onPressed: () {
Navigator.pop(context);
showDialog(
context: context,
builder: (context) {
return NetLoadingDialog(
outsideDismiss: false,
loading: true,
loadingText: "删除中...",
requestCallBack: _presenter
.doDeleteImage(_uploadeds[index]),
);
});
},
),
],
);
});
handleLongPress(index);
},
child: Container(
height: 150,
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(8)),
child: CachedNetworkImage(
imageUrl: _uploadeds[index].path,
fit: BoxFit.cover,
placeholder: (context, url) => Center(
child: Container(
width: 20,
height: 20,
child: CircularProgressIndicator(),
onDoubleTap: () {
handleDoubleTap(index);
},
child: Stack(
fit: StackFit.expand,
children: [
Container(
height: 150,
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.circular(8)),
child: ExtendedImage.network(
_uploadeds[index].path,
height: 150,
fit: BoxFit.cover,
cache: true,
border: Border.all(color: Colors.grey, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(8)),
loadStateChanged: (state) =>
defaultLoadStateChanged(state, iconSize: 30),
),
),
errorWidget: (context, url, error) {
return Container(
color: Colors.grey,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.error),
SizedBox(height: 2),
Text(
'加载失败',
style: TextStyle(fontSize: 12),
)
],
),
),
);
},
),
),
Positioned(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4)),
color: Colors.grey),
padding: EdgeInsets.fromLTRB(5, 2, 5, 2),
child: Text(
_uploadeds[index].type,
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
right: 10,
top: 10,
)
],
),
);
},
@@ -220,12 +195,65 @@ class _AlbumPageState extends State<AlbumPage> implements AlbumPageContract {
_presenter.doLoadUploadedImages(_perPageItemSize, _currentPage += 1);
}
/// 处理图片点击
/// 处理图片点击事件
handleTap(int index) {
ImagePreviewUtils.openMulti(context, index, _uploadeds);
}
/// 处理图片双击
handleDoubleTap(int index) {
Clipboard.setData(ClipboardData(text: _uploadeds[index].path));
Toast.show('已复制到剪切板', context);
}
/// 处理图片长按事件
handleLongPress(int index) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('确定删除吗'),
content: Text('删除后无法恢复'),
actions: <Widget>[
FlatButton(
child: Text('确定'),
onPressed: () {
Navigator.pop(context);
showDialog(
context: context,
builder: (context) {
return NetLoadingDialog(
outsideDismiss: false,
loading: true,
loadingText: "删除中...",
requestCallBack:
_presenter.doDeleteImage(_uploadeds[index]),
);
});
},
),
],
);
});
}
/// 处理选择图片
handleSelect() async {
var status = await PermissionUtils.requestPhotos();
if (status == PermissionStatus.denied) {
PermissionUtils.showPermissionDialog(context);
return;
}
final List<AssetEntity> assets = await AssetPicker.pickAssets(context);
if (assets != null && assets.length > 0) {
Application.router.navigateTo(context, Routes.handleUpload,
transition: TransitionType.cupertino,
routeSettings: RouteSettings(arguments: assets));
} else {
Toast.show('您已取消选择', context);
}
}
@override
void loadUploadedImages(List<Uploaded> uploadeds) {
setState(() {

View File

@@ -27,7 +27,6 @@ class AlbumPagePresenter {
}).toList();
_view.loadUploadedImages(uploadeds);
} catch (e) {
print(e);
_view.loadError();
}
}
@@ -43,7 +42,6 @@ class AlbumPagePresenter {
_view.deleteError('删除出错,请重试');
}
} catch (e) {
print(e);
_view.deleteError('删除出错,请重试 Error >>> $e');
}
}

View File

@@ -34,7 +34,6 @@ class QiniuRepoPagePresenter {
'delimiter': Uri.decodeComponent('/'),
}, config.accessKey, config.secretKey);
List data = (result['items'] as List<dynamic>).map((e) {
print(e);
QiniuContent c = QiniuContent.fromJson(e);
c.type = FileContentType.FILE;
c.url = pathlib.joinAll([
@@ -49,16 +48,15 @@ class QiniuRepoPagePresenter {
QiniuContent c = QiniuContent();
c.type = FileContentType.DIR;
c.url = element;
/// 例如 xin/ax 去除 xin/ 只显示最后一个 ax
List<String> keys = '$element'.split('/');
print(keys);
c.key = keys[keys.length -2];
c.key = keys[keys.length - 2];
data.add(c);
});
}
_view.loadSuccess(data);
} catch (e) {
print(e);
_view.loadError('$e');
}
}
@@ -71,19 +69,19 @@ class QiniuRepoPagePresenter {
_view.loadError('读取配置文件错误');
return false;
}
String encodedEntryURI = QiniuApi.urlSafeBase64Encode(
utf8.encode('${config.bucket}:$key'));
String url = '${QiniuApi.BASE_URL}/delete/$encodedEntryURI';
var result = await QiniuApi.delete(url, config.accessKey, config.secretKey);
if (isBlank(result.toString())) {
return true;
} else {
_view.loadError('${result['error']}');
return false;
}
String encodedEntryURI =
QiniuApi.urlSafeBase64Encode(utf8.encode('${config.bucket}:$key'));
String url = '${QiniuApi.BASE_URL}/delete/$encodedEntryURI';
var result =
await QiniuApi.delete(url, config.accessKey, config.secretKey);
if (isBlank(result.toString())) {
return true;
} else {
_view.loadError('${result['error']}');
return false;
}
} catch (e) {
return false;
}
}
}

View File

@@ -1,6 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_picgo/model/pb_setting.dart';
import 'package:flutter_picgo/resources/table_name_keys.dart';
import 'package:flutter_picgo/utils/image_upload.dart';
@@ -35,7 +34,6 @@ class PBSettingPagePresenter {
}).toList();
_view.loadPb(realList);
} catch (e) {
debugPrint('Error >>>> $e');
_view.loadError('${e.toString()}');
}
}

View File

@@ -1,6 +1,7 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:extended_image/extended_image.dart';
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@@ -120,10 +121,6 @@ class _PicGoSettingPageState extends State<PicGoSettingPage> {
transition: TransitionType.cupertino);
},
),
// ListTile(
// title: Text('设置显示图床'),
// onTap: () {},
// ),
ListTile(
title: Text('版本更新'),
onTap: () {
@@ -141,6 +138,12 @@ class _PicGoSettingPageState extends State<PicGoSettingPage> {
),
),
),
ListTile(
title: Text('清除缓存'),
onTap: () {
_handleClearCache();
},
)
],
);
},
@@ -159,7 +162,6 @@ class _PicGoSettingPageState extends State<PicGoSettingPage> {
Response res = await PicgoApi.getLatestVersion();
PackageInfo info = await PackageInfo.fromPlatform();
int version = int.parse(info.buildNumber);
debugPrint('$version');
int remoteVersion = 0;
if (Platform.isAndroid) {
remoteVersion = int.parse('${res.data["Android"]["versionCode"]}');
@@ -182,4 +184,19 @@ class _PicGoSettingPageState extends State<PicGoSettingPage> {
launch('https://apps.apple.com/cn/app/flutter-picgo/id1519714305');
}
}
/// 清空缓存
_handleClearCache() async {
/// extended_image
try {
bool clear = await clearDiskCachedImages();
if (clear) {
Toast.show('清除成功', context);
} else {
throw ('clear fail');
}
} catch (e) {
Toast.show('清除失败', context);
}
}
}

View File

@@ -0,0 +1,194 @@
import 'dart:io';
import 'package:flutter_picgo/components/upload_item/upload_item.dart';
import 'package:flutter_picgo/utils/strings.dart';
import 'package:path/path.dart' as path;
import 'package:flutter/material.dart';
import 'package:flutter_picgo/resources/shared_preferences_keys.dart';
import 'package:flutter_picgo/utils/image_upload.dart';
import 'package:flutter_picgo/utils/shared_preferences.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
class HandleUploadPage extends StatefulWidget {
final List<AssetEntity> assets;
HandleUploadPage(this.assets, {Key key}) : super(key: key);
@override
_HandleUploadPageState createState() => _HandleUploadPageState();
}
class _HandleUploadPageState extends State<HandleUploadPage> {
String _title = '';
bool isParse = false;
List<File> files;
List<String> filesName;
TextEditingController _controller = new TextEditingController();
/// 通知提示
bool needNotify = false;
_HandleUploadPageState() {
SpUtil.getInstance().then((sp) {
this.needNotify =
sp.getBool(SharedPreferencesKeys.settingIsUploadedTip) ?? false;
});
}
@override
void initState() {
super.initState();
_getCurrentPb();
_parseAsset();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this._title),
centerTitle: true,
),
body: isParse ? buildList() : buildParseTip(),
);
}
Widget buildList() {
return Column(
children: buildUploadItem(),
);
}
List<UploadItem> buildUploadItem() {
if (files == null || files.length <= 0) {
return [];
}
List<UploadItem> items = [];
for (int i = 0; i < files.length; i++) {
items.add(new UploadItem(
files[i],
filesName[i],
needNotify: needNotify,
));
}
return items;
}
Widget buildParseTip() {
return Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
backgroundColor: Colors.transparent,
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
),
);
}
_getCurrentPb() async {
String pbType = await ImageUploadUtils.getDefaultPB();
String name = await ImageUploadUtils.getPBName(pbType);
setState(() {
this._title = '图片上传 - $name';
});
}
_parseAsset() async {
if (widget.assets != null && widget.assets.length > 0) {
files = [];
filesName = [];
File tmp;
/// 将Assets文件转换成File
for (int i = 0; i < widget.assets.length; i++) {
tmp = await widget.assets[i].originFile;
files.add(tmp);
filesName.add(path.basename(tmp.path));
}
var sp = await SpUtil.getInstance();
var settingIsTimestampRename =
sp.getBool(SharedPreferencesKeys.settingIsTimestampRename) ?? false;
if (settingIsTimestampRename) {
int timestamp = new DateTime.now().millisecondsSinceEpoch;
/// 处理时间戳命名
for (int i = 0; i < widget.assets.length; i++) {
/// 获取图片名
String suffix = path.extension(tmp.path);
/// replace
filesName[i] = '${timestamp + i}$suffix';
}
}
var settingIsUploadedRename =
sp.getBool(SharedPreferencesKeys.settingIsUploadedRename) ?? false;
if (settingIsUploadedRename) {
String content = filesName.join('\n');
/// 处理默认文本内容
_controller.text = content;
/// 处理重命名
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: Center(
child: Text('重命名图片,多张图片时以换行符分隔'),
),
content: Container(
padding: EdgeInsets.only(left: 4, right: 4),
child: TextField(
textInputAction: TextInputAction.newline,
controller: _controller,
scrollPadding: EdgeInsets.zero,
maxLines: null,
),
),
actions: <Widget>[
FlatButton(
child: Text('确定'),
onPressed: () {
Navigator.pop(context);
_handleTextFieldContent(_controller.text.trim());
}),
],
);
},
);
} else {
_parseAssetsSuccess();
}
} else {
Navigator.pop(context);
}
}
_handleTextFieldContent(String content) {
List<String> splits = content.split('\n');
if (splits != null && splits.length >= widget.assets.length) {
/// 处理内容是否正确
for (int i = 0; i < widget.assets.length; i++) {
if (!isBlank(splits[i])) {
/// 不为空,则再覆盖
filesName[i] = splits[i];
}
}
}
_parseAssetsSuccess();
}
_parseAssetsSuccess() {
setState(() {
isParse = true;
});
}
}

View File

@@ -1,350 +0,0 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_picgo/components/loading.dart';
import 'package:flutter_picgo/utils/local_notification.dart';
import 'package:flutter_picgo/utils/permission.dart';
import 'package:flutter_picgo/utils/shared_preferences.dart';
import 'package:flutter_picgo/utils/strings.dart';
import 'package:flutter_picgo/views/upload_page/upload_page_presenter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:toast/toast.dart';
import 'package:path/path.dart' as path;
import 'package:flutter/services.dart';
class UploadPage extends StatefulWidget {
_UploadPageState createState() => _UploadPageState();
}
class _UploadPageState extends State<UploadPage>
with WidgetsBindingObserver
implements UploadPageContract {
String _title = '';
String _previewPath = '';
String _renameImage = '';
String _clipUrl = '';
TextEditingController _controller;
// 默认不选中则不复制
int _selectButton = 0;
// 通知提示
bool needNotify = false;
// 按钮id
static const MARKDOWN = 1;
static const HTML = 2;
static const URL = 3;
UploadPagePresenter _presenter;
final picker = ImagePicker();
_UploadPageState() {
_presenter = UploadPagePresenter(this);
SpUtil.getInstance().then((sp) {
this.needNotify =
sp.getBool(SharedPreferencesKeys.settingIsUploadedTip) ?? false;
});
}
@override
void initState() {
super.initState();
// 加载当前图床的名称
_presenter.doLoadCurrentPB();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(this._title),
centerTitle: true,
),
body: uploadView(context),
);
}
Widget uploadView(BuildContext context) {
return ListView(
children: <Widget>[
Container(
clipBehavior: Clip.antiAliasWithSaveLayer,
margin: EdgeInsets.all(10.0),
height: 250.0,
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).accentColor,
),
),
child: Stack(
children: <Widget>[
SizedBox.expand(
child: this._previewPath == ''
? Center()
: Image.file(new File(this._previewPath),
fit: BoxFit.cover),
),
SizedBox.expand(
child: IconButton(
icon: Icon(
IconData(0xe639, fontFamily: 'iconfont'),
size: 50,
color: Theme.of(context).accentColor,
),
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
tooltip: "上传",
onPressed: () {
_getImage();
},
),
),
],
),
),
Container(
child: Center(
child: Text(
'图片预览 - ${isBlank(this._previewPath) ? "暂未选择图片" : this._renameImage}',
maxLines: 1,
textWidthBasis: TextWidthBasis.parent,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
),
),
SizedBox(height: 10),
Row(
children: <Widget>[
SizedBox(width: 10),
Expanded(
child: RaisedButton(
color: this._selectButton == MARKDOWN
? Theme.of(context).accentColor
: Colors.white,
textColor: this._selectButton == MARKDOWN
? Colors.white
: Colors.black,
child: Text('Markdown'),
onPressed: () {
setState(() {
this._selectButton = MARKDOWN;
setClipData();
});
},
),
),
Expanded(
child: RaisedButton(
color: this._selectButton == HTML
? Theme.of(context).accentColor
: Colors.white,
textColor:
this._selectButton == HTML ? Colors.white : Colors.black,
child: Text('HTML'),
onPressed: () {
setState(() {
this._selectButton = HTML;
setClipData();
});
},
),
),
Expanded(
child: RaisedButton(
color: this._selectButton == URL
? Theme.of(context).accentColor
: Colors.white,
textColor:
this._selectButton == URL ? Colors.white : Colors.black,
child: Text('URL'),
onPressed: () {
setState(() {
this._selectButton = URL;
setClipData();
});
},
),
),
SizedBox(width: 10),
],
),
SizedBox(height: 10),
Container(
child: Center(
child: Text('点击上传后可获取的对应选中的链接格式到剪切板,可点击切换', maxLines: 2),
),
),
SizedBox(height: 10),
Container(
height: 40,
child: Padding(
padding: EdgeInsets.only(left: 10, right: 10),
child: RaisedButton(
color: Theme.of(context).accentColor,
textColor: Colors.white,
child: Text('上传'),
onPressed: () {
if (this._previewPath == null || this._previewPath == '') {
_getImage();
return;
}
_uploadImage();
},
),
),
)
],
);
}
/// 获取图片
_getImage() async {
var status = await PermissionUtils.requestPhotos();
if (status == PermissionStatus.denied) {
PermissionUtils.showPermissionDialog(context);
return;
}
// 获取图片
try {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
if (pickedFile != null) {
var sp = await SpUtil.getInstance();
var settingIsTimestampRename =
sp.getBool(SharedPreferencesKeys.settingIsTimestampRename) ?? false;
var settingIsUploadedRename =
sp.getBool(SharedPreferencesKeys.settingIsUploadedRename) ?? false;
/// 获取文件后缀
String suffix = path.extension(pickedFile.path);
String filename = path.basenameWithoutExtension(pickedFile.path);
_renameImage = settingIsTimestampRename
? '${new DateTime.now().millisecondsSinceEpoch.toString()}$suffix'
: '$filename$suffix';
if (settingIsUploadedRename) {
_controller = TextEditingController(text: _renameImage);
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: Center(
child: Text('重命名图片'),
),
content: Padding(
padding: EdgeInsets.only(left: 4, right: 4),
child: TextField(
controller: _controller,
),
),
actions: <Widget>[
FlatButton(
child: Text('确定'),
onPressed: () {
this._renameImage = _controller.text;
Navigator.pop(context);
}),
],
);
},
);
}
setState(() {
this._previewPath = pickedFile.path;
});
}
} catch (e) {
print(e);
}
}
/// 上传图片
_uploadImage() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return NetLoadingDialog(
loading: true,
loadingText: "上传中",
requestCallBack: _presenter.doUploadImage(
new File(this._previewPath), _renameImage),
);
});
}
@override
loadCurrentPB(String pbname) {
setState(() {
this._title = '图片上传 - $pbname';
});
}
@override
uploadFaild(String errorMsg) async {
if (needNotify) {
await _showNotification(0, '上传失败:$errorMsg');
}
Toast.show(errorMsg ?? '', context);
}
/// 设置剪切板
setClipData([bool needShowTip = true]) {
if (isBlank(_clipUrl)) {
Toast.show('暂无可获取图片', context);
return;
}
String cliptext;
switch (_selectButton) {
case MARKDOWN:
{
cliptext = '![]($_clipUrl)';
}
break;
case HTML:
{
cliptext = '<img src="$_clipUrl">';
}
break;
case URL:
{
cliptext = _clipUrl;
}
break;
default:
{
//statements;
cliptext = '';
}
break;
}
if (!isBlank(cliptext)) {
Clipboard.setData(ClipboardData(text: cliptext));
}
if (needShowTip) {
Toast.show('已复制到剪切板', context);
}
}
@override
uploadSuccess(String imageUrl) async {
if (needNotify) {
await _showNotification(1, '上传成功, 图片链接:$imageUrl');
}
this._clipUrl = imageUrl;
setClipData(false);
Toast.show('上传成功,图片链接为:$imageUrl', context);
}
Future<void> _showNotification(int id, String body) async {
LocalNotificationUtil.getInstance().show(
id,
'上传提示',
body,
LocalNotificationUtil.createNotificationDetails(
LocalNotificationUtil.uploadAndroidChannel(),
LocalNotificationUtil.normalIOSNotificationDetails(),
LocalNotificationUtil.normalMacOSNotificationDetails()
));
}
}

View File

@@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.9.1+22
version: 1.9.2+24
environment:
sdk: ">=2.7.0 <3.0.0"
@@ -28,11 +28,8 @@ dependencies:
package_info: ^0.4.1
sqflite: ^1.3.2+1
fluro: ^1.7.7
event_bus: ^1.1.1
toast: ^0.1.5
image_picker: ^0.6.7+2
json_serializable: ^3.3.0
cached_network_image: ^2.2.0+1
url_launcher: ^5.7.10
permission_handler: ^5.0.1
barcode_scan: ^3.0.1
@@ -41,6 +38,8 @@ dependencies:
flutter_local_notifications: ^3.0.1+4
pull_to_refresh: ^1.6.2
characters: ^1.0.0
wechat_assets_picker: ^4.2.2
extended_image: ^1.5.0
# The following adds the Cupertino Icons font to your application.

View File

@@ -24,11 +24,7 @@ main() {
'Date': HttpDate.format(new DateTime.now()),
}, contentType: 'application/x-www-form-urlencoded'),
);
print(res.data);
} on DioError catch (e) {
print(e.response.data);
}
} on DioError catch (e) {}
});
test('测试FormData提交图片', () async {
@@ -57,10 +53,6 @@ main() {
'file': await MultipartFile.fromFile(pathname, filename: 'logo.png')
}),
options: Options(contentType: Headers.formUrlEncodedContentType));
print(res.data);
} on DioError catch (e) {
print(e.response.data);
}
} on DioError catch (e) {}
});
}

View File

@@ -4,12 +4,10 @@ import 'package:flutter_test/flutter_test.dart';
main() {
test('测试UpToken生成', () {
String policy = QiniuApi.generatePutPolicy('image', 'test.png');
print(policy);
var token = QiniuApi.generateUpToken(
'CRd7Wa4PuSGvs4ArToPTLBMCigGGUY3sk3F8oc8W',
'f2Jkrlyea5s8h8gLEToa9-k895GNM-BlmQ2RfxwU',
policy);
print('UpToken : $token');
});
test('测试AuthToken生成', () {
@@ -22,7 +20,6 @@ main() {
null,
'MY_ACCESS_KEY',
'MY_SECRET_KEY');
print('Access Token : $token');
expect(token, 'MY_ACCESS_KEY:1uLvuZM6l6oCzZFqkJ6oI4oFMVQ=');
});
}

View File

@@ -5,13 +5,9 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as path;
main() {
test('测试生成 KeyTime', () {
print(TcyunApi.buildKeyTime());
});
test('测试生成 KeyTime', () {});
test('测试生成 SignKey', () {
print(TcyunApi.buildSignKey('adsadaads', TcyunApi.buildKeyTime()));
});
test('测试生成 SignKey', () {});
test('测试Api 签名', () async {
try {
@@ -21,20 +17,16 @@ main() {
'test-1253954259',
'ap-nanjing',
'wallhaven-2e9j79.jpg');
} catch (e) {
print(e);
}
} catch (e) {}
});
test('PostObjecy 提交', () async {
try {
String pathname = path.joinAll(
[Directory.current.path, '..\\assets\\' 'images', 'logo.png']);
print(pathname);
String keyTime = TcyunApi.buildKeyTime();
String policy = TcyunApi.buildPolicy('ap-nanjing', 'logo.png',
'AKIDvb0B9rqfeOr44kt2ar46rO2cwzl6JwUk', keyTime);
print(policy);
// TcyunApi.postObject(
// 'test-1253954259',
// 'ap-nanjing',
@@ -51,8 +43,6 @@ main() {
// "q-signature": TcyunApi.buildSignature(
// 'KOEoR1LL5apX1lFRN4VgZB0nJgmdEbie', keyTime, policy)
// }));
} catch (e) {
print(e);
}
} catch (e) {}
});
}