Skip to content

Commit 0c6d7b7

Browse files
committed
Merge branch 'dev'
2 parents c1721ef + a1ac356 commit 0c6d7b7

File tree

14 files changed

+350
-19
lines changed

14 files changed

+350
-19
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Flutter-PicGo: 一个用于快速上传图片并获取图片URL链接的**手机
2222
- 阿里云OSS [v1.4+]
2323
- 腾讯云COS [v1.5+]
2424
- 牛图网 [v1.6+]
25+
- 兰空 [v1.7+]
26+
- 又拍云 [v1.8+]
2527

2628
> 开发进度可以查看 [Projects](https://github.com/PicGo/flutter-picgo/projects),会同步更新开发进度
2729
@@ -32,8 +34,7 @@ Flutter-PicGo: 一个用于快速上传图片并获取图片URL链接的**手机
3234
- 适配深色模式,可跟随系统或手动设置
3335
- 支持将*Flutter-PicGo*的配置导出至剪切板
3436

35-
> 基本使用配置与PicGo无异,可参考[配置文档](https://picgo.github.io/PicGo-Doc/zh/guide/config.html#%E5%9B%BE%E5%BA%8A%E5%8C%BA)
36-
> 腾讯云COS仅支持v5版配置
37+
> 注:牛图与兰空不支持远端删除,腾讯云COS仅支持v5版配置
3738
3839
# 应用截图
3940

docs/version.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"iOS": {
3-
"versionName": "1.7.0",
4-
"versionCode": "15"
3+
"versionName": "1.8.0",
4+
"versionCode": "16"
55
},
66
"Android": {
7-
"versionName": "1.7.0",
8-
"versionCode": "15"
7+
"versionName": "1.8.0",
8+
"versionCode": "16"
99
}
1010
}

docs/设计文档.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@
3232
| 6 | 新增腾讯云COS图床记录 |
3333
| 7 | 新增牛图网图床记录 |
3434
| 8 | 新增兰空图床记录 |
35+
| 9 | 新增又拍云图床记录 |
3536

lib/api/upyun_api.dart

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import 'dart:convert';
2+
import 'dart:io';
3+
4+
import 'package:crypto/crypto.dart';
5+
import 'package:dio/dio.dart';
6+
import 'package:flutter_picgo/utils/net.dart';
7+
import 'package:path/path.dart';
8+
9+
class UpyunApi {
10+
static const BASE_URL = 'http://v0.api.upyun.com';
11+
12+
static const String operatorKey = 'operatorKey';
13+
static const String passwordKey = 'passwordKey';
14+
15+
/// REST API PUT
16+
static Future putObject(
17+
File file,
18+
String operator,
19+
String password,
20+
String name,
21+
String bucket, {
22+
String path = '',
23+
}) async {
24+
String wholePath = joinAll([BASE_URL, bucket, path, name]);
25+
var bytes = file.readAsBytesSync();
26+
Response res = await NetUtils.getInstance().put(wholePath,
27+
data: Stream.fromIterable(bytes.map((e) => [e])),
28+
options: Options(
29+
headers: {
30+
Headers.contentLengthHeader: bytes.length,
31+
},
32+
contentType: 'image/${extension(name).replaceFirst('.', '')}',
33+
extra: {
34+
operatorKey: operator,
35+
passwordKey: password,
36+
}));
37+
return res.headers;
38+
}
39+
40+
/// REST API DELETE
41+
static Future deleteObject(
42+
String bucket,
43+
String operator,
44+
String password,
45+
String key,
46+
) async {
47+
String wholePath = joinAll([BASE_URL, bucket, key]);
48+
Response res = await NetUtils.getInstance().delete(wholePath,
49+
options: Options(
50+
extra: {
51+
operatorKey: operator,
52+
passwordKey: password,
53+
},
54+
));
55+
return res.headers;
56+
}
57+
58+
/// build policy
59+
static String buildPolicy(String bucket, String saveKey) {
60+
Map<String, dynamic> map = {
61+
'bucket': bucket,
62+
'save-key': saveKey,
63+
'expiration': DateTime.now().millisecondsSinceEpoch + 30 * 60 * 1000,
64+
};
65+
return base64.encode(utf8.encode(json.encode(map)));
66+
}
67+
}
68+
69+
class UpyunInterceptor extends InterceptorsWrapper {
70+
@override
71+
Future onRequest(RequestOptions options) async {
72+
if (options.path.contains(UpyunApi.BASE_URL.replaceFirst('http://', ''))) {
73+
/// 请求方式,如:GET、POST、PUT、HEAD 等
74+
String method = options.method.toUpperCase();
75+
String path = options.uri.path;
76+
String date = HttpDate.format(DateTime.now());
77+
String pwdMd5 =
78+
'${md5.convert(utf8.encode(options.extra[UpyunApi.passwordKey]))}';
79+
String operator = options.extra[UpyunApi.operatorKey];
80+
String sign = '$method&$path&$date';
81+
82+
/// 签名构造
83+
var hmacsha1 = Hmac(sha1, utf8.encode('$pwdMd5'));
84+
var auth = hmacsha1.convert(utf8.encode(sign));
85+
String realAuth = base64.encode(auth.bytes);
86+
87+
/// Add Common Header
88+
options.headers.addAll({
89+
'Date': date,
90+
'Authorization': 'UPYUN $operator:$realAuth',
91+
});
92+
}
93+
return options;
94+
}
95+
}

lib/model/upyun_config.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class UpyunConfig {
2+
String bucket;
3+
String operator;
4+
String options;
5+
String password;
6+
String path;
7+
String url;
8+
9+
UpyunConfig(
10+
{this.bucket,
11+
this.operator,
12+
this.options,
13+
this.password,
14+
this.path,
15+
this.url});
16+
17+
UpyunConfig.fromJson(Map<String, dynamic> json) {
18+
bucket = json['bucket'];
19+
operator = json['operator'];
20+
options = json['options'];
21+
password = json['password'];
22+
path = json['path'];
23+
url = json['url'];
24+
}
25+
26+
Map<String, dynamic> toJson() {
27+
final Map<String, dynamic> data = new Map<String, dynamic>();
28+
data['bucket'] = this.bucket;
29+
data['operator'] = this.operator;
30+
data['options'] = this.options;
31+
data['password'] = this.password;
32+
data['path'] = this.path;
33+
data['url'] = this.url;
34+
return data;
35+
}
36+
}

lib/resources/pb_type_keys.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ class PBTypeKeys {
1414
static const niupic = 'niupic';
1515

1616
static const lsky = 'lsky';
17+
18+
static const upyun = 'upyun';
1719
}

lib/routers/router_handler.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:flutter_picgo/views/pb_setting_page/pb_setting_page.dart';
1313
import 'package:flutter_picgo/views/pb_setting_page/qiniu_page/qiniu_page.dart';
1414
import 'package:flutter_picgo/views/pb_setting_page/smms_page/smms_page.dart';
1515
import 'package:flutter_picgo/views/pb_setting_page/tcyun_page/tcyun_page.dart';
16+
import 'package:flutter_picgo/views/pb_setting_page/upyun_page/upyun_page.dart';
1617
import 'package:flutter_picgo/views/picgo_setting_page/theme_setting_page.dart';
1718
import 'package:flutter_picgo/views/upload_page/upload_page.dart';
1819
import 'package:flutter_picgo/views/pb_setting_page/github_page/github_page.dart';
@@ -132,6 +133,11 @@ var pbsettingLskyHandler = new Handler(
132133
handlerFunc: (context, parameters) => LskyPage(),
133134
);
134135

136+
// 又拍云图床设置页面
137+
var pbsettingUpyunHandler = new Handler(
138+
handlerFunc: (context, parameters) => UpyunPage(),
139+
);
140+
135141
// picgo设置页面
136142
var picgosettingHandler = new Handler(
137143
handlerFunc: (BuildContext context, Map<String, List<String>> params) =>

lib/routers/routers.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class Routes {
3737
// --------- lsky -------------------
3838
static const String settingPbLsky = '/setting/pb/lsky';
3939
// -----------------------------------
40+
// --------- upyun -------------------
41+
static const String settingPbUpyun = '/setting/pb/upyun';
42+
// -----------------------------------
4043

4144
static void configureRoutes(Router router) {
4245
router.notFoundHandler = notfoundHandler;
@@ -58,5 +61,6 @@ class Routes {
5861
router.define(settingPbTcyun, handler: pbsettingTcyunHandler);
5962
router.define(settingPbNiupic, handler: pbsettingNiupicHandler);
6063
router.define(settingPbLsky, handler: pbsettingLskyHandler);
64+
router.define(settingPbUpyun, handler: pbsettingUpyunHandler);
6165
}
6266
}

lib/utils/db_provider.dart

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class DbProvider {
3434
try {
3535
db = await openDatabase(
3636
path,
37-
version: 8,
37+
version: 9,
3838
onCreate: (db, version) async {
3939
// 创建pb_setting表
4040
_initPb(db);
@@ -87,30 +87,42 @@ class DbProvider {
8787
config varchar(255) DEFAULT NULL,
8888
visible INTEGER DEFAULT 1
8989
)''');
90-
// github图床
90+
91+
/// github图床
9192
await db.rawInsert(
9293
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.github}", "/setting/pb/github", "Github图床", NULL, 1)');
93-
// SM.MS图床
94+
95+
/// SM.MS图床
9496
await db.rawInsert(
9597
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.smms}", "/setting/pb/smms", "SM.MS图床", NULL, 1)');
96-
// Gitee图床
98+
99+
/// Gitee图床
97100
await db.rawInsert(
98101
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.gitee}", "/setting/pb/gitee", "Gitee图床", NULL, 1)');
99-
// Qiniu图床
102+
103+
/// Qiniu图床
100104
await db.rawInsert(
101105
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.qiniu}", "/setting/pb/qiniu", "七牛图床", NULL, 1)');
102-
// 阿里云OSS
106+
107+
/// 阿里云OSS
103108
await db.rawInsert(
104109
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.aliyun}", "/setting/pb/aliyun", "阿里云OSS图床", NULL, 1)');
105-
// 腾讯云COS
110+
111+
/// 腾讯云COS
106112
await db.rawInsert(
107113
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.tcyun}", "/setting/pb/tcyun", "腾讯云COS图床", NULL, 1)');
108-
// 牛图网
114+
115+
/// 牛图网
109116
await db.rawInsert(
110117
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.niupic}", "/setting/pb/niupic", "牛图网图床", NULL, 1)');
111-
// 兰空图床
118+
119+
/// 兰空图床
112120
await db.rawInsert(
113121
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.lsky}", "/setting/pb/lsky", "兰空图床", NULL, 1)');
122+
123+
/// 又拍云图床
124+
await db.rawInsert(
125+
'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.upyun}", "/setting/pb/upyun", "又拍云图床", NULL, 1)');
114126
// copy data
115127
// update authors set dynasty_index=(select id from dynasties where dynasties .name=authors.dynasty) where dynasty in (select name from dynasties )
116128
if (isExists) {

lib/utils/net.dart

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:dio/dio.dart';
22
import 'package:flutter_picgo/api/tcyun_api.dart';
3+
import 'package:flutter_picgo/api/upyun_api.dart';
34

45
const bool inProduction = const bool.fromEnvironment("dart.vm.product");
56

@@ -10,14 +11,19 @@ class NetUtils {
1011
NetUtils._internal() {
1112
_dio = new Dio(BaseOptions(
1213
connectTimeout: 30000, receiveTimeout: 30000, sendTimeout: 30000));
14+
15+
/// Tcyun Interceptor
16+
dio.interceptors.add(TcyunInterceptor());
17+
18+
/// Upyun Interceptor
19+
dio.interceptors.add(UpyunInterceptor());
20+
21+
/// Log Interceptor
1322
if (!inProduction) {
1423
/// Log
1524
dio.interceptors
1625
.add(LogInterceptor(requestBody: true, responseBody: true));
1726
}
18-
19-
/// Tcyun Interceptor
20-
dio.interceptors.add(TcyunInterceptor());
2127
}
2228

2329
Dio get dio => _dio;

0 commit comments

Comments
 (0)