diff --git a/README.md b/README.md index 563e89e..1cf226f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Flutter-PicGo: 一个用于快速上传图片并获取图片URL链接的**手机 - 七牛云 [v1.3+] - 阿里云OSS [v1.4+] - 腾讯云COS [v1.5+] +- 牛图网 [v1.6+] > 开发进度可以查看 [Projects](https://github.com/PicGo/flutter-picgo/projects),会同步更新开发进度 @@ -65,7 +66,7 @@ Flutter-PicGo: 一个用于快速上传图片并获取图片URL链接的**手机 - [Flutter-Go](https://github.com/alibaba/flutter-go) -# [License](https://github.com/hackycy/flutter-picgo/blob/master/LICENSE) +# License ``` txt MIT License diff --git a/docs/static/location.html b/docs/static/location.html new file mode 100644 index 0000000..97263e3 --- /dev/null +++ b/docs/static/location.html @@ -0,0 +1,23 @@ + + + + + + + Flutter-Picgo Release + + + + + + + \ No newline at end of file diff --git a/docs/version.json b/docs/version.json index cd58e8d..74b8f5f 100644 --- a/docs/version.json +++ b/docs/version.json @@ -1,10 +1,10 @@ { "iOS": { - "versionName": "1.6.0", - "versionCode": "14" + "versionName": "1.7.0", + "versionCode": "15" }, "Android": { - "versionName": "1.6.0", - "versionCode": "14" + "versionName": "1.7.0", + "versionCode": "15" } } \ No newline at end of file diff --git "a/docs/\350\256\276\350\256\241\346\226\207\346\241\243.md" "b/docs/\350\256\276\350\256\241\346\226\207\346\241\243.md" index a2a4629..a3d9ead 100644 --- "a/docs/\350\256\276\350\256\241\346\226\207\346\241\243.md" +++ "b/docs/\350\256\276\350\256\241\346\226\207\346\241\243.md" @@ -24,11 +24,12 @@ | 版本 | 描述 | | ---- | ------------------------------------------------ | -| 1 | pb_setting,uploaded表初始化,增加Github图床记录 | +| 1 | pb_setting,uploaded表初始化,增加Github图床记录 | | 2 | uploaded新增info列,新增SM.MS图床记录 | -| 3 | 新增Gitee图床记录 | -| 4 | 新增Qiniu图床记录 | +| 3 | 新增Gitee图床记录 | +| 4 | 新增Qiniu图床记录 | | 5 | 新增阿里云OSS图床记录 | | 6 | 新增腾讯云COS图床记录 | -| 7 | 新增牛图网图床记录 | +| 7 | 新增牛图网图床记录 | +| 8 | 新增兰空图床记录 | diff --git a/lib/api/lsky_api.dart b/lib/api/lsky_api.dart new file mode 100644 index 0000000..c327e93 --- /dev/null +++ b/lib/api/lsky_api.dart @@ -0,0 +1,27 @@ +import 'package:dio/dio.dart'; +import 'package:flutter_picgo/utils/net.dart'; +import 'package:path/path.dart' as path; + +class LskyApi { + static Future token(String email, String pwd, String host) async { + String url = path.joinAll([host, 'api/token']); + Response res = await NetUtils.getInstance().post(url, data: { + 'email': email, + 'password': pwd, + }); + return res.data; + } + + static Future upload(String token, String host, FormData data) async { + String url = path.joinAll([host, 'api/upload']); + Response res = await NetUtils.getInstance() + .post(url, data: data, options: buildCommonOptions(token)); + return res.data; + } + + static Options buildCommonOptions(String token) { + return Options(headers: { + 'token': token, + }); + } +} diff --git a/lib/model/lsky_config.dart b/lib/model/lsky_config.dart new file mode 100644 index 0000000..ab2a7a2 --- /dev/null +++ b/lib/model/lsky_config.dart @@ -0,0 +1,24 @@ +class LskyConfig { + String host; + String email; + String password; + String token; + + LskyConfig({this.host, this.email, this.password, this.token}); + + LskyConfig.fromJson(Map json) { + host = json['host']; + email = json['email']; + password = json['password']; + token = json['token']; + } + + Map toJson() { + final Map data = new Map(); + data['host'] = this.host; + data['email'] = this.email; + data['password'] = this.password; + data['token'] = this.token; + return data; + } +} diff --git a/lib/resources/pb_type_keys.dart b/lib/resources/pb_type_keys.dart index b0ee8f3..f003a53 100644 --- a/lib/resources/pb_type_keys.dart +++ b/lib/resources/pb_type_keys.dart @@ -12,4 +12,6 @@ class PBTypeKeys { static const tcyun = 'tcyun'; static const niupic = 'niupic'; + + static const lsky = 'lsky'; } diff --git a/lib/routers/router_handler.dart b/lib/routers/router_handler.dart index 7007fb8..f80bbf7 100644 --- a/lib/routers/router_handler.dart +++ b/lib/routers/router_handler.dart @@ -7,6 +7,7 @@ import 'package:flutter_picgo/views/pb_setting_page/aliyun_page/aliyun_page.dart import 'package:flutter_picgo/views/pb_setting_page/gitee_page/gitee_page.dart'; import 'package:flutter_picgo/views/pb_setting_page/gitee_page/gitee_repo_page.dart'; import 'package:flutter_picgo/views/pb_setting_page/github_page/github_repo_page.dart'; +import 'package:flutter_picgo/views/pb_setting_page/lsky_page/lsky_page.dart'; import 'package:flutter_picgo/views/pb_setting_page/niupic_page/niupic_page.dart'; import 'package:flutter_picgo/views/pb_setting_page/pb_setting_page.dart'; import 'package:flutter_picgo/views/pb_setting_page/qiniu_page/qiniu_page.dart'; @@ -126,6 +127,11 @@ var pbsettingNiupicHandler = new Handler( handlerFunc: (context, parameters) => NiupicPage(), ); +// 兰空图床设置页面 +var pbsettingLskyHandler = new Handler( + handlerFunc: (context, parameters) => LskyPage(), +); + // picgo设置页面 var picgosettingHandler = new Handler( handlerFunc: (BuildContext context, Map> params) => diff --git a/lib/routers/routers.dart b/lib/routers/routers.dart index f63e8f1..7a39a3d 100644 --- a/lib/routers/routers.dart +++ b/lib/routers/routers.dart @@ -34,6 +34,9 @@ class Routes { // --------- niupic ------------------- static const String settingPbNiupic = '/setting/pb/niupic'; // ----------------------------------- + // --------- lsky ------------------- + static const String settingPbLsky = '/setting/pb/lsky'; + // ----------------------------------- static void configureRoutes(Router router) { router.notFoundHandler = notfoundHandler; @@ -54,5 +57,6 @@ class Routes { router.define(settingPbAliyun, handler: pbsettingAliyunHandler); router.define(settingPbTcyun, handler: pbsettingTcyunHandler); router.define(settingPbNiupic, handler: pbsettingNiupicHandler); + router.define(settingPbLsky, handler: pbsettingLskyHandler); } } diff --git a/lib/utils/db_provider.dart b/lib/utils/db_provider.dart index 9979988..5f8ee74 100644 --- a/lib/utils/db_provider.dart +++ b/lib/utils/db_provider.dart @@ -34,7 +34,7 @@ class DbProvider { try { db = await openDatabase( path, - version: 7, + version: 8, onCreate: (db, version) async { // 创建pb_setting表 _initPb(db); @@ -108,6 +108,9 @@ class DbProvider { // 牛图网 await db.rawInsert( 'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.niupic}", "/setting/pb/niupic", "牛图网图床", NULL, 1)'); + // 兰空图床 + await db.rawInsert( + 'INSERT INTO $TABLE_NAME_PBSETTING(type, path, name, config, visible) VALUES("${PBTypeKeys.lsky}", "/setting/pb/lsky", "兰空图床", NULL, 1)'); // copy data // update authors set dynasty_index=(select id from dynasties where dynasties .name=authors.dynasty) where dynasty in (select name from dynasties ) if (isExists) { diff --git a/lib/utils/strategy/impl/lsky_image_upload.dart b/lib/utils/strategy/impl/lsky_image_upload.dart new file mode 100644 index 0000000..66f7fcb --- /dev/null +++ b/lib/utils/strategy/impl/lsky_image_upload.dart @@ -0,0 +1,59 @@ +import 'dart:convert'; + +import 'package:dio/dio.dart'; +import 'package:flutter_picgo/api/lsky_api.dart'; +import 'package:flutter_picgo/model/lsky_config.dart'; +import 'package:flutter_picgo/model/uploaded.dart'; +import 'package:flutter_picgo/resources/pb_type_keys.dart'; +import 'package:flutter_picgo/utils/image_upload.dart'; +import 'dart:io'; + +import 'package:flutter_picgo/utils/strategy/image_upload_strategy.dart'; +import 'package:flutter_picgo/utils/strings.dart'; + +class LskyImageUpload implements ImageUploadStrategy { + @override + Future delete(Uploaded uploaded) async { + return uploaded; + } + + @override + Future upload(File file, String renameImage) async { + String configStr = await ImageUploadUtils.getPBConfig(PBTypeKeys.lsky); + if (isBlank(configStr)) { + throw LskyError(error: '读取配置文件错误!请重试'); + } + LskyConfig config = LskyConfig.fromJson(json.decode(configStr)); + FormData formData = FormData.fromMap({ + "image": await MultipartFile.fromFile(file.path, filename: renameImage), + }); + var result = await LskyApi.upload(config.token, config.host, formData); + if (result['code'] == 200) { + var uploadedItem = + Uploaded(-1, '${result['data']['url']}', PBTypeKeys.lsky, info: ''); + await ImageUploadUtils.saveUploadedItem(uploadedItem); + return uploadedItem; + } else { + throw new LskyError(error: '${result['msg']}'); + } + } +} + +class LskyError implements Exception { + LskyError({ + this.error, + }); + + dynamic error; + + String get message => (error?.toString() ?? ''); + + @override + String toString() { + var msg = 'LskyError $message'; + if (error is Error) { + msg += '\n${error.stackTrace}'; + } + return msg; + } +} diff --git a/lib/utils/strategy/upload_strategy_factory.dart b/lib/utils/strategy/upload_strategy_factory.dart index 7a9fd0b..4368809 100644 --- a/lib/utils/strategy/upload_strategy_factory.dart +++ b/lib/utils/strategy/upload_strategy_factory.dart @@ -3,6 +3,7 @@ import 'package:flutter_picgo/utils/strategy/impl/aliyun_image_upload.dart'; import 'package:flutter_picgo/utils/strategy/impl/gitee_image_upload.dart'; import 'package:flutter_picgo/utils/strategy/impl/github_image_upload.dart'; import 'package:flutter_picgo/utils/strategy/image_upload_strategy.dart'; +import 'package:flutter_picgo/utils/strategy/impl/lsky_image_upload.dart'; import 'package:flutter_picgo/utils/strategy/impl/niupic_image_upload.dart'; import 'package:flutter_picgo/utils/strategy/impl/qiniu_image_upload.dart'; import 'package:flutter_picgo/utils/strategy/impl/smms_image_upload.dart'; @@ -39,6 +40,9 @@ class UploadStrategyFactory { } else if (type == PBTypeKeys.niupic) { /// 牛图网 cache[type] = new NiupicImageUpload(); + } else if (type == PBTypeKeys.lsky) { + /// 兰空 + cache[type] = new LskyImageUpload(); } } return cache[type]; diff --git a/lib/views/pb_setting_page/base_pb_page_state.dart b/lib/views/pb_setting_page/base_pb_page_state.dart index 34c65ff..57e2cbc 100644 --- a/lib/views/pb_setting_page/base_pb_page_state.dart +++ b/lib/views/pb_setting_page/base_pb_page_state.dart @@ -66,7 +66,7 @@ abstract class BasePBSettingPageState ), Center( child: Text( - '请先保存后再进行连接测试', + tip, textAlign: TextAlign.center, style: TextStyle(color: Colors.grey[400]), ), @@ -152,6 +152,9 @@ abstract class BasePBSettingPageState /// 表单验证 bool get validate => _formKey?.currentState?.validate() ?? true; + /// 子类可重写更改文本 + String get tip => '请先保存后再进行连接测试'; + /// 保存配置 save() async { if (isBlank(pbType)) { diff --git a/lib/views/pb_setting_page/lsky_page/lsky_page.dart b/lib/views/pb_setting_page/lsky_page/lsky_page.dart new file mode 100644 index 0000000..da941af --- /dev/null +++ b/lib/views/pb_setting_page/lsky_page/lsky_page.dart @@ -0,0 +1,93 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_picgo/api/lsky_api.dart'; +import 'package:flutter_picgo/model/config.dart'; +import 'package:flutter_picgo/model/lsky_config.dart'; +import 'package:flutter_picgo/resources/pb_type_keys.dart'; +import 'package:flutter_picgo/utils/strings.dart'; +import 'package:flutter_picgo/views/pb_setting_page/base_pb_page_state.dart'; +import 'package:toast/toast.dart'; + +class LskyPage extends StatefulWidget { + _LskyPageState createState() => _LskyPageState(); +} + +class _LskyPageState extends BasePBSettingPageState { + @override + AppBar get appbar => AppBar( + title: Text('兰空图床'), + centerTitle: true, + ); + + @override + onLoadConfig(String config) { + List configs = []; + Map map; + if (isBlank(config)) { + map = LskyConfig().toJson(); + } else { + map = LskyConfig.fromJson(json.decode(config)).toJson(); + } + map.forEach((key, value) { + Config config; + if (key == 'host') { + config = Config( + label: '设定Host', + placeholder: '例如:https://lsky.si-yee.com', + needValidate: true, + value: value); + } else if (key == 'token') { + config = Config( + label: '设定Token', + placeholder: 'Token', + needValidate: false, + value: value); + } else if (key == 'email') { + config = Config( + label: '设定邮箱', + placeholder: 'Email', + needValidate: true, + value: value); + } else if (key == 'password') { + config = Config( + label: '设定密码', + placeholder: '设定密码', + needValidate: true, + value: value); + } + config.name = key; + configs.add(config); + }); + setConfigs(configs); + } + + @override + String get tip => '点击保存会自动获取Token,如果已填写字段则不会自动生成'; + + @override + String get pbType => PBTypeKeys.lsky; + + @override + save() async { + if (isBlank(controllers['token'].text.trim())) { + // 如果Token为空,则自动获取 + String email = controllers['email'].value.text.trim(); + String pwd = controllers['password'].value.text.trim(); + String host = controllers['host'].value.text.trim(); + var result = await LskyApi.token(email, pwd, host); + if (result["code"] == 200) { + // controllers["token"].text = '${result["data"]["token"]}'; + setState(() { + configs[3].value = '${result["data"]["token"]}'; + + super.save(); + }); + } else { + Toast.show('Token获取失败,请检查配置', context); + } + } else { + return super.save(); + } + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 033fa80..6987852 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.6.0+14 +version: 1.7.0+15 environment: sdk: ">=2.7.0 <3.0.0"