From 7ee55a3e10a019af74a3211807057bf68c0aecca Mon Sep 17 00:00:00 2001 From: liupan1890 <67817756+liupan1890@users.noreply.github.com> Date: Tue, 29 Jun 2021 20:28:45 +0800 Subject: [PATCH] v1.6.29 --- aliserver/aliyun/ApiFile.go | 387 ++++------------ aliserver/aliyun/ApiFileDown.go | 82 +--- aliserver/aliyun/ApiFileUpload.go | 91 ++-- aliserver/aliyun/ApiLink.go | 41 +- aliserver/aliyun/ApiShare.go | 200 +++++++++ aliserver/aliyun/ApiUser.go | 30 +- aliserver/data/Setting.go | 2 +- aliserver/download/downmanage.go | 4 +- aliserver/go.mod | 13 - aliserver/go.sum | 29 -- aliserver/link/linkmanage.go | 128 ++++++ aliserver/link/share115.go | 187 ++++++++ aliserver/link/shareali.go | 207 +++++++++ aliserver/localhost/Action.go | 10 + aliserver/utils/FileHelper.go | 4 +- aliserver/utils/HttpHelper.go | 17 + alixby/.flutter-plugins-dependencies | 2 +- alixby/lib/api/AliFile.dart | 12 +- alixby/lib/api/Linker.dart | 37 ++ alixby/lib/main.dart | 11 +- alixby/lib/models/PageRightFileItem.dart | 4 + alixby/lib/models/Setting.dart | 2 +- alixby/lib/pagedown/DownFileList.dart | 44 +- alixby/lib/pagedown/PageRightDown.dart | 4 +- alixby/lib/pagepan/CreatDirDialog.dart | 79 ++-- .../lib/pagepan/CreatMiaoChuanBackDialog.dart | 10 +- alixby/lib/pagepan/CreatMiaoChuanDialog.dart | 197 +++++---- alixby/lib/pagepan/DownSaveDialog.dart | 30 +- alixby/lib/pagepan/DropUploadDialog.dart | 38 +- alixby/lib/pagepan/MoveDialog.dart | 112 +++-- alixby/lib/pagepan/PageRightPan.dart | 10 +- alixby/lib/pagepan/PanFileList.dart | 8 +- alixby/lib/pagepan/PanRightTopButton.dart | 414 ++++++++++-------- alixby/lib/pagepan/RenameDialog.dart | 96 ++-- alixby/lib/pagepan/RenameMutlDialog.dart | 45 +- .../lib/pagepan/SaveMiaoChuan115Dialog.dart | 37 +- .../lib/pagepan/SaveMiaoChuanBackDialog.dart | 83 +++- .../lib/pagepan/SaveMiaoChuanTxtDialog.dart | 37 +- .../lib/pagepan/SaveMiaoChuanXbyDialog.dart | 35 +- alixby/lib/pagepan/SaveShareDialog.dart | 306 +++++++++++++ alixby/lib/pagepan/UnrarDialog.dart | 48 +- alixby/lib/pagerss/PageRightRssHelp.dart | 11 +- alixby/lib/pagerss/PageRightRssSearch.dart | 91 +++- alixby/lib/pagerss/ZhuanCunDialog.dart | 48 +- alixby/lib/states/FileState.dart | 6 +- alixby/lib/states/Global.dart | 4 +- alixby/lib/states/pageRssSearchState.dart | 11 +- alixby/lib/utils/MColors.dart | 3 + alixby/lib/utils/SpinKitRing.dart | 114 +++++ alixby/lib/utils/SpinKitRotatingCircle.dart | 65 +++ alixby/lib/utils/StringUtils.dart | 6 + alixby/lib/views/PageRightSetting.dart | 1 + alixby/pubspec.yaml | 5 +- changelog.txt | 8 + 54 files changed, 2434 insertions(+), 1072 deletions(-) create mode 100644 aliserver/aliyun/ApiShare.go delete mode 100644 aliserver/go.mod delete mode 100644 aliserver/go.sum create mode 100644 aliserver/link/share115.go create mode 100644 aliserver/link/shareali.go create mode 100644 alixby/lib/pagepan/SaveShareDialog.dart create mode 100644 alixby/lib/utils/SpinKitRing.dart create mode 100644 alixby/lib/utils/SpinKitRotatingCircle.dart diff --git a/aliserver/aliyun/ApiFile.go b/aliserver/aliyun/ApiFile.go index 7f61505..dc1df3b 100644 --- a/aliserver/aliyun/ApiFile.go +++ b/aliserver/aliyun/ApiFile.go @@ -24,47 +24,19 @@ type FileItemModel struct { P_file_icon string `json:"file_icon"` } -func ApiFileList(boxid string, parentid string, marker string) (retjsonstr string) { - defer func() { - if errr := recover(); errr != nil { - log.Println("ApiFileListError ", " error=", errr) - retjsonstr = `{"code":503,"message":"error","next_marker":"","items":[]}` - } - }() - - var apiurl = "https://api.aliyundrive.com/v2/file/list" - - var postjson = map[string]interface{}{"drive_id": boxid, - "parent_file_id": parentid, - "limit": 100, - "all": false, - "fields": "thumbnail", - "order_by": "name", - "order_direction": "ASC"} - if marker != "" { - postjson["marker"] = marker - } - b, _ := json.Marshal(postjson) - postdata := string(b) - - //"image_thumbnail_process":"image/resize,w_160/format,jpeg", - //"image_url_process":"image/resize,w_1920/format,jpeg", - //"video_thumbnail_process":"video/snapshot,t_0,f_jpg,ar_auto,w_300", - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) +func _APIHTTP(apiurl string, postdata *[]byte) (code int, bodybytes *[]byte) { + code, _, bodybytes = utils.PostHTTPBytes2(apiurl, GetAuthorization(), postdata) if code == 401 { //UserAccessToken 失效了,尝试刷新一次 ApiTokenRefresh("") //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) + code, _, bodybytes = utils.PostHTTPBytes2(apiurl, GetAuthorization(), postdata) } - if code != 200 || !gjson.Valid(body) { - return `{"code":503,"message":"error","next_marker":"","items":[]}` - } - info := gjson.Parse(body) + return code, bodybytes +} +func _FileListBuilder(builder *strings.Builder, info *gjson.Result) { next_marker := info.Get("next_marker").String() items := info.Get("items").Array() - var builder strings.Builder builder.Grow(300 * (len(items) + 1)) builder.WriteString(`{"code":0,"message":"success","next_marker":"`) builder.WriteString(next_marker) @@ -88,12 +60,11 @@ func ApiFileList(boxid string, parentid string, marker string) (retjsonstr strin if value.Get("type").String() != "folder" { file_icon = category } - + ext = value.Get("file_extension").String() if category == "others" || category == "doc" { - ext = value.Get("file_extension").String() if strings.Index(";.3gp.3iv.asf.avi.cpk.divx.dv.hdv.fli.flv.f4v.f4p.h264.i263.m2t.m2ts.mts.ts.trp.m4v.mkv.mov.mp2.mp4.mpeg.mpg.mpg2.mpg4.nsv.nut.nuv.rm.rmvb.vcd.vob.webm.wmv.mk3d.hevc.yuv.y4m.iso.", ext) > 0 { file_icon = "video" - } else if file_size < 102400 { + } else if file_size < 1024*500 { if strings.Index(";.c.cpp.java.htm.html.css.js.vue.php.aspx.shtml.asp.jsp.json.url.txt.md.markdown.xml.md5.ini.nfo.info.config.cfg.bat.sh.cmd.log.debug.go.lrc.", ext) > 0 { file_icon = "txt" } @@ -140,6 +111,42 @@ func ApiFileList(boxid string, parentid string, marker string) (retjsonstr strin } } builder.WriteString(`]}`) +} + +func ApiFileList(boxid string, parentid string, marker string) (retjsonstr string) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiFileListError ", " error=", errr) + retjsonstr = `{"code":503,"message":"error","next_marker":"","items":[]}` + } + }() + + var apiurl = "https://api.aliyundrive.com/v2/file/list" + + var postjson = map[string]interface{}{"drive_id": boxid, + "parent_file_id": parentid, + "limit": 100, + "all": false, + "fields": "thumbnail", + "order_by": "name", + "order_direction": "ASC"} + if marker != "" { + postjson["marker"] = marker + } + + //"image_thumbnail_process":"image/resize,w_160/format,jpeg", + //"image_url_process":"image/resize,w_1920/format,jpeg", + //"video_thumbnail_process":"video/snapshot,t_0,f_jpg,ar_auto,w_300", + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) + + if code != 200 || !gjson.Valid(body) { + return `{"code":503,"message":"error","next_marker":"","items":[]}` + } + info := gjson.Parse(body) + var builder strings.Builder + _FileListBuilder(&builder, &info) return builder.String() } @@ -160,20 +167,14 @@ func ApiDirList(boxid string, parentid string) (retjsonstr string) { "fields": "thumbnail", "order_by": "name", "order_direction": "ASC"} - b, _ := json.Marshal(postjson) - postdata := string(b) //"image_thumbnail_process":"image/resize,w_160/format,jpeg", //"image_url_process":"image/resize,w_1920/format,jpeg", //"video_thumbnail_process":"video/snapshot,t_0,f_jpg,ar_auto,w_300", + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } if code != 200 || !gjson.Valid(body) { return `{"code":503,"message":"error","next_marker":"","items":[]}` } @@ -251,103 +252,20 @@ func ApiFavorFileList(boxid string, marker string) (retjsonstr string) { if marker != "" { postjson["marker"] = marker } - b, _ := json.Marshal(postjson) - postdata := string(b) //"image_thumbnail_process":"image/resize,w_160/format,jpeg", //"image_url_process":"image/resize,w_1920/format,jpeg", //"video_thumbnail_process":"video/snapshot,t_0,f_jpg,ar_auto,w_300", - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return `{"code":503,"message":"error","next_marker":"","items":[]}` } info := gjson.Parse(body) - next_marker := info.Get("next_marker").String() - items := info.Get("items").Array() var builder strings.Builder - builder.Grow(300 * (len(items) + 1)) - builder.WriteString(`{"code":0,"message":"success","next_marker":"`) - builder.WriteString(next_marker) - builder.WriteString(`","items":[`) - var max = len(items) - var value = gjson.Result{} - - var file_time = time.Now() - var file_size = int64(0) - var file_icon = "" - var category = "" - var ext = "" - var status = "" - for i := 0; i < max; i++ { - value = items[i] - - file_time = value.Get("updated_at").Time() - file_size = value.Get("size").Int() - category = value.Get("category").String() - file_icon = "folder" - if value.Get("type").String() != "folder" { - file_icon = category - } - - if category == "others" || category == "doc" { - ext = strings.ToLower(value.Get("file_extension").String()) - if strings.Index(";.3gp.3iv.asf.avi.cpk.divx.dv.hdv.fli.flv.f4v.f4p.h264.i263.m2t.m2ts.mts.ts.trp.m4v.mkv.mov.mp2.mp4.mpeg.mpg.mpg2.mpg4.nsv.nut.nuv.rm.rmvb.vcd.vob.webm.wmv.mk3d.hevc.yuv.y4m.iso.", ext) > 0 { - file_icon = "video" - } else if file_size < 102400 { - if strings.Index(";.c.cpp.java.htm.html.css.js.vue.php.aspx.shtml.asp.jsp.json.url.txt.md.markdown.xml.md5.ini.nfo.info.config.cfg.bat.sh.cmd.log.debug.go.lrc.", ext) > 0 { - file_icon = "txt" - } - } - } - if strings.Index(";.zip.rar.", ext) > 0 { - file_icon = "zip" - } - if file_icon != "folder" && file_icon != "image" && file_icon != "video" && file_icon != "audio" && file_icon != "txt" && file_icon != "zip" { - file_icon = "file" - } - - status = value.Get("status").String() - if value.Get("thumbnail").Exists() && strings.Index(value.Get("thumbnail").String(), "illegal_thumbnail") > 0 { - status = "illegal" - } - - builder.WriteString(`{"key":"`) - builder.WriteString(value.Get("file_id").String()) - builder.WriteString(`","name":"`) - builder.WriteString(utils.ToJSONString(value.Get("name").String())) - builder.WriteString(`","pid":"`) - builder.WriteString(value.Get("parent_file_id").String()) - builder.WriteString(`","size":`) - builder.WriteString(strconv.FormatInt(file_size, 10)) - builder.WriteString(`,"time":`) - builder.WriteString(strconv.FormatInt(file_time.Unix(), 10)) - builder.WriteString(`,"type":"`) - builder.WriteString(value.Get("type").String()) - builder.WriteString(`","sizestr":"`) - builder.WriteString(utils.FormateSizeString(file_size)) - builder.WriteString(`","timestr":"`) - builder.WriteString(file_time.Format("2006 01-02")) - builder.WriteString(`","icon":"`) - builder.WriteString(file_icon) - builder.WriteString(`","starred":`) - builder.WriteString(strconv.FormatBool(value.Get("starred").Bool())) - builder.WriteString(`,"status":"`) - builder.WriteString(status) - - if i >= (max - 1) { - builder.WriteString(`"}`) - } else { - builder.WriteString(`"},`) - } - } - builder.WriteString(`]}`) + _FileListBuilder(&builder, &info) return builder.String() } func ApiTrashFileList(boxid string, marker string) (retjsonstr string) { @@ -370,102 +288,20 @@ func ApiTrashFileList(boxid string, marker string) (retjsonstr string) { if marker != "" { postjson["marker"] = marker } - b, _ := json.Marshal(postjson) - postdata := string(b) //"image_thumbnail_process":"image/resize,w_160/format,jpeg", //"image_url_process":"image/resize,w_1920/format,jpeg", //"video_thumbnail_process":"video/snapshot,t_0,f_jpg,ar_auto,w_300", - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return `{"code":503,"message":"error","next_marker":"","items":[]}` } info := gjson.Parse(body) - next_marker := info.Get("next_marker").String() - items := info.Get("items").Array() var builder strings.Builder - builder.Grow(300 * (len(items) + 1)) - builder.WriteString(`{"code":0,"message":"success","next_marker":"`) - builder.WriteString(next_marker) - builder.WriteString(`","items":[`) - var max = len(items) - var value = gjson.Result{} - - var file_time = time.Now() - var file_size = int64(0) - var file_icon = "" - var category = "" - var ext = "" - var status = "" - for i := 0; i < max; i++ { - value = items[i] - - file_time = value.Get("trashed_at").Time() - file_size = value.Get("size").Int() - category = value.Get("category").String() - file_icon = "folder" - if value.Get("type").String() != "folder" { - file_icon = category - } - ext = value.Get("file_extension").String() - if category == "others" || category == "doc" { - if strings.Index(";.3gp.3iv.asf.avi.cpk.divx.dv.hdv.fli.flv.f4v.f4p.h264.i263.m2t.m2ts.mts.ts.trp.m4v.mkv.mov.mp2.mp4.mpeg.mpg.mpg2.mpg4.nsv.nut.nuv.rm.rmvb.vcd.vob.webm.wmv.mk3d.hevc.yuv.y4m.iso.", ext) > 0 { - file_icon = "video" - } else if file_size < 102400 { - if strings.Index(";.c.cpp.java.htm.html.css.js.vue.php.aspx.shtml.asp.jsp.json.url.txt.md.markdown.xml.md5.ini.nfo.info.config.cfg.bat.sh.cmd.log.debug.go.lrc.", ext) > 0 { - file_icon = "txt" - } - } - } - if strings.Index(";.zip.rar.", ext) > 0 { - file_icon = "zip" - } - if file_icon != "folder" && file_icon != "image" && file_icon != "video" && file_icon != "audio" && file_icon != "txt" && file_icon != "zip" { - file_icon = "file" - } - - status = value.Get("status").String() - if value.Get("thumbnail").Exists() && strings.Index(value.Get("thumbnail").String(), "illegal_thumbnail") > 0 { - status = "illegal" - } - - builder.WriteString(`{"key":"`) - builder.WriteString(value.Get("file_id").String()) - builder.WriteString(`","name":"`) - builder.WriteString(utils.ToJSONString(value.Get("name").String())) - builder.WriteString(`","pid":"`) - builder.WriteString(value.Get("parent_file_id").String()) - builder.WriteString(`","size":`) - builder.WriteString(strconv.FormatInt(file_size, 10)) - builder.WriteString(`,"time":`) - builder.WriteString(strconv.FormatInt(file_time.Unix(), 10)) - builder.WriteString(`,"type":"`) - builder.WriteString(value.Get("type").String()) - builder.WriteString(`","sizestr":"`) - builder.WriteString(utils.FormateSizeString(file_size)) - builder.WriteString(`","timestr":"`) - builder.WriteString(file_time.Format("2006 01-02")) - builder.WriteString(`","icon":"`) - builder.WriteString(file_icon) - builder.WriteString(`","starred":`) - builder.WriteString(strconv.FormatBool(value.Get("starred").Bool())) - builder.WriteString(`,"status":"`) - builder.WriteString(status) - - if i >= (max - 1) { - builder.WriteString(`"}`) - } else { - builder.WriteString(`"},`) - } - } - builder.WriteString(`]}`) + _FileListBuilder(&builder, &info) return builder.String() } @@ -484,16 +320,9 @@ func ApiCreatForder(boxid string, parentid string, name string) (retjsonstr stri "check_name_mode": "refuse", "type": "folder"} - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 201 || !gjson.Valid(body) { //注意这里是201 return utils.ToErrorMessageJSON("创建文件夹失败") } @@ -519,16 +348,9 @@ func ApiUncompress(boxid string, file_id string, target_file_id string, password var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return utils.ToErrorMessageJSON("获取文件信息失败") } @@ -549,16 +371,9 @@ func ApiUncompress(boxid string, file_id string, target_file_id string, password if password != "" { postjson["password"] = password } - b, _ = json.Marshal(postjson) - postdata = string(b) - - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ = json.Marshal(postjson) + code, bodybytes = _APIHTTP(apiurl, &postdata) + body = string(*bodybytes) if code != 202 && code != 400 && code != 500 || !gjson.Valid(body) { //注意这里是202 return utils.ToErrorMessageJSON("创建解压缩任务失败") } @@ -600,16 +415,9 @@ func ApiUncompressCheck(boxid string, domain_id, file_id, task_id string) (retjs "task_id": task_id, } - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 && code != 400 && code != 500 || !gjson.Valid(body) { return utils.ToErrorMessageJSON("获取解压缩进度失败") } @@ -649,16 +457,9 @@ func ApiRename(boxid string, file_id string, name string) (retjsonstr string) { "name": name, "check_name_mode": "refuse"} - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return utils.ToErrorMessageJSON("重命名失败") } @@ -674,7 +475,7 @@ func ApiRenameBatch(boxid string, keylist []string, namelist []string) (retjsons defer func() { if errr := recover(); errr != nil { log.Println("ApiRenameBatchError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("count", 0, "error", len(keylist)) + retjsonstr = utils.ToSuccessJSON2("filecount", 0, "error", len(keylist)) } }() //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"9999999","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} @@ -703,7 +504,7 @@ func ApiRenameBatch(boxid string, keylist []string, namelist []string) (retjsons blist = append(blist, postdata) count := _RunBatch(blist) - return utils.ToSuccessJSON2("count", count, "error", len(keylist)-int(count)) + return utils.ToSuccessJSON2("filecount", count, "error", len(keylist)-int(count)) } func ApiFavor(boxid string, file_id string, isfavor bool) (retjsonstr string) { @@ -730,16 +531,9 @@ func ApiFavor(boxid string, file_id string, isfavor bool) (retjsonstr string) { "starred": false} } - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return utils.ToErrorMessageJSON("收藏失败") } @@ -755,7 +549,7 @@ func ApiTrashBatch(boxid string, filelist []string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiTrashBatchError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("count", 0, "error", len(filelist)) + retjsonstr = utils.ToSuccessJSON2("filecount", 0, "error", len(filelist)) } }() //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"9999999","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} @@ -784,14 +578,14 @@ func ApiTrashBatch(boxid string, filelist []string) (retjsonstr string) { blist = append(blist, postdata) count := _RunBatch(blist) - return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) + return utils.ToSuccessJSON2("filecount", count, "error", len(filelist)-int(count)) } func ApiFavorBatch(boxid string, filelist []string, isfavor bool) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiFavorBatchError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("count", 0, "error", len(filelist)) + retjsonstr = utils.ToSuccessJSON2("filecount", 0, "error", len(filelist)) } }() //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"9999999","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} @@ -825,14 +619,14 @@ func ApiFavorBatch(boxid string, filelist []string, isfavor bool) (retjsonstr st blist = append(blist, postdata) count := _RunBatch(blist) - return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) + return utils.ToSuccessJSON2("filecount", count, "error", len(filelist)-int(count)) } func ApiMoveBatch(boxid string, filelist []string, movetobox, movetoid string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiMoveBatchError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("count", 0, "error", len(filelist)) + retjsonstr = utils.ToSuccessJSON2("filecount", 0, "error", len(filelist)) } }() //https://api.aliyundrive.com/v2/batch @@ -865,14 +659,14 @@ func ApiMoveBatch(boxid string, filelist []string, movetobox, movetoid string) ( blist = append(blist, postdata) count := _RunBatch(blist) - return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) + return utils.ToSuccessJSON2("filecount", count, "error", len(filelist)-int(count)) } func ApiTrashDeleteBatch(boxid string, filelist []string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiTrashDeleteBatchError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("count", 0, "error", len(filelist)) + retjsonstr = utils.ToSuccessJSON2("filecount", 0, "error", len(filelist)) } }() //{"requests":[{"body":{"drive_id":"9999999","file_id":"60a5bb43bf60766feada4eca9d0da23a501eb7c8"},"headers":{"Content-Type":"application/json"},"id":"60a5bb43bf60766feada4eca9d0da23a501eb7c8","method":"POST","url":"/file/delete"}],"resource":"file"} @@ -900,13 +694,13 @@ func ApiTrashDeleteBatch(boxid string, filelist []string) (retjsonstr string) { blist = append(blist, postdata) count := _RunBatch(blist) - return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) + return utils.ToSuccessJSON2("filecount", count, "error", len(filelist)-int(count)) } func ApiTrashRestoreBatch(boxid string, filelist []string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiTrashRestoreBatchError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("count", 0, "error", len(filelist)) + retjsonstr = utils.ToSuccessJSON2("filecount", 0, "error", len(filelist)) } }() //{"requests":[{"body":{"drive_id":"9999999","file_id":"60a5bb4394b2ad243fb84509a576506afc890397"},"headers":{"Content-Type":"application/json"},"id":"60a5bb4394b2ad243fb84509a576506afc890397","method":"POST","url":"/recyclebin/restore"}],"resource":"file"} @@ -934,7 +728,7 @@ func ApiTrashRestoreBatch(boxid string, filelist []string) (retjsonstr string) { blist = append(blist, postdata) count := _RunBatch(blist) - return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) + return utils.ToSuccessJSON2("filecount", count, "error", len(filelist)-int(count)) } func _RunBatch(blist []string) (count int32) { @@ -963,13 +757,10 @@ func _Batch(postdata string) (count int32) { }() HTTPTOTAL <- struct{}{} //写入,如果已经写入了5次,就会在这里阻塞住 var apiurl = "https://api.aliyundrive.com/v2/batch" - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + var postdatabytes = []byte(postdata) + code, bodybytes := _APIHTTP(apiurl, &postdatabytes) + body := string(*bodybytes) + if code != 200 || !gjson.Valid(body) { return 0 } diff --git a/aliserver/aliyun/ApiFileDown.go b/aliserver/aliyun/ApiFileDown.go index 4af159f..b20e182 100644 --- a/aliserver/aliyun/ApiFileDown.go +++ b/aliserver/aliyun/ApiFileDown.go @@ -43,19 +43,12 @@ func ApiFileDownloadUrl(boxid string, file_id string, expire_sec int) (downurl s "file_id": file_id, "expire_sec": expire_sec, } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return "", 0, errors.New("401") - } + return "", 0, errors.New("401") } if code != 200 || !gjson.Valid(body) { return "", 0, errors.New("error") @@ -84,19 +77,12 @@ func ApiFileGetUrl(boxid string, file_id string, parentpath string) (urlinfo Fil var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return urlinfo, errors.New("401") - } + return urlinfo, errors.New("401") } + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return urlinfo, errors.New("error") } @@ -136,7 +122,7 @@ func ApiFileListAllForDown(boxid string, parentid string, parentpath string, isf return list, nil } } - return nil, errors.New("error") + return nil, err } //_ApiFileListAllForDown 读取一个文件夹包含的文件列表 isfull==true时遍历所有子文件夹 @@ -151,7 +137,7 @@ func _ApiFileListAllForDown(boxid string, parentid string, parentpath string, is for { flist, next, ferr := ApiFileListUrl(boxid, parentid, parentpath, marker) if ferr != nil { - return nil, errors.New("error") //有错误直接退出 + return nil, ferr //有错误直接退出 } if len(flist) > 0 { list = append(list, flist...) @@ -205,20 +191,14 @@ func ApiFileListUrl(boxid string, parentid string, parentpath string, marker str if marker != "" { postjson["marker"] = marker } - b, _ := json.Marshal(postjson) - postdata := string(b) //"image_thumbnail_process":"image/resize,w_160/format,jpeg", //"image_url_process":"image/resize,w_1920/format,jpeg", //"video_thumbnail_process":"video/snapshot,t_0,f_jpg,ar_auto,w_300", - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return nil, "", errors.New("error") } @@ -233,7 +213,7 @@ func ApiFileListUrl(boxid string, parentid string, parentpath string, marker str file_id := info.Get("file_id").String() name := utils.ClearFileName(info.Get("name").String(), true) if name == "" { - return nil, "", errors.New("error") + return nil, "", errors.New("nameerror") } if filetype == "file" { //url := info.Get("url").String() @@ -309,19 +289,10 @@ func ApiImage(boxid string, file_id string) string { var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} - b, _ := json.Marshal(postjson) - postdata := string(b) + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return utils.ToErrorMessageJSON("获取图片链接失败") - } - } if code != 200 || !gjson.Valid(body) { return utils.ToErrorMessageJSON("获取图片链接失败") } @@ -350,19 +321,10 @@ func ApiText(boxid string, file_id string) string { var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} - b, _ := json.Marshal(postjson) - postdata := string(b) + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return utils.ToErrorMessageJSON("获取文本链接失败") - } - } if code != 200 || !gjson.Valid(body) { return utils.ToErrorMessageJSON("获取文本链接失败") } @@ -412,8 +374,8 @@ func ApiText(boxid string, file_id string) string { text := string(bodybs) temp := []rune(text) length4 := len(temp) - if length4 > 1024*100 { //1万字 - text = string(temp[0:1024*100]) + "\n\n\n\n剩余" + strconv.FormatInt(int64(length4-1024*100), 10) + "字被省略.....\n\n\n\n" + if length4 > 1024*500 { //1万字 + text = string(temp[0:1024*500]) + "\n\n\n\n剩余" + strconv.FormatInt(int64(length4-1024*500), 10) + "字被省略.....\n\n\n\n" } text = strings.ReplaceAll(text, " ", " ") if text == "" { diff --git a/aliserver/aliyun/ApiFileUpload.go b/aliserver/aliyun/ApiFileUpload.go index 7de5448..ce3dc75 100644 --- a/aliserver/aliyun/ApiFileUpload.go +++ b/aliserver/aliyun/ApiFileUpload.go @@ -1,7 +1,6 @@ package aliyun import ( - "aliserver/utils" "encoding/json" "errors" "log" @@ -26,16 +25,9 @@ func UploadCreatForder(boxid string, parentid string, name string) (dirid string "check_name_mode": "refuse", "type": "folder"} - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 201 || !gjson.Valid(body) { //注意这里是201 return "", errors.New("创建文件夹失败") } @@ -71,17 +63,13 @@ func UploadCreatFile(boxid string, parentid string, name string, size int64, has "content_hash": strings.ToLower(hash), } - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 201 || !gjson.Valid(body) { //注意这里是201 + if strings.Contains(body, "file size is exceed") { + return false, "", "", "", errors.New("创建文件失败(单文件最大30GB)") + } return false, "", "", "", errors.New("创建文件失败") } info := gjson.Parse(body) @@ -124,19 +112,14 @@ func UploadFileCheckHash(boxid string, file_id string, hash string) (Same bool, var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} - b, _ := json.Marshal(postjson) - postdata := string(b) + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return false, errors.New("401") - } + return false, errors.New("401") } + if code != 200 || !gjson.Valid(body) { return false, errors.New("error") } @@ -160,19 +143,12 @@ func UploadFileDelete(boxid string, file_id string) (Delete bool, err error) { var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, _ := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) + postdata, _ := json.Marshal(postjson) + code, _ := _APIHTTP(apiurl, &postdata) if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, _ = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return false, errors.New("401") - } + return false, errors.New("401") } + if code != 204 && code != 202 { return false, errors.New("error") } @@ -197,19 +173,13 @@ func UploadFileComplete(boxid string, parentid string, name string, file_id stri "content_type": "", } - b, _ := json.Marshal(postjson) - postdata := string(b) - - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return errors.New("401") - } + return errors.New("401") } + if code != 200 || !gjson.Valid(body) { return errors.New("error") } @@ -242,19 +212,14 @@ func UploadFilePartUrl(boxid string, parentid string, name string, file_id strin }, } - b, _ := json.Marshal(postjson) - postdata := string(b) + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), postdata) if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) - if code == 401 { - return "", errors.New("401") - } + return "", errors.New("401") } + if code != 200 || !gjson.Valid(body) { return "", errors.New("error") } diff --git a/aliserver/aliyun/ApiLink.go b/aliserver/aliyun/ApiLink.go index 580cb36..f5060b5 100644 --- a/aliserver/aliyun/ApiLink.go +++ b/aliserver/aliyun/ApiLink.go @@ -13,7 +13,7 @@ type LinkFileModel struct { FileList []string `json:"FileList"` Name string `json:"Name"` Size int64 `json:"Size"` - Message string `json:"-"` + Message string `json:"Message"` } type LinkSearchModel struct { @@ -69,7 +69,7 @@ func ApiFileListAllForLink(boxid string, file_id string, name string) (link *Lin return link, nil } } - return nil, errors.New("error") + return nil, err } //_ApiFileListAllForLink 读取一个文件夹的信息(文件列表)(遍历子文件夹) @@ -85,7 +85,7 @@ func _ApiFileListAllForLink(boxid string, file_id string, name string) (link *Li for { flist, next, ferr := ApiFileListUrl(boxid, file_id, name, marker) if ferr != nil { - return nil, errors.New("error") //有错误直接退出 + return nil, ferr //有错误直接退出 } if len(flist) > 0 { list = append(list, flist...) @@ -141,7 +141,7 @@ func ApiPostLinkToServer(urldata string, postdata *[]byte) (link string) { link = "error" } }() - + //出于服务器数据安全考虑,此处已被屏蔽 return "error" } @@ -160,9 +160,38 @@ func ApiParseLinkToServer(urldata string, postdata *[]byte) (link *LinkFileModel Message: "error", Size: 0, } - + //出于服务器数据安全考虑,此处已被屏蔽 return link, "" } +func ApiShareLinkToServer(urldata string, postdata *[]byte) (link *LinkFileModel) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiShareLinkToServerError ", " error=", errr) + link.Message = "error" + } + }() + link = &LinkFileModel{ + DirList: []*LinkFileModel{}, + FileList: []string{}, + Name: "", + Message: "error", + Size: 0, + } + //出于服务器数据安全考虑,此处已被屏蔽 + return link +} + +func ApiShareLinkPwdToServer(urldata string) (pwd string) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiShareLinkPwdToServerError ", " error=", errr) + pwd = "error" + } + }() + + //出于服务器数据安全考虑,此处已被屏蔽 + return pwd +} func ApiSearchLinkToServer(urldata string, postdata *[]byte) (LinkSearchModel, error) { defer func() { @@ -174,6 +203,6 @@ func ApiSearchLinkToServer(urldata string, postdata *[]byte) (LinkSearchModel, e Count: 0, FileList: []*LinkSearchFileModel{}, } - + //出于服务器数据安全考虑,此处已被屏蔽 return result, errors.New("error") } diff --git a/aliserver/aliyun/ApiShare.go b/aliserver/aliyun/ApiShare.go new file mode 100644 index 0000000..ba78398 --- /dev/null +++ b/aliserver/aliyun/ApiShare.go @@ -0,0 +1,200 @@ +package aliyun + +import ( + "aliserver/utils" + "encoding/json" + "errors" + "log" + "strconv" + "strings" + + "github.com/tidwall/gjson" +) + +func _APIHTTPS(apiurl string, sharetoken string, postdata *[]byte) (code int, bodybytes *[]byte) { + code, _, bodybytes = utils.PostHTTPBytes2(apiurl, GetAuthorization()+"\nx-share-token: "+sharetoken, postdata) + if code == 401 { + //UserAccessToken 失效了,尝试刷新一次 + ApiTokenRefresh("") + //刷新完了,重新尝试一遍 + code, _, bodybytes = utils.PostHTTPBytes2(apiurl, GetAuthorization()+"\nx-share-token: "+sharetoken, postdata) + } + return code, bodybytes +} + +func ApiGetShareToken(sid, pwd string) (token string, err error) { + //https://api.aliyundrive.com/v2/share_link/get_share_token + //{"share_id":"BNGfGxA3NGq","share_pwd":""} + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiGetShareTokenError ", " error=", errr) + err = errors.New("error") + } + }() + var apiurl = "https://api.aliyundrive.com/v2/share_link/get_share_token" + + var postjson = map[string]interface{}{"share_id": sid, + "share_pwd": pwd, + } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) + if code != 200 || !gjson.Valid(body) { + if strings.Contains(body, "share_pwd is not valid") { + return "", errors.New("密码错误") + } + return "", errors.New("code=" + strconv.FormatInt(int64(code), 10)) + } + token = gjson.Get(body, "share_token").String() + if token != "" { + return token, nil + } else { + return "", errors.New("tokenError") + } +} + +func ApiGetShareAnonymous(sid string) (sharename, shareinfo string, fileinfos string, err error) { + //https://api.aliyundrive.com/v2/share_link/get_share_token + //{"share_id":"BNGfGxA3NGq","share_pwd":""} + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiGetShareAnonymousError ", " error=", errr) + err = errors.New("error") + } + }() + var apiurl = "https://api.aliyundrive.com/adrive/v2/share_link/get_share_by_anonymous?share_id=" + sid + + var postjson = map[string]interface{}{"share_id": sid} + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) + if code != 200 || !gjson.Valid(body) { + return "", "", "", errors.New("code=" + strconv.FormatInt(int64(code), 10)) + } + info := gjson.Parse(body) + + if info.Get("creator_id").Exists() { + var oinfo = map[string]interface{}{} + oinfo["sid"] = sid + oinfo["creator_id"] = info.Get("creator_id").String() + oinfo["expiration"] = info.Get("expiration").String() + oinfo["file_count"] = info.Get("file_count").Int() + oinfo["share_name"] = info.Get("share_name").String() + oinfo["updated_at"] = info.Get("updated_at").String() + fileinfos = info.Get("file_infos").Raw + b1, _ := json.Marshal(oinfo) + shareinfo = string(b1) + sharename = info.Get("share_name").String() + return sharename, shareinfo, fileinfos, nil + } else { + return "", "", "", errors.New("bodyError") + } +} + +func ApiSaveShareFilesBatch(shareid, boxid, parentid string, filelist []string) (retjsonstr string) { + //{"requests":[{"body":{"file_id":"60d5aa14be9f9a3019bc4655803010090140f5cc","share_id":"BNGfGxA3NGq","file_id_list":["60d5aa14be9f9a3019bc4655803010090140f5cc"],"to_parent_file_id":"60d32777623547df8c0645c080e4545f4d8b038f","to_drive_id":"8699982","auto_rename":true},"headers":{"Content-Type":"application/json"},"id":"0","method":"POST","url":"/file/copy"}],"resource":"file"} + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiSaveShareFilesBatchError ", " error=", errr) + retjsonstr = utils.ToSuccessJSON2("filecount", 0, "error", len(filelist)) + } + }() + //https://api.aliyundrive.com/v2/batch + //{"responses":[{"body":{"domain_id":"bj29","drive_id":"8699982","file_id":"60d9c4ca9ed2d8c38038475dab7f28bc8a6d7564"},"id":"0","status":201}]} + //保存文件 返回值201 + + var postdata = `{"requests":[` + var max = len(filelist) - 1 + var add = 0 + + var blist = make([]string, 0) + for i := 0; i < len(filelist); i++ { + postdata += `{"body":{"share_id":"` + shareid + `","file_id_list":["` + filelist[i] + `"],"file_id":"` + filelist[i] + `","to_drive_id":"` + boxid + `","to_parent_file_id":"` + parentid + `","auto_rename":false},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/copy"}` + + add++ + if add == 90 && i < max { + postdata += `],"resource":"file"}` + blist = append(blist, postdata) + postdata = `{"requests":[` + add = 0 + } else if i < max { + postdata += "," + } + } + postdata += `],"resource":"file"}` + + blist = append(blist, postdata) + count := _RunBatch(blist) + + return utils.ToSuccessJSON2("filecount", count, "error", len(filelist)-int(count)) +} + +//ApiGetShareListAll 读取一个文件夹包含的文件列表 isfull==true时遍历所有子文件夹 +func ApiGetShareListAll(sid, parentid, token string) (list []*FileUrlModel, err error) { + defer func() { + if errr := recover(); errr != nil { + log.Println("_ApiGetShareListAllError ", " error=", errr) + err = errors.New("error") + } + }() + var marker = "" + for { + flist, next, ferr := _ApiGetShareList(sid, token, parentid, marker) + if ferr != nil { + return nil, ferr //有错误直接退出 + } + if len(flist) > 0 { + list = append(list, flist...) + } + marker = next + if next == "" { + break + } + } + return list, nil +} + +func _ApiGetShareList(sid, token, parentid, marker string) (list []*FileUrlModel, next_marker string, err error) { + //https://api.aliyundrive.com/v2/share_link/get_share_token + //{"share_id":"BNGfGxA3NGq","parent_file_id":"root","limit":100,"image_thumbnail_process":"image/resize,w_160/format,jpeg","image_url_process":"image/resize,w_1920/format,jpeg","video_thumbnail_process":"video/snapshot,t_0,f_jpg,ar_auto,w_300","order_by":"name","order_direction":"DESC"} + + var apiurl = "https://api.aliyundrive.com/v2/file/list" + + var postjson = map[string]interface{}{"share_id": sid, + "parent_file_id": parentid, + "limit": 100, + "order_by": "name", + "order_direction": "ASC", + } + if marker != "" { + postjson["marker"] = marker + } + postdata, _ := json.Marshal(postjson) + code, bodybytes := _APIHTTPS(apiurl, token, &postdata) + body := string(*bodybytes) + if code != 200 || !gjson.Valid(body) { + return nil, "", errors.New("error") + } + infofull := gjson.Parse(body) + next_marker = infofull.Get("next_marker").String() + items := infofull.Get("items").Array() + + var max = len(items) + for i := 0; i < max; i++ { + info := items[i] + filetype := info.Get("type").String() //folder + file_id := info.Get("file_id").String() + name := utils.ClearFileName(info.Get("name").String(), true) + if name == "" { + return nil, "", errors.New("nameerror") + } + if filetype == "file" { + size := info.Get("size").Int() + list = append(list, &FileUrlModel{P_drive_id: "", P_file_id: file_id, P_file_name: name, P_size: size, IsUrl: true, IsDir: false}) + } else { + list = append(list, &FileUrlModel{P_drive_id: "", P_file_id: file_id, P_file_name: name, IsUrl: false, IsDir: true}) + } + } + + return list, next_marker, nil +} diff --git a/aliserver/aliyun/ApiUser.go b/aliserver/aliyun/ApiUser.go index 894d2f1..89a659e 100644 --- a/aliserver/aliyun/ApiUser.go +++ b/aliserver/aliyun/ApiUser.go @@ -87,13 +87,9 @@ func ApiUserInfo() (retjsonstr string) { var checktime = time.Now().Unix() - 600 //秒 - 10分钟 if _user.UserInfo.P_total_size == "" || _user.UserInfo.M_info_time < checktime { var apiurl = "https://api.aliyundrive.com/v2/databox/get_personal_info" - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), "") - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), "") - } + postdata := []byte("") + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return utils.ToSuccessJSON("info", "") @@ -142,13 +138,9 @@ func ApiUserXiangCeID() (driveId string) { } var apiurl = "https://api.aliyundrive.com/adrive/v1/user/albums_info" //{"code":"200","message":"success","data":{"driveId":"","driveName":"alibum"},"resultCode":"200"} - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), "{}") - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), "{}") - } + postdata := []byte("{}") + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return "" @@ -172,13 +164,9 @@ func ApiUserSboxID() (driveId string) { } var apiurl = "https://api.aliyundrive.com/v2/sbox/get" //{"drive_id":"","sbox_used_size":5725023,"sbox_total_size":53687091200,"recommend_vip":"svip","pin_setup":true,"locked":false,"insurance_enabled":false} - code, _, body := utils.PostHTTPString(apiurl, GetAuthorization(), "{}") - if code == 401 { - //UserAccessToken 失效了,尝试刷新一次 - ApiTokenRefresh("") - //刷新完了,重新尝试一遍 - code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), "{}") - } + postdata := []byte("{}") + code, bodybytes := _APIHTTP(apiurl, &postdata) + body := string(*bodybytes) if code != 200 || !gjson.Valid(body) { return "" diff --git a/aliserver/data/Setting.go b/aliserver/data/Setting.go index 07ef3df..3effaf5 100644 --- a/aliserver/data/Setting.go +++ b/aliserver/data/Setting.go @@ -84,7 +84,7 @@ type IConfigModel struct { } //LocalExeVer 文件版本 -const LocalExeVer = "1.6.21.0" +const LocalExeVer = "1.6.29.0" //Config 全局,serverconfig var Config = IConfigModel{ diff --git a/aliserver/download/downmanage.go b/aliserver/download/downmanage.go index e5def34..73c2191 100644 --- a/aliserver/download/downmanage.go +++ b/aliserver/download/downmanage.go @@ -240,7 +240,9 @@ func DowningStartAll() string { //DowningStopAll 停止全部 func DowningStopAll() string { - Aria2Rpc.ForcePauseAll() + if Aria2Rpc != nil { + Aria2Rpc.ForcePauseAll() + } list := []string{} DataDowningList := DataDowningReadCopy() diff --git a/aliserver/go.mod b/aliserver/go.mod deleted file mode 100644 index 0efa955..0000000 --- a/aliserver/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module aliserver - -go 1.16 - -require ( - github.com/chennqqi/chardet v0.0.0-20161007034103-ae230b79a1bb - github.com/gorilla/websocket v1.4.2 // indirect - github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect - github.com/tidwall/buntdb v1.2.3 - github.com/tidwall/gjson v1.8.0 // indirect - github.com/typa01/go-utils v0.0.0-20181126045345-a86b05b01c1e - golang.org/x/text v0.3.6 -) diff --git a/aliserver/go.sum b/aliserver/go.sum deleted file mode 100644 index a5d1b3e..0000000 --- a/aliserver/go.sum +++ /dev/null @@ -1,29 +0,0 @@ -github.com/chennqqi/chardet v0.0.0-20161007034103-ae230b79a1bb h1:yLw3LVjt/1K2P4fLtrEAaC0jJRLMEQNIIxOTeA+QK/w= -github.com/chennqqi/chardet v0.0.0-20161007034103-ae230b79a1bb/go.mod h1:4PE/z4MAxJHLMAnv4qY7kCVaCgqRjyp0KA6dZN0tpb0= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= -github.com/tidwall/btree v0.4.2 h1:aLwwJlG+InuFzdAPuBf9YCAR1LvSQ9zhC5aorFPlIPs= -github.com/tidwall/btree v0.4.2/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= -github.com/tidwall/buntdb v1.2.3 h1:AoGVe4yrhKmnEPHrPrW5EUOATHOCIk4VtFvd8xn/ZtU= -github.com/tidwall/buntdb v1.2.3/go.mod h1:+i/gBwYOHWG19wLgwMXFLkl00twh9+VWkkaOhuNQ4PA= -github.com/tidwall/gjson v1.7.4/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ= -github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/grect v0.1.1 h1:+kMEkxhoqB7rniVXzMEIA66XwU07STgINqxh+qVIndY= -github.com/tidwall/grect v0.1.1/go.mod h1:CzvbGiFbWUwiJ1JohXLb28McpyBsI00TK9Y6pDWLGRQ= -github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8= -github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= -github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8= -github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ= -github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE= -github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw= -github.com/typa01/go-utils v0.0.0-20181126045345-a86b05b01c1e h1:gLqWYNlVARpRjbaXJ3Ywp3PnHhvY8aLL/hWV3j75yJY= -github.com/typa01/go-utils v0.0.0-20181126045345-a86b05b01c1e/go.mod h1:77xqNay7XAZcNiuWNmqAKfGRZMqkXug1rKw9R0oj57w= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/aliserver/link/linkmanage.go b/aliserver/link/linkmanage.go index a13c047..a8df884 100644 --- a/aliserver/link/linkmanage.go +++ b/aliserver/link/linkmanage.go @@ -10,6 +10,7 @@ import ( "encoding/json" "errors" "log" + "net/url" "strconv" "strings" "sync" @@ -202,6 +203,133 @@ func GoLinkParse(linkstr string, password string, ispublic bool) string { return utils.ToErrorMessageJSON(link.Message) } } + +func GoLinkShare(linkstr string, password string) string { + + UserID := aliyun.GetUserID() + if UserID == "" { + return utils.ToErrorMessageJSON("还没有登录阿里云盘账号") + } + if strings.Contains(linkstr, " ") { + linkstr = linkstr[0:strings.Index(linkstr, " ")] + } + if strings.Contains(linkstr, "\t") { + linkstr = linkstr[0:strings.Index(linkstr, "\t")] + } + if strings.Contains(linkstr, "\n") { + linkstr = linkstr[0:strings.Index(linkstr, "\n")] + } + if strings.Contains(linkstr, "?") { + linkstr = linkstr[0:strings.Index(linkstr, "?")] + } + if strings.Contains(linkstr, "#") { + linkstr = linkstr[0:strings.Index(linkstr, "#")] + } + //根据link解析出文件列表 + linkfile := "" + linkstate := "success" + linksid := "" + if strings.Contains(linkstr, "115.com/s/") { + linkstr = GetLinkStr115(linkstr) + if linkstr == "" { + return utils.ToErrorMessageJSON("错误的115链接格式") + } + linksid = GetLinkStr115SID(linkstr) + if linksid == "" { + return utils.ToErrorMessageJSON("错误的115链接格式") + } + link, err := GetLinkFiles115(linksid, password) + if err != nil { + linkstate = "error" + linkfile = err.Error() + } else { + b, _ := json.Marshal(link) + linkfile = string(b) + } + } else if strings.Contains(linkstr, "aliyundrive.com/s/") { + linkstr = GetLinkStrAli(linkstr) + if linkstr == "" { + return utils.ToErrorMessageJSON("错误的阿里云盘链接格式") + } + linksid = GetLinkStrAliSID(linkstr) + if linksid == "" { + return utils.ToErrorMessageJSON("错误的阿里云盘链接格式") + } + link, err := GetLinkFilesAli(linksid, password) + if err != nil { + linkstate = "error" + linkfile = err.Error() + } else { + b, _ := json.Marshal(link) + linkfile = string(b) + } + } else { + return utils.ToErrorMessageJSON("错误的链接格式") + } + + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + zw.Write([]byte(linkfile)) + err := zw.Close() + if err != nil { + log.Println("zw.Close", err) + return utils.ToErrorMessageJSON("gzip时出错") + } + bs := buf.Bytes() + + urldata := "password=" + password + "&linkstr=" + url.QueryEscape(linkstr) + "&linkstate=" + url.QueryEscape(linkstate) + link := aliyun.ApiShareLinkToServer(urldata, &bs) + if link.Message == "" { + xbylink := linkstr + if password != "" { + xbylink = xbylink + " 密码:" + password + } + linklog := LinkLogModel{ + Link: xbylink, + LogTime: time.Now().Unix(), + IsCreater: false, + } + b, _ := json.Marshal(linklog) + data.SetLink("Link:"+linkstr, string(b)) + infostr := strconv.FormatInt(int64(link.GetFileCount()), 10) + "个文件 " + utils.FormateSizeString(link.GetTotalSize()) + return utils.ToSuccessJSON4("shareid", linksid, "xbylink", xbylink, "info", infostr, "link", link) + } else { + log.Println("sharelink", err) + return utils.ToErrorMessageJSON(link.Message) + } +} +func GoLinkShareUpload(boxid string, parentid string, shareid, linkstr string) string { + if parentid == "" { + parentid = "root" + } + + UserID := aliyun.GetUserID() + if UserID == "" { + return utils.ToErrorMessageJSON("还没有登录阿里云盘账号") + } + link := aliyun.LinkFileModel{ + DirList: []*aliyun.LinkFileModel{}, + FileList: []string{}, + Name: "", + Size: 0, + Message: "", + } + + err := json.Unmarshal([]byte(linkstr), &link) + if err != nil { + return utils.ToErrorMessageJSON("json格式化失败") + } + //当前阿里云盘只开放了文件分享 + + filelist := make([]string, len(link.FileList)) + + for i := 0; i < len(link.FileList); i++ { + var item = link.FileList[i] + filelist[i] = item[strings.LastIndex(item, "|")+1:] + } + + return aliyun.ApiSaveShareFilesBatch(shareid, boxid, parentid, filelist) +} func GoLinkUpload(boxid string, ParentID string, linkstr string) string { if ParentID == "" { ParentID = "root" diff --git a/aliserver/link/share115.go b/aliserver/link/share115.go new file mode 100644 index 0000000..36323d6 --- /dev/null +++ b/aliserver/link/share115.go @@ -0,0 +1,187 @@ +package link + +import ( + "aliserver/aliyun" + "aliserver/utils" + "errors" + "log" + "net/url" + "regexp" + "strconv" + "strings" + "sync" + + "github.com/tidwall/gjson" +) + +/* File115Model +{"fid":"1862054705834608552","uid":84855794,"cid":1861939744516982705,"n":"\u795e\u96d5.mkv","s":3284977491,"t":"1591990218","d":1,"c":0,"e":"","ico":"mkv","sha":"56E4525713236D035092A34521F6403675DFFD8C","fl":[],"u":"","iv":1,"vdi":4,"play_long":2762} +{"pid":"0","p":0,"ns":"\u795e\u96d5\u4fa0\u4fa32006"} +*/ +type File115Model struct { + //文件时有 文件夹时没有 + P_fid string `json:"fid"` + //文件夹时是文件夹ID 文件时是父文件夹ID + P_cid uint64 `json:"cid"` + //文件名 + P_name string `json:"n"` + //文件大小 + P_size int64 `json:"s"` + //文件时有 文件夹时没有 + P_sha1 string `json:"sha"` + + IsDir bool +} + +func GetLinkStr115(linkstr string) string { + reg := regexp.MustCompile(`115.com/s/([\w]+)`) + params := reg.FindStringSubmatch(linkstr) + if params == nil || len(params) < 2 { + return "" + } + sid := params[1] + return "https://115.com/s/" + sid +} +func GetLinkStr115SID(linkstr string) string { + reg := regexp.MustCompile(`115.com/s/([\w]+)`) + params := reg.FindStringSubmatch(linkstr) + if params == nil || len(params) < 2 { + return "" + } + sid := params[1] + return sid +} + +func GetLinkFiles115(linksid string, password string) (link *aliyun.LinkFileModel, err error) { + defer func() { + if errr := recover(); errr != nil { + log.Println("GetLinkFiles115Error ", " error=", errr) + err = errors.New("error") + } + }() + + link, err = ApiFileListAllFor115Link(linksid, password, "", linksid, true) + return link, err +} + +//ApiFileListAllFor115Link 读取一个文件夹的信息(文件列表)(遍历子文件夹) +func ApiFileListAllFor115Link(sid string, password string, cid string, name string, isroot bool) (link *aliyun.LinkFileModel, err error) { + for i := 0; i < 3; i++ { + link, err = _ApiFileListAllFor115Link(sid, password, cid, name, isroot) + if err == nil { + return link, nil + } else { + errmsg := err.Error() + if errmsg != "error" { + return nil, err + } + } + } + return nil, err +} + +//_ApiFileListAllFor115Link 读取一个文件夹的信息(文件列表)(遍历子文件夹) +func _ApiFileListAllFor115Link(sid string, password string, cid string, name string, isroot bool) (link *aliyun.LinkFileModel, err error) { + + defer func() { + if errr := recover(); errr != nil { + log.Println("_ApiFileListAllFor115LinkError ", " error=", errr) + err = errors.New("error") + } + }() + + link = &aliyun.LinkFileModel{ + DirList: []*aliyun.LinkFileModel{}, + FileList: []string{}, + Name: name, + Message: "", + Size: 0, + } + var list = []*File115Model{} + for i := 0; i < 10; i++ { + + var snapurl = "http://webapi.115.com/share/snap?share_code=" + sid + "&offset=" + strconv.FormatInt(int64(i*1150), 10) + "&limit=1150&receive_code=" + password + "&cid=" + cid + var header = "Accept: application/json, text/javascript, */*; q=0.01\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36\n" + header += "Origin: http://115.com\nReferer: http://115.com/s/" + sid + "\nCookie: UM_distinctid=17a128ef7dc12f-080ccb4644bb72-45410429-18bb10-17a128ef7dd18e; acw_tc=784e2ca816247924164328480e337b502062e834f980928973a048a6ca27fe" + + code, _, body := utils.GetHTTPString(snapurl, header) + if code != 200 || !gjson.Valid(body) { + return nil, errors.New("code=" + strconv.FormatInt(int64(code), 10)) + } + if gjson.Get(body, "state").Bool() == false { + errmsg := gjson.Get(body, "error").String() + if errmsg == "请输入访问码" && i == 0 && isroot { + //第一次,尝试联网读取 + urldata := "&linkstr=" + url.QueryEscape("https://115.com/s/"+sid) + password2 := aliyun.ApiShareLinkPwdToServer(urldata) + if password2 != "error" { + password = password2 + return _ApiFileListAllFor115Link(sid, password, cid, name, false) //重新开始 + } + } + return nil, errors.New(errmsg) + } + + if i == 0 && isroot { + sinfo := gjson.Get(body, "data.shareinfo") + link.Message = sinfo.Raw + link.Name = gjson.Get(sinfo.Raw, "share_title").String() + } + + count := gjson.Get(body, "data.count").Int() + items := gjson.Get(body, "data.list").Array() + + var max = len(items) + for i := 0; i < max; i++ { + info := items[i] + P_fid := info.Get("fid").String() //file + P_cid := info.Get("cid").Uint() + P_name := utils.ClearFileName(info.Get("n").String(), true) + if P_name == "" { + return nil, errors.New("nameerror") + } + if P_fid != "" { + P_size := info.Get("s").Int() + P_sha1 := info.Get("sha").String() //E27EB7D983E212CDDF9149094E31E40CC47417D6 + + list = append(list, &File115Model{P_fid: P_fid, P_cid: P_cid, P_name: P_name, P_sha1: P_sha1, P_size: P_size, IsDir: false}) + } else { + list = append(list, &File115Model{P_fid: P_fid, P_cid: P_cid, P_name: P_name, P_sha1: "", IsDir: true}) + } + } + if int64(len(list)) >= count { + break + } + } + + var wg sync.WaitGroup + var lock sync.Mutex + errnum := 0 + var max = len(list) + for i := 0; i < max; i++ { + var item = list[i] + if item.IsDir { + wg.Add(1) + go func(item *File115Model) { + dir, derr := ApiFileListAllFor115Link(sid, password, strconv.FormatUint(item.P_cid, 10), item.P_name, false) + //注意这里,如果子文件夹遍历时出错了,直接退出,确保要么全部成功,要么全部失败,不丢失 + if derr != nil { + errnum++ + } else { + lock.Lock() + link.DirList = append(link.DirList, dir) + lock.Unlock() + } + defer wg.Done() + }(item) + } else { + link.Size += item.P_size + link.FileList = append(link.FileList, strings.ReplaceAll(item.P_name, "|", "|")+"|"+strconv.FormatInt(item.P_size, 10)+"|"+item.P_sha1) + } + } + wg.Wait() + if errnum > 0 { + return nil, errors.New("列出文件信息时出错") + } + return link, nil +} diff --git a/aliserver/link/shareali.go b/aliserver/link/shareali.go new file mode 100644 index 0000000..c209ade --- /dev/null +++ b/aliserver/link/shareali.go @@ -0,0 +1,207 @@ +package link + +import ( + "aliserver/aliyun" + "aliserver/utils" + "errors" + "log" + "net/url" + "regexp" + "strconv" + "strings" + "sync" + + "github.com/tidwall/gjson" +) + +type FileAliModel struct { + //文件时有 文件夹时没有 + P_fid string `json:"fid"` + //文件夹时是文件夹ID 文件时是父文件夹ID + P_cid uint64 `json:"cid"` + //文件名 + P_name string `json:"n"` + //文件大小 + P_size int64 `json:"s"` + //文件时有 文件夹时没有 + P_sha1 string `json:"sha"` + + IsDir bool +} + +func GetLinkStrAli(linkstr string) string { + //https://www.aliyundrive.com/s/FGtXkA5SVZM + reg := regexp.MustCompile(`aliyundrive.com/s/([\w]+)`) + params := reg.FindStringSubmatch(linkstr) + if params == nil || len(params) < 2 { + return "" + } + sid := params[1] + return "https://www.aliyundrive.com/s/" + sid +} +func GetLinkStrAliSID(linkstr string) string { + reg := regexp.MustCompile(`aliyundrive.com/s/([\w]+)`) + params := reg.FindStringSubmatch(linkstr) + if params == nil || len(params) < 2 { + return "" + } + sid := params[1] + return sid +} + +func GetLinkFilesAli(linksid string, password string) (link *aliyun.LinkFileModel, err error) { + defer func() { + if errr := recover(); errr != nil { + log.Println("GetLinkFilesAliError ", " error=", errr) + err = errors.New("error") + } + }() + + sharename, shareinfo, fileinfos, err := aliyun.ApiGetShareAnonymous(linksid) + if err != nil { + return nil, err + } + + token, err := aliyun.ApiGetShareToken(linksid, password) + if err != nil { + errmsg := err.Error() + if errmsg == "密码错误" { + //尝试联网读取 + urldata := "&linkstr=" + url.QueryEscape("https://www.aliyundrive.com/s/"+linksid) + password2 := aliyun.ApiShareLinkPwdToServer(urldata) + if password2 != "error" { + password = password2 + token, err = aliyun.ApiGetShareToken(linksid, password) + } + } + if err != nil { + err2 := errors.New("error") + link, err2 = _ApiFileListAllForAliLink2(linksid, shareinfo, fileinfos) //文件数量<3时尝试绕过密码 + if err2 != nil { + return nil, err + } + } + } + + link, err = ApiFileListAllForAliLink(linksid, token, "root", linksid) + if err != nil { + return nil, err + } + link.Name = sharename + link.Message = shareinfo + return link, err + +} + +//ApiFileListAllForAliLink 读取一个文件夹的信息(文件列表)(遍历子文件夹) +func ApiFileListAllForAliLink(sid string, token string, parentid string, name string) (link *aliyun.LinkFileModel, err error) { + for i := 0; i < 3; i++ { + link, err = _ApiFileListAllForAliLink(sid, token, parentid, name) + if err == nil { + return link, nil + } else { + errmsg := err.Error() + if errmsg != "error" { + return nil, err + } + } + } + return nil, err +} + +//_ApiFileListAllForAliLink 读取一个文件夹的信息(文件列表)(遍历子文件夹) +func _ApiFileListAllForAliLink(sid string, token string, parentid string, name string) (link *aliyun.LinkFileModel, err error) { + + defer func() { + if errr := recover(); errr != nil { + log.Println("_ApiFileListAllForAliLinkError ", " error=", errr) + err = errors.New("error") + } + }() + + link = &aliyun.LinkFileModel{ + DirList: []*aliyun.LinkFileModel{}, + FileList: []string{}, + Name: name, + Message: "", + Size: 0, + } + list, err := aliyun.ApiGetShareListAll(sid, parentid, token) + if err != nil { + return nil, err + } + + var wg sync.WaitGroup + var lock sync.Mutex + errnum := 0 + var max = len(list) + for i := 0; i < max; i++ { + var item = list[i] + if item.IsDir { + wg.Add(1) + go func(item *aliyun.FileUrlModel) { + dir, derr := ApiFileListAllForAliLink(sid, token, item.P_file_id, item.P_file_name) + //注意这里,如果子文件夹遍历时出错了,直接退出,确保要么全部成功,要么全部失败,不丢失 + if derr != nil { + errnum++ + } else { + lock.Lock() + link.DirList = append(link.DirList, dir) + lock.Unlock() + } + defer wg.Done() + }(item) + } else { + link.Size += item.P_size + link.FileList = append(link.FileList, strings.ReplaceAll(item.P_file_name, "|", "|")+"|"+strconv.FormatInt(item.P_size, 10)+"|"+item.P_file_id) + } + } + wg.Wait() + if errnum > 0 { + return nil, errors.New("列出文件信息时出错") + } + return link, nil +} + +func _ApiFileListAllForAliLink2(sid, shareinfo, fileinfos string) (link *aliyun.LinkFileModel, err error) { + defer func() { + if errr := recover(); errr != nil { + log.Println("_ApiFileListAllForAliLinkError ", " error=", errr) + err = errors.New("error") + } + }() + + info := gjson.Parse(shareinfo) + count := info.Get("file_count").Int() + + files := gjson.Parse(fileinfos).Array() + if count == int64(len(files)) { + //文件数量<3 + link = &aliyun.LinkFileModel{ + DirList: []*aliyun.LinkFileModel{}, + FileList: []string{}, + Name: sid, + Message: "", + Size: 0, + } + var max = len(files) + for i := 0; i < max; i++ { + info := files[i] + filetype := info.Get("type").String() //folder + file_id := info.Get("file_id").String() + name := utils.ClearFileName(info.Get("name").String(), true) + if name == "" { + return nil, errors.New("nameerror") + } + if filetype == "file" { + size := info.Get("size").Int() + link.Size += size + link.FileList = append(link.FileList, strings.ReplaceAll(name, "|", "|")+"|"+strconv.FormatInt(size, 10)+"|"+file_id) + } else { + return nil, errors.New("direrror") + } + } + return link, nil + } + return nil, errors.New("error") +} diff --git a/aliserver/localhost/Action.go b/aliserver/localhost/Action.go index 5bcd55f..832cf5b 100644 --- a/aliserver/localhost/Action.go +++ b/aliserver/localhost/Action.go @@ -366,6 +366,16 @@ func HookAction(url string, postdata string) (ishook bool, hookresult string) { ispublic := gjson.Get(postdata, "ispublic").Bool() return true, link.GoLinkParse(linkstr, password, ispublic) + case "GoLinkShare": + linkstr := gjson.Get(postdata, "link").String() + password := gjson.Get(postdata, "password").String() + return true, link.GoLinkShare(linkstr, password) + case "GoLinkShareUpload": + shareid := gjson.Get(postdata, "shareid").String() + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + parentid := gjson.Get(postdata, "parentid").String() + linkstr := gjson.Get(postdata, "linkstr").String() + return true, link.GoLinkShareUpload(boxid, parentid, shareid, linkstr) case "GoLinkUpload": boxid := GetBoxID(gjson.Get(postdata, "box").String()) parentid := gjson.Get(postdata, "parentid").String() diff --git a/aliserver/utils/FileHelper.go b/aliserver/utils/FileHelper.go index f01e025..d9f6efb 100644 --- a/aliserver/utils/FileHelper.go +++ b/aliserver/utils/FileHelper.go @@ -77,13 +77,13 @@ func FormateSizeString(size int64) string { case size < 1024*1024: // KB s = size / 1024 if s > 99 { - return strconv.FormatInt(s, 10) + "kb" + return strconv.FormatInt(s, 10) + "KB" } return fmt.Sprintf("%.1fKB", float64(size)/float64(1024)) case size < 1024*1024*1024: // MB s = size / 1024 / 1024 if s > 99 { - return strconv.FormatInt(s, 10) + "mb" + return strconv.FormatInt(s, 10) + "MB" } return fmt.Sprintf("%.1fMB", float64(size)/float64(1024*1024)) case size < 1024*1024*1024*1024: //GB diff --git a/aliserver/utils/HttpHelper.go b/aliserver/utils/HttpHelper.go index ce28336..563db27 100644 --- a/aliserver/utils/HttpHelper.go +++ b/aliserver/utils/HttpHelper.go @@ -229,6 +229,23 @@ func PostHTTPBytes(url string, header string, postdata *[]byte) (code int, head } return code, head, body } +func PostHTTPBytes2(url string, header string, postdata *[]byte) (code int, head string, bodybytes *[]byte) { + + for i := 0; i < 2; i++ { + if i > 0 { + time.Sleep(time.Duration(400 * time.Millisecond)) + } + bodybytes = nil + code, head, bodybytes = Raw("POST", url, header, bytes.NewReader(*postdata)) + if code == 200 || code == 206 { + return 200, head, bodybytes + } + if code >= 200 && code <= 400 { + return code, head, bodybytes + } + } + return code, head, bodybytes +} //NetErrorMessage 格式化网络错误信息 func NetErrorMessage(msg string) string { diff --git a/alixby/.flutter-plugins-dependencies b/alixby/.flutter-plugins-dependencies index 92301db..c93556c 100644 --- a/alixby/.flutter-plugins-dependencies +++ b/alixby/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"path_provider","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"url_launcher","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-6.0.3\\\\","dependencies":[]}],"android":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"path_provider","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"url_launcher","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-6.0.3\\\\","dependencies":[]}],"macos":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"path_provider_macos","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_macos-2.0.0\\\\","dependencies":[]},{"name":"url_launcher_macos","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_macos-2.0.0\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.0.0\\\\","dependencies":[]},{"name":"url_launcher_linux","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_linux-2.0.0\\\\","dependencies":[]}],"windows":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"file_selector_windows","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\file_selector_windows-0.0.2\\\\","dependencies":[]},{"name":"path_provider_windows","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.0.1\\\\","dependencies":[]},{"name":"url_launcher_windows","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_windows-2.0.0\\\\","dependencies":[]}],"web":[{"name":"file_selector_web","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\file_selector_web-0.8.1\\\\","dependencies":[]},{"name":"url_launcher_web","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_web-2.0.0\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"dropfiles_window","dependencies":[]},{"name":"file_selector","dependencies":["file_selector_web"]},{"name":"file_selector_web","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows","url_launcher_web"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-06-21 20:09:24.343650","version":"2.2.1"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"path_provider","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"url_launcher","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-6.0.3\\\\","dependencies":[]}],"android":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"path_provider","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider-2.0.1\\\\","dependencies":[]},{"name":"url_launcher","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher-6.0.3\\\\","dependencies":[]}],"macos":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"path_provider_macos","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_macos-2.0.0\\\\","dependencies":[]},{"name":"url_launcher_macos","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_macos-2.0.0\\\\","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.0.0\\\\","dependencies":[]},{"name":"url_launcher_linux","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_linux-2.0.0\\\\","dependencies":[]}],"windows":[{"name":"dropfiles_window","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\dropfiles_window-0.0.2\\\\","dependencies":[]},{"name":"file_selector_windows","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\file_selector_windows-0.0.2\\\\","dependencies":[]},{"name":"path_provider_windows","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.0.1\\\\","dependencies":[]},{"name":"url_launcher_windows","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_windows-2.0.0\\\\","dependencies":[]}],"web":[{"name":"file_selector_web","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\file_selector_web-0.8.1\\\\","dependencies":[]},{"name":"url_launcher_web","path":"D:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.flutter-io.cn\\\\url_launcher_web-2.0.0\\\\","dependencies":[]}]},"dependencyGraph":[{"name":"dropfiles_window","dependencies":[]},{"name":"file_selector","dependencies":["file_selector_web"]},{"name":"file_selector_web","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows","url_launcher_web"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-06-29 19:23:12.505223","version":"2.2.1"} \ No newline at end of file diff --git a/alixby/lib/api/AliFile.dart b/alixby/lib/api/AliFile.dart index 959b610..63d4f4e 100644 --- a/alixby/lib/api/AliFile.dart +++ b/alixby/lib/api/AliFile.dart @@ -142,7 +142,7 @@ class AliFile { var result = await HttpHelper.postToServer( "ApiRenameBatch", jsonEncode({'box': box, 'keylist': keylist, "namelist": namelist})); if (result["code"] == 0) { - return result["count"]; + return result["filecount"]; } } catch (e) { print('apiRenameBatch ' + e.toString()); @@ -184,7 +184,7 @@ class AliFile { try { var result = await HttpHelper.postToServer("ApiTrashBatch", jsonEncode({'box': box, 'filelist': filelist})); if (result["code"] == 0) { - return result["count"]; + return result["filecount"]; } } catch (e) { print('apiTrashBatch ' + e.toString()); @@ -197,7 +197,7 @@ class AliFile { var result = await HttpHelper.postToServer( "ApiMoveBatch", jsonEncode({'box': box, 'filelist': filelist, "movetobox": movetobox, "movetoid": movetoid})); if (result["code"] == 0) { - return result["count"]; + return result["filecount"]; } } catch (e) { print('apiMoveBatch ' + e.toString()); @@ -225,7 +225,7 @@ class AliFile { try { var result = await HttpHelper.postToServer("ApiTrashDeleteBatch", jsonEncode({'box': box, 'filelist': filelist})); if (result["code"] == 0) { - return result["count"]; + return result["filecount"]; } } catch (e) { print('apiTrashDeleteBatch ' + e.toString()); @@ -238,7 +238,7 @@ class AliFile { var result = await HttpHelper.postToServer("ApiTrashRestoreBatch", jsonEncode({'box': box, 'filelist': filelist})); if (result["code"] == 0) { - return result["count"]; + return result["filecount"]; } } catch (e) { print('apiTrashRestoreBatch ' + e.toString()); @@ -251,7 +251,7 @@ class AliFile { var result = await HttpHelper.postToServer( "ApiFavorBatch", jsonEncode({'box': box, "isfavor": isfavor, 'filelist': filelist})); if (result["code"] == 0) { - return result["count"]; + return result["filecount"]; } } catch (e) { print('apiFavorBatch ' + e.toString()); diff --git a/alixby/lib/api/Linker.dart b/alixby/lib/api/Linker.dart index ae7fe2f..6c65c34 100644 --- a/alixby/lib/api/Linker.dart +++ b/alixby/lib/api/Linker.dart @@ -25,6 +25,7 @@ class LinkFileModel { int size = 0; int leve = 0; bool isdir = false; + String shareid = ""; //分享链接 特殊 List children = []; String fulljson = ""; @@ -153,6 +154,42 @@ class Linker { return parse; } + static Future goLinkShare(String link, String password, bool ispublic) async { + LinkFileModel parse = LinkFileModel.newFileItem("", 0, "error", true); + try { + var result = await HttpHelper.postToServer( + "GoLinkShare", jsonEncode({"link": link, "password": password, "ispublic": ispublic})); + if (result["code"] == 0) { + //正确返回文件列表 + parse = LinkFileModel.fromJson(result["link"]); + parse.fulljson = json.encode(result["link"]); + parse.name = result["info"] + " " + parse.name; + if (link.toLowerCase().contains("aliyundrive.com/s/")) { + parse.shareid = result["shareid"]; + } + } else if (result["code"] == 503) { + parse.hash = result["message"]; + } + } catch (e) { + print('goLinkParse ' + e.toString()); + } + return parse; + } + + static Future goLinkShareUpload(String box, String parentid, String shareid, String linkstr) async { + try { + var result = await HttpHelper.postToServer( + "GoLinkShareUpload", jsonEncode({'box': box, "parentid": parentid, "shareid": shareid, "linkstr": linkstr})); + if (result["code"] == 0) { + //正确返回文件列表 + return result["filecount"]; + } + } catch (e) { + print('goLinkUpload ' + e.toString()); + } + return 0; + } + static Future goLinkUpload(String box, String parentid, String linkstr) async { try { var result = await HttpHelper.postToServer( diff --git a/alixby/lib/main.dart b/alixby/lib/main.dart index 39d1f01..83bfd3f 100644 --- a/alixby/lib/main.dart +++ b/alixby/lib/main.dart @@ -41,7 +41,7 @@ void main() async { ), )); //980 - Future.delayed(Duration(milliseconds: 200), () { + Future.delayed(Duration(milliseconds: 300), () { GoServer.connServer(); }); @@ -58,7 +58,7 @@ void main() async { if (upload != null) { BotToast.remove(upload!, "upload"); } - Future.delayed(Duration(milliseconds: 100), () { + Future.delayed(Duration(milliseconds: 200), () { var key = UniqueKey(); upload = key; BotToast.showEnhancedWidget( @@ -171,9 +171,14 @@ class MyApp extends StatelessWidget { } } -class MyHomePage extends StatelessWidget { +class MyHomePage extends StatefulWidget { MyHomePage({required Key key}) : super(key: key); + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { @override Widget build(BuildContext context) { var screenWidth = MediaQuery.of(context).size.width; diff --git a/alixby/lib/models/PageRightFileItem.dart b/alixby/lib/models/PageRightFileItem.dart index 06a4f0f..da5554a 100644 --- a/alixby/lib/models/PageRightFileItem.dart +++ b/alixby/lib/models/PageRightFileItem.dart @@ -8,6 +8,8 @@ class PageRightFileItem { PageRightFileItem(); static PageRightFileItem newPageRightFileItem(String box, String key, Icon icon, String title, int fileSize, DateTime fileTime, bool isFavor, bool isDir, String filetype) { + var ind = title.lastIndexOf("."); + var ext = ind > 0 ? title.substring(ind + 1).toLowerCase() : ""; return PageRightFileItem() ..box = box ..key = key @@ -18,6 +20,7 @@ class PageRightFileItem { ..filetimestr = "${fileTime.year.toString()}\n${fileTime.month.toString()}-${fileTime.day.toString()}" ..title = title ..filetype = filetype + ..fileext = ext ..isFavor = isFavor ..isDir = isDir; } @@ -34,6 +37,7 @@ class PageRightFileItem { bool isFavor = false; bool isDir = false; String filetype = "file"; + String fileext = ""; /* factory PageRightFileItem.fromJson(Map json) { return PageRightFileItem() diff --git a/alixby/lib/models/Setting.dart b/alixby/lib/models/Setting.dart index 8a3b501..86b97b2 100644 --- a/alixby/lib/models/Setting.dart +++ b/alixby/lib/models/Setting.dart @@ -22,7 +22,7 @@ class Setting { String ver = ""; String serverVer = ""; // ignore: non_constant_identifier_names - static String UIVER = "1.6.21.0"; + static String UIVER = "1.6.29.0"; factory Setting.fromJson(Map json) { return Setting() diff --git a/alixby/lib/pagedown/DownFileList.dart b/alixby/lib/pagedown/DownFileList.dart index 864ad05..20cef31 100644 --- a/alixby/lib/pagedown/DownFileList.dart +++ b/alixby/lib/pagedown/DownFileList.dart @@ -2,9 +2,10 @@ import 'package:alixby/api/Downloader.dart'; import 'package:alixby/api/Uploader.dart'; import 'package:alixby/states/Global.dart'; import 'package:alixby/states/pageDownState.dart'; +import 'package:alixby/utils/StringUtils.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/rendering.dart'; -import 'package:gradient_widgets/gradient_widgets.dart'; +import 'package:percent_indicator/percent_indicator.dart'; import 'package:hovering/hovering.dart'; import 'package:provider/provider.dart'; import 'package:alixby/utils/MColors.dart'; @@ -71,6 +72,12 @@ class _DownFileListState extends State { SizedBox uploadBox = SizedBox(width: 40, height: 40, child: Icon(MIcons.upload, color: MColors.iconDown)); SizedBox uploadBoxed = SizedBox(width: 40, height: 40, child: Icon(MIcons.upload, color: MColors.iconSelected)); + static LinearGradient coralCandyGradient = + buildGradient(Alignment.topLeft, Alignment.bottomRight, const [Color(0xffFFF0D1), Color(0xffFFB8C6)]); + static LinearGradient buildGradient(AlignmentGeometry begin, AlignmentGeometry end, List colors) => + LinearGradient(begin: begin, end: end, colors: colors); + static Color probg = Color(0xfff0f0f1); + static onTapFile(String key) { Global.pageDownState.pageSelectFile(key); } @@ -154,7 +161,8 @@ class _DownFileListState extends State { Expanded( child: Tooltip( message: item.path, - child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), + child: Text(StringUtils.joinChar(item.title), + softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), ), ), Container( @@ -176,12 +184,14 @@ class _DownFileListState extends State { alignment: Alignment.center, child: Column(children: [ Padding(padding: EdgeInsets.only(top: 20)), - SizedBox( - height: 3, - child: GradientProgressIndicator( - gradient: Gradients.coralCandyGradient, - value: item.downProgress / 100, - )), + LinearPercentIndicator( + key: Key("prd_hcr_tp_" + item.key), + width: 90.0, + lineHeight: 3.0, + percent: item.downProgress / 100, + linearGradient: coralCandyGradient, + backgroundColor: probg, + ), Padding(padding: EdgeInsets.only(top: 4)), Text(item.lastTime, style: @@ -207,10 +217,10 @@ class _DownFileListState extends State { left: 0, top: 39, child: SizedBox( - width: 210.0, + width: 220.0, height: 20.0, child: Container( - width: 210, + width: 220, child: Text( item.failedMessage, overflow: TextOverflow.clip, @@ -239,7 +249,8 @@ class _DownFileListState extends State { Expanded( child: Tooltip( message: item.path, - child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), + child: Text(StringUtils.joinChar(item.title), + softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), ), ), Container( @@ -278,10 +289,10 @@ class _DownFileListState extends State { left: 0, top: 39, child: SizedBox( - width: 210.0, + width: 220.0, height: 20.0, child: Container( - width: 210, + width: 220, child: Text( item.failedMessage, overflow: TextOverflow.clip, @@ -318,7 +329,8 @@ class _DownFileListState extends State { Expanded( child: Tooltip( message: item.path, - child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), + child: Text(StringUtils.joinChar(item.title), + softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), ), ), Container( @@ -349,10 +361,10 @@ class _DownFileListState extends State { left: 0, top: 39, child: SizedBox( - width: 210.0, + width: 220.0, height: 20.0, child: Container( - width: 210, + width: 220, child: Text( item.failedMessage, overflow: TextOverflow.clip, diff --git a/alixby/lib/pagedown/PageRightDown.dart b/alixby/lib/pagedown/PageRightDown.dart index fbd5708..14e6b16 100644 --- a/alixby/lib/pagedown/PageRightDown.dart +++ b/alixby/lib/pagedown/PageRightDown.dart @@ -106,11 +106,11 @@ class _PageRightDownState extends State with AutomaticKeepAliveCl icon: Icon(MIcons.pause, size: 16), label: Text('全部暂停'), onPressed: () => onTapBtn('stop')), Padding(padding: EdgeInsets.only(left: 12)), OutlinedButton.icon( - icon: Icon(MIcons.delete, size: 16), label: Text('全部删除'), onPressed: () => onTapBtn('delete')), + icon: Icon(MIcons.delete, size: 16), label: Text('全部清除'), onPressed: () => onTapBtn('delete')), ]) : Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ OutlinedButton.icon( - icon: Icon(MIcons.delete, size: 16), label: Text('全部删除'), onPressed: () => onTapBtn('delete')), + icon: Icon(MIcons.delete, size: 16), label: Text('全部清除'), onPressed: () => onTapBtn('delete')), ])), Container(height: 1, width: double.infinity, color: MColors.pageRightBorderColor), Container( diff --git a/alixby/lib/pagepan/CreatDirDialog.dart b/alixby/lib/pagepan/CreatDirDialog.dart index 5adc0bf..53c52a5 100644 --- a/alixby/lib/pagepan/CreatDirDialog.dart +++ b/alixby/lib/pagepan/CreatDirDialog.dart @@ -1,8 +1,9 @@ import 'package:alixby/api/AliFile.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -10,30 +11,17 @@ import 'package:provider/provider.dart'; import 'package:alixby/states/SettingState.dart'; // ignore: must_be_immutable -class CreatDirDialog extends StatelessWidget { - CreatDirDialog({Key? key, required this.box}) : super(key: key); +class CreatDirDialog extends StatefulWidget { + CreatDirDialog({Key? key, required this.box, required this.parentid}) : super(key: key); String box = ""; - final TextEditingController controller = TextEditingController(); + String parentid = ""; - void onSubmitted(BuildContext context) { - String dirname = controller.text; - dirname = dirname.replaceAll('"', '').trim(); + @override + _CreatDirDialogState createState() => _CreatDirDialogState(); +} - var fcHide = Loading.showLoading(); - var parentid = Global.getFileState(box).pageRightDirKey; - AliFile.apiCreatForder(box, parentid, dirname).then((value) { - fcHide(); - if (value == "success") { - Future.delayed(Duration(milliseconds: 200), () { - Global.getTreeState(box).pageRefreshNode(); - }); - BotToast.showText(text: "创建成功"); - Navigator.of(context).pop('ok'); - } else { - BotToast.showText(text: "创建失败请重试"); - } - }); - } +class _CreatDirDialogState extends State { + final TextEditingController controller = TextEditingController(); @override Widget build(BuildContext context) { @@ -90,7 +78,7 @@ class CreatDirDialog extends StatelessWidget { helperText: "文件夹名不要有特殊字符:<>!:*?\\/.'\"", helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: MColors.inputBorderHover, @@ -104,19 +92,48 @@ class CreatDirDialog extends StatelessWidget { ), ), ), - onSubmitted: (val) { - onSubmitted(context); - }, )), Positioned.directional( textDirection: TextDirection.rtl, start: 0, - child: ElevatedButton( - onPressed: () { - onSubmitted(context); + child: ArgonButton( + height: 32, + width: 80, + minWidth: 80, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "创建", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + String dirname = controller.text; + dirname = dirname.replaceAll('"', '').trim(); + if (btnState == ButtonState.Busy) return; + startLoading(); + + AliFile.apiCreatForder(widget.box, widget.parentid, dirname).then((value) { + // fcHide(); + stopLoading(); + if (value == "success") { + Future.delayed(Duration(milliseconds: 600), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + BotToast.showText(text: "创建成功"); + Navigator.of(context).pop('ok'); + } else { + BotToast.showText(text: "创建失败请重试"); + } + }); }, - child: Text(" 创建 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), )), ], ), diff --git a/alixby/lib/pagepan/CreatMiaoChuanBackDialog.dart b/alixby/lib/pagepan/CreatMiaoChuanBackDialog.dart index 6e6aa81..61b2aca 100644 --- a/alixby/lib/pagepan/CreatMiaoChuanBackDialog.dart +++ b/alixby/lib/pagepan/CreatMiaoChuanBackDialog.dart @@ -1,5 +1,6 @@ import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/StringUtils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -9,7 +10,7 @@ import 'package:alixby/states/SettingState.dart'; // ignore: must_be_immutable class CreatMiaoChuanBackDialog extends StatelessWidget { CreatMiaoChuanBackDialog({Key? key, required this.filename, required this.info}) : super(key: key) { - controller.text = filename; + controller.text = StringUtils.joinChar(filename); } String filename = ""; String info = ""; @@ -27,7 +28,7 @@ class CreatMiaoChuanBackDialog extends StatelessWidget { style: TextStyle(color: MColors.textColor, fontFamily: "opposans"), child: Center( child: Container( - height: 160, + height: 200, width: 460, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), @@ -57,12 +58,13 @@ class CreatMiaoChuanBackDialog extends StatelessWidget { children: [ TextField( controller: controller, - maxLines: 2, + maxLines: 4, autocorrect: false, enableSuggestions: false, style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), cursorColor: MColors.inputBorderHover, autofocus: false, + readOnly: true, decoration: InputDecoration( helperText: "创建成功,以后可以粘贴此txt的内容,导入恢复文件", helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), @@ -84,7 +86,7 @@ class CreatMiaoChuanBackDialog extends StatelessWidget { Positioned.directional( textDirection: TextDirection.rtl, start: 0, - top: 22, + top: 64, child: Text( info.toUpperCase() + " ", style: TextStyle(fontSize: 13, color: MColors.textColorGray, fontFamily: "opposans"), diff --git a/alixby/lib/pagepan/CreatMiaoChuanDialog.dart b/alixby/lib/pagepan/CreatMiaoChuanDialog.dart index 1fe6911..207d0b7 100644 --- a/alixby/lib/pagepan/CreatMiaoChuanDialog.dart +++ b/alixby/lib/pagepan/CreatMiaoChuanDialog.dart @@ -1,10 +1,12 @@ import 'package:alixby/api/Linker.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; import 'package:alixby/pagepan/CreatMiaoChuanBackDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; +import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -14,17 +16,33 @@ import 'package:alixby/states/SettingState.dart'; // ignore: must_be_immutable class CreatMiaoChuanDialog extends StatefulWidget { CreatMiaoChuanDialog( - {Key? key, required this.box, required this.parentid, required String parentname, required this.filelist}) + {Key? key, + required this.box, + required this.parentid, + required String parentname, + required this.filelist, + required int fileCount, + required int fileSize}) : super(key: key) { var dt = DateTime.now(); if (filelist.length == 1) {} - savename = '秒传_' + - parentname + - "_" + - "${dt.year.toString()}${dt.month.toString().padLeft(2, '0')}${dt.day.toString().padLeft(2, '0')}" + - ".txt"; + if (fileSize > 0) { + savename = '秒传_' + + parentname + + "_" + + filesize(fileSize, 0).replaceAll(" ", "") + + "_" + + "${dt.year.toString()}${dt.month.toString().padLeft(2, '0')}${dt.day.toString().padLeft(2, '0')}" + + ".txt"; + } else { + savename = '秒传_' + + parentname + + "_" + + "${dt.year.toString()}${dt.month.toString().padLeft(2, '0')}${dt.day.toString().padLeft(2, '0')}" + + ".txt"; + } } String box = ""; String parentid = ""; @@ -63,8 +81,8 @@ class _CreatMiaoChuanDialogState extends State { style: TextStyle(color: MColors.textColor, fontFamily: "opposans"), child: Center( child: Container( - height: 400, - width: 500, + height: 460, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -97,7 +115,88 @@ class _CreatMiaoChuanDialogState extends State { child: Text("为选中的 " + widget.filelist.length.toString() + " 个文件/文件夹创建秒传文件"), ), Padding(padding: EdgeInsets.only(top: 24)), - _buildCanShu(context), + Container( + child: TextField( + controller: pwdcontroller, + minLines: 1, + maxLines: 4, + scrollPhysics: NeverScrollableScrollPhysics(), + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: true, + decoration: InputDecoration( + helperText: "填写要保存到网盘里的文件名(.txt)", + helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + )), + Container( + alignment: Alignment.bottomRight, + child: ArgonButton( + height: 32, + width: 120, + minWidth: 120, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "创建秒传文件", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + String filename = pwdcontroller.text; + if (filename.length < 1) { + BotToast.showText(text: "保存的文件名不能为空", align: Alignment(0, 0)); + return; + } + if (filename.endsWith(".txt") == false) filename = filename + ".txt"; + filename = filename.replaceAll("..", ".").replaceAll("\"", ""); + if (btnState == ButtonState.Busy) return; + startLoading(); + Linker.goLinkCreatFile(filename, "", widget.box, widget.parentid, widget.filelist) + .then((value) { + stopLoading(); + if (value.length > 1) { + Navigator.of(context).pop('ok'); + BotToast.showText(text: "创建文件成功"); + Future.delayed(Duration(milliseconds: 600), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: CreatMiaoChuanBackDialog(filename: filename, info: value[0])); + }); + } else { + BotToast.showText(text: "创建失败:" + value[0]); + } + }); + }, + )), Padding(padding: EdgeInsets.only(top: 24)), Padding(padding: EdgeInsets.only(top: 32)), Container( @@ -156,82 +255,4 @@ class _CreatMiaoChuanDialogState extends State { )), ))); } - - Widget _buildCanShu(BuildContext context) { - return Container( - alignment: Alignment.topLeft, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: ConstrainedBox( - constraints: BoxConstraints(maxHeight: 60, maxWidth: 20), - child: TextField( - controller: pwdcontroller, - maxLines: 1, - maxLength: 60, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), - cursorColor: MColors.inputBorderHover, - autofocus: false, - decoration: InputDecoration( - helperText: "填写要保存到网盘里的文件名(.txt)", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderHover, - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderHover, - width: 1, - ), - ), - ), - ))), - Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { - String filename = pwdcontroller.text; - if (filename.length < 1) { - BotToast.showText(text: "保存的文件名不能为空", align: Alignment(0, 0)); - return; - } - if (filename.endsWith(".txt") == false) filename = filename + ".txt"; - filename = filename.replaceAll("..", ".").replaceAll("\"", ""); - var fcHide = Loading.showLoading(); - - Linker.goLinkCreatFile(filename, "", widget.box, widget.parentid, widget.filelist).then((value) { - fcHide(); - if (value.length > 1) { - Navigator.of(context).pop('ok'); - BotToast.showText(text: "创建文件成功"); - Future.delayed(Duration(milliseconds: 200), () { - Global.getTreeState(widget.box).pageRefreshNode(); - }); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: CreatMiaoChuanBackDialog(filename: filename, info: value[0])); - }); - } else { - BotToast.showText(text: "创建失败:" + value[0]); - } - }); - }, - child: Text("生成文件"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), - ), - ], - ), - ); - } } diff --git a/alixby/lib/pagepan/DownSaveDialog.dart b/alixby/lib/pagepan/DownSaveDialog.dart index 4dd03e5..238aa16 100644 --- a/alixby/lib/pagepan/DownSaveDialog.dart +++ b/alixby/lib/pagepan/DownSaveDialog.dart @@ -3,6 +3,8 @@ import 'package:alixby/states/Global.dart'; import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -102,7 +104,7 @@ class _DownSaveDialogState extends State { helperText: "默认是保存位置+网盘全路径+文件名,不推荐修改", helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: MColors.inputBorderHover, @@ -122,10 +124,28 @@ class _DownSaveDialogState extends State { start: 0, child: ConstrainedBox( constraints: BoxConstraints(minHeight: 31), - child: ElevatedButton.icon( - icon: Icon(MIcons.file_folder, size: 16), - label: Text('选择'), - onPressed: () => _getDirectoryPath()))), + child: ArgonButton( + height: 32, + width: 80, + minWidth: 80, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "选择", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + _getDirectoryPath(); + }, + ))), ], ), ), diff --git a/alixby/lib/pagepan/DropUploadDialog.dart b/alixby/lib/pagepan/DropUploadDialog.dart index d107588..fa9f020 100644 --- a/alixby/lib/pagepan/DropUploadDialog.dart +++ b/alixby/lib/pagepan/DropUploadDialog.dart @@ -3,9 +3,11 @@ import 'dart:io'; import 'package:alixby/api/Uploader.dart'; import 'package:alixby/models/PageRightFileItem.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:alixby/utils/StringUtils.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -101,7 +103,7 @@ class _DropUploadDialogState extends State { child: Center( child: Container( height: 520, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -211,7 +213,7 @@ class _DropUploadDialogState extends State { padding2, Expanded( child: Text( - item.title, + StringUtils.joinChar(item.title), style: textStyle, softWrap: false, overflow: TextOverflow.ellipsis, @@ -242,15 +244,33 @@ class _DropUploadDialogState extends State { style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { - var fcHide = Loading.showLoading(); + ArgonButton( + height: 32, + width: 80, + minWidth: 80, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "上传", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + if (btnState == ButtonState.Busy) return; + startLoading(); Uploader.goUploadFileAndDir(widget.box, widget.parentid, widget.fileuplist).then((value) { - fcHide(); + stopLoading(); if (value > 0) { BotToast.showText(text: "成功创建" + value.toString() + "个上传任务"); BotToast.remove(widget.ukey, "upload"); - Future.delayed(Duration(milliseconds: 500), () { + Future.delayed(Duration(milliseconds: 600), () { Global.getTreeState(widget.box).pageRefreshNode(); }); } else { @@ -258,8 +278,6 @@ class _DropUploadDialogState extends State { } }); }, - child: Text(" 上传 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ], ), diff --git a/alixby/lib/pagepan/MoveDialog.dart b/alixby/lib/pagepan/MoveDialog.dart index a3b2823..05ee742 100644 --- a/alixby/lib/pagepan/MoveDialog.dart +++ b/alixby/lib/pagepan/MoveDialog.dart @@ -1,8 +1,10 @@ import 'package:alixby/api/AliFile.dart'; import 'package:alixby/states/PanData.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:alixby/utils/StringUtils.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -68,7 +70,7 @@ class _MoveDialogState extends State { child: Center( child: Container( height: 500, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -92,7 +94,7 @@ class _MoveDialogState extends State { TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), Container(padding: EdgeInsets.only(top: 20)), Container( - width: 440, + width: 480, height: 370, alignment: Alignment.topLeft, decoration: BoxDecoration( @@ -139,7 +141,7 @@ class _MoveDialogState extends State { )), ))), Container( - width: 440, + width: 480, padding: EdgeInsets.only(top: 12), child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ UnconstrainedBox( @@ -189,50 +191,66 @@ class _MoveDialogState extends State { style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { - if (widget.parentid == selectKey && widget.box == movetobox) { - BotToast.showText(text: "不能" + widget.pagetitle + "到原位置"); - return; - } - if (widget.filelist.length > 0) { - var fcHide = Loading.showLoading(); + ArgonButton( + height: 32, + width: 200, + minWidth: 200, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + widget.pagetitle + "到选中的文件夹内", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + if (widget.parentid == selectKey && widget.box == movetobox) { + BotToast.showText(text: "不能" + widget.pagetitle + "到原位置"); + return; + } + if (widget.filelist.length > 0) { + if (btnState == ButtonState.Busy) return; + startLoading(); - if (widget.iscopy) { - AliFile.apiCopyBatch(widget.box, widget.parentid, widget.filelist, movetobox, selectKey) - .then((value) { - fcHide(); - Future.delayed(Duration(milliseconds: 600), () { - PanData.loadFileList(widget.box, widget.parentid, "copy"); //触发联网加载 - }); - Future.delayed(Duration(milliseconds: 700), () { - PanData.loadFileList(movetobox, selectKey, "copy"); //触发联网加载 - }); + if (widget.iscopy) { + AliFile.apiCopyBatch( + widget.box, widget.parentid, widget.filelist, movetobox, selectKey) + .then((value) { + stopLoading(); + Future.delayed(Duration(milliseconds: 600), () { + PanData.loadFileList(widget.box, widget.parentid, "copy"); //触发联网加载 + }); + Future.delayed(Duration(milliseconds: 700), () { + PanData.loadFileList(movetobox, selectKey, "copy"); //触发联网加载 + }); - pageExpandedNode("root", true); - Navigator.of(context).pop('ok'); - BotToast.showText(text: "成功" + widget.pagetitle + value.toString() + "个文件"); - }); - } else { - AliFile.apiMoveBatch(widget.box, widget.filelist, movetobox, selectKey).then((value) { - fcHide(); - Future.delayed(Duration(milliseconds: 600), () { - PanData.loadFileList(widget.box, widget.parentid, "move"); //触发联网加载 - }); - Future.delayed(Duration(milliseconds: 700), () { - PanData.loadFileList(movetobox, selectKey, "move"); //触发联网加载 + pageExpandedNode("root", true); + Navigator.of(context).pop('ok'); + BotToast.showText(text: "成功" + widget.pagetitle + value.toString() + "个文件"); }); + } else { + AliFile.apiMoveBatch(widget.box, widget.filelist, movetobox, selectKey).then((value) { + stopLoading(); + Future.delayed(Duration(milliseconds: 600), () { + PanData.loadFileList(widget.box, widget.parentid, "move"); //触发联网加载 + }); + Future.delayed(Duration(milliseconds: 700), () { + PanData.loadFileList(movetobox, selectKey, "move"); //触发联网加载 + }); - pageExpandedNode("root", true); - Navigator.of(context).pop('ok'); - BotToast.showText(text: "成功" + widget.pagetitle + value.toString() + "个文件"); - }); + pageExpandedNode("root", true); + Navigator.of(context).pop('ok'); + BotToast.showText(text: "成功" + widget.pagetitle + value.toString() + "个文件"); + }); + } } - } - }, - child: Text(widget.pagetitle + "到选中的文件夹内"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), - ), + }), ]), ), ], @@ -336,7 +354,7 @@ class DirNode2 { hoverDecoration: hoverDecoration, child: Container( key: Key("pdt_move_rchc_" + key), - width: 400 - leve * 20, + width: 440 - leve * 20, height: 24, padding: padding, child: Row(key: Key("pdt_move_rchcr_" + key), children: [ @@ -344,7 +362,7 @@ class DirNode2 { padding2, Expanded( child: Text( - label, + StringUtils.joinChar(label), key: Key("pdt_move_rchcrt_" + key), style: style, maxLines: 1, @@ -367,7 +385,7 @@ class DirNode2 { hoverDecoration: hoverDecorations, child: Container( key: Key("pdt_move_rchc_" + key), - width: 400 - leve * 20, + width: 440 - leve * 20, height: 24, padding: padding, child: Row(key: Key("pdt_move_rchcr_" + key), children: [ @@ -375,7 +393,7 @@ class DirNode2 { padding2, Expanded( child: Text( - label, + StringUtils.joinChar(label), key: Key("pdt_move_rchcrt_" + key), style: styles, maxLines: 1, diff --git a/alixby/lib/pagepan/PageRightPan.dart b/alixby/lib/pagepan/PageRightPan.dart index 682810f..a65f04d 100644 --- a/alixby/lib/pagepan/PageRightPan.dart +++ b/alixby/lib/pagepan/PageRightPan.dart @@ -67,7 +67,7 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie Padding(padding: EdgeInsets.only(left: 8)), Text(filestate.pageRightFileSelectedDes), Expanded(child: Container()), - Container(child: Icon(MIcons.sort, color: Color(0xff637dff), size: 28)), + Container(child: Icon(MIcons.sort, color: Color(0xff637dff), size: 22)), Container(child: _buildSortMenu(filestate)), Padding(padding: EdgeInsets.only(left: 12)), ])), @@ -108,7 +108,7 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie tooltip: '选择排序方式', padding: EdgeInsets.all(0), child: Text("按 " + filestate.pageRightFileOrderBy + " 排序", - style: TextStyle(fontSize: 14, color: Color(0xff637dff), fontFamily: "opposans")), + style: TextStyle(fontSize: 13, color: Color(0xff637dff), fontFamily: "opposans")), itemBuilder: (context) { return >[ PopupMenuItem( @@ -123,6 +123,12 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie value: '文件名 从大到小', child: Text('文件名 从大到小'), ), + PopupMenuItem( + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), + height: 32, + value: '文件类型', + child: Text('文件类型'), + ), PopupMenuItem( textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), height: 32, diff --git a/alixby/lib/pagepan/PanFileList.dart b/alixby/lib/pagepan/PanFileList.dart index 99a444c..0a457be 100644 --- a/alixby/lib/pagepan/PanFileList.dart +++ b/alixby/lib/pagepan/PanFileList.dart @@ -5,6 +5,7 @@ import 'package:alixby/utils/Loading.dart'; import 'package:alixby/pagepan/ImageDialog.dart'; import 'package:alixby/pagepan/TextDialog.dart'; import 'package:alixby/pagepan/UnRarDialog.dart'; +import 'package:alixby/utils/StringUtils.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/rendering.dart'; import 'package:hovering/hovering.dart'; @@ -178,7 +179,9 @@ class _PanFileListState extends State { var hoverDecorations = BoxDecoration( color: MColors.pageRightFileBGSelect, border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); - var title = item.title.padRight(10); + var title = item.title; + if (title.length < 10) title = title.padRight(10, ' '); + return HoverContainer( key: Key("prf_h_" + item.key), cursor: SystemMouseCursors.basic, @@ -210,7 +213,8 @@ class _PanFileListState extends State { mouseCursor: item.filetype != "file" ? SystemMouseCursors.click : SystemMouseCursors.basic, onTap: () => onTapFileName(item.box, item.key, item.filetype, context), - child: Text(title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2)))) + child: Text(StringUtils.joinChar(title), + softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2)))) ])), Container( key: Key("prf_hcr_s_" + item.key), diff --git a/alixby/lib/pagepan/PanRightTopButton.dart b/alixby/lib/pagepan/PanRightTopButton.dart index 833094d..bce95f1 100644 --- a/alixby/lib/pagepan/PanRightTopButton.dart +++ b/alixby/lib/pagepan/PanRightTopButton.dart @@ -3,6 +3,7 @@ import 'package:alixby/api/Downloader.dart'; import 'package:alixby/api/Uploader.dart'; import 'package:alixby/pagepan/SaveMiaoChuan115Dialog.dart'; import 'package:alixby/pagepan/SaveMiaoChuanXbyDialog.dart'; +import 'package:alixby/pagepan/SaveShareDialog.dart'; import 'package:alixby/states/Global.dart'; import 'package:alixby/states/PanData.dart'; import 'package:alixby/utils/Loading.dart'; @@ -11,6 +12,8 @@ import 'package:alixby/utils/MIcons.dart'; import 'package:alixby/pagepan/CreatMiaoChuanDialog.dart'; import 'package:alixby/pagepan/RenameMutlDialog.dart'; import 'package:alixby/pagepan/SaveMiaoChuanTxtDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; @@ -166,26 +169,23 @@ class _PanRightTopButtonState extends State { } Widget _buildRefresh() { - return OutlinedButton.icon( - icon: Icon(MIcons.sync, size: 16), - label: Text('刷新'), - onPressed: () => Global.getTreeState(widget.box).pageRefreshNode()); + return _buildBtn("刷新", MIcons.sync, (start, stop) { + Global.getTreeState(widget.box).pageRefreshNode(); + }); } Widget _buildCreatDir() { - return OutlinedButton.icon( - icon: Icon(MIcons.folderadd, size: 16), - label: Text('新建文件夹'), - onPressed: () { - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: CreatDirDialog(box: widget.box)); - }); - }); + return _buildBtn("新建文件夹", MIcons.folderadd, (start, stop) { + var parentid = Global.getFileState(widget.box).pageRightDirKey; + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: CreatDirDialog(box: widget.box, parentid: parentid)); + }); + }); } Widget _buildUpload() { @@ -234,7 +234,7 @@ class _PanRightTopButtonState extends State { padding: EdgeInsets.all(0), color: MColors.userNavBtnBG, child: OutlinedButton.icon( - icon: Icon(MIcons.upload, size: 16), + icon: Icon(MIcons.upload, size: 18), label: Text('上传'), onPressed: null, style: ButtonStyle(mouseCursor: MaterialStateMouseCursor.clickable), @@ -259,83 +259,72 @@ class _PanRightTopButtonState extends State { } Widget _buildDown() { - var txt = "下载"; + return _buildBtn("下载", MIcons.download, (start, stop) { + if (Global.settingState.setting.savePath == "") { + BotToast.showText(text: "需要先设置一下下载保存位置"); + Global.userState.updatePageIndex(4); + return; + } + var parentid = Global.getFileState(widget.box).pageRightDirKey; + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - return OutlinedButton.icon( - icon: Icon(MIcons.download, size: 16), - label: Text(txt), - onPressed: () { - if (Global.settingState.setting.savePath == "") { - BotToast.showText(text: "需要先设置一下下载保存位置"); - Global.userState.updatePageIndex(4); - return; - } - var parentid = Global.getFileState(widget.box).pageRightDirKey; - var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - - if (Global.settingState.setting.savePathCheck == false) { - //直接下载 - var savepath = Global.settingState.setting.savePath.replaceAll('"', '').trim(); - var fcHide = Loading.showLoading(); - Downloader.goDownFile(widget.box, parentid, savepath, filelist).then((value) { - fcHide(); - if (value > 0) { - BotToast.showText(text: "成功创建" + value.toString() + "个文件的下载任务"); - } else { - BotToast.showText(text: "创建下载任务失败请重试"); - } - }); - return; + if (Global.settingState.setting.savePathCheck == false) { + //直接下载 + var savepath = Global.settingState.setting.savePath.replaceAll('"', '').trim(); + start(); + Downloader.goDownFile(widget.box, parentid, savepath, filelist).then((value) { + stop(); + if (value > 0) { + BotToast.showText(text: "成功创建" + value.toString() + "个文件的下载任务"); } else { - //显示弹窗 - var parentPath = Global.getFileState(widget.box).getSelectedFileParentPath(); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: DownSaveDialog( - box: widget.box, parentid: parentid, parentPath: parentPath, filelist: filelist)); - }); + BotToast.showText(text: "创建下载任务失败请重试"); } }); + return; + } else { + //显示弹窗 + var parentPath = Global.getFileState(widget.box).getSelectedFileParentPath(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: + DownSaveDialog(box: widget.box, parentid: parentid, parentPath: parentPath, filelist: filelist)); + }); + } + }); } Widget _buildMove() { - return OutlinedButton.icon( - icon: Icon(MIcons.scissor, size: 16), - label: Text("移动"), - onPressed: () { - var parentid = Global.getFileState(widget.box).pageRightDirKey; - var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: MoveDialog(iscopy: false, box: widget.box, parentid: parentid, filelist: filelist)); - }); - }); + return _buildBtn("移动", MIcons.scissor, (start, stop) { + var parentid = Global.getFileState(widget.box).pageRightDirKey; + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: MoveDialog(iscopy: false, box: widget.box, parentid: parentid, filelist: filelist)); + }); + }); } Widget _buildCopy() { - return OutlinedButton.icon( - icon: Icon(MIcons.copy, size: 16), - label: Text("复制"), - onPressed: () { - var parentid = Global.getFileState(widget.box).pageRightDirKey; - var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: MoveDialog(iscopy: true, box: widget.box, parentid: parentid, filelist: filelist)); - }); - }); + return _buildBtn("复制", MIcons.copy, (start, stop) { + var parentid = Global.getFileState(widget.box).pageRightDirKey; + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: MoveDialog(iscopy: true, box: widget.box, parentid: parentid, filelist: filelist)); + }); + }); } // ignore: unused_element @@ -347,9 +336,15 @@ class _PanRightTopButtonState extends State { var parentid = Global.getFileState(widget.box).pageRightDirKey; var parentname = Global.getFileState(widget.box).pageRightDirName; var files = Global.getFileState(widget.box).getSelectedFiles(); - if (files.length == 1) { + var filecount = files.length; + if (filecount == 1) { parentname = files[0].title; } + var filesize = 0; + for (var i = 0; i < filecount; i++) { + filesize += files[i].fileSize; + } + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); showDialog( barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 @@ -358,7 +353,13 @@ class _PanRightTopButtonState extends State { return WillPopScope( onWillPop: () async => false, //关键代码 child: CreatMiaoChuanDialog( - box: widget.box, parentid: parentid, parentname: parentname, filelist: filelist)); + box: widget.box, + parentid: parentid, + parentname: parentname, + filelist: filelist, + fileCount: files.length, + fileSize: filesize, + )); }); }); } @@ -430,111 +431,98 @@ class _PanRightTopButtonState extends State { } Widget _buildSaveShare() { - return OutlinedButton.icon( - icon: Icon(MIcons.link2, size: 16), - label: Text("导入分享", - style: TextStyle(decorationStyle: TextDecorationStyle.solid, decoration: TextDecoration.lineThrough)), - onPressed: () { - BotToast.showText(text: "此功能还在开发中"); - }); + return _buildBtn("导入分享", MIcons.link, (start, stop) { + var parentid = Global.getFileState(widget.box).pageRightDirKey; + var parentname = Global.getFileState(widget.box).getSelectedFileParentPath(); + + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: SaveShareDialog(box: widget.box, parentid: parentid, parentname: parentname)); + }); + }); } Widget _buildRename() { if (widget.selectCount <= 1) { - return OutlinedButton.icon( - icon: Icon(MIcons.edit_square, size: 16), - label: Text('改名'), - onPressed: () { - var filelist = Global.getFileState(widget.box).getSelectedFiles(); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: RenameDialog(box: widget.box, fileid: filelist[0].key, filename: filelist[0].title)); - }); - }); + return _buildBtn('改名', MIcons.edit_square, (start, stop) { + var filelist = Global.getFileState(widget.box).getSelectedFiles(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: RenameDialog(box: widget.box, fileid: filelist[0].key, filename: filelist[0].title)); + }); + }); } else { - return OutlinedButton.icon( - icon: Icon(MIcons.edit_square, size: 16), - label: Text('批量改名'), - onPressed: () { - var filelist = Global.getFileState(widget.box).getSelectedFiles(); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: RenameMutlDialog(box: widget.box, filelist: filelist)); - }); - }); + return _buildBtn('批量改名', MIcons.edit_square, (start, stop) { + var filelist = Global.getFileState(widget.box).getSelectedFiles(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: RenameMutlDialog(box: widget.box, filelist: filelist)); + }); + }); } } Widget _buildTrash() { - return OutlinedButton.icon( - icon: Icon(MIcons.rest, size: 16), - label: Text("回收站"), - onPressed: () { - var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - if (filelist.length > 0) { - var fcHide = Loading.showLoading(); - - AliFile.apiTrashBatch(widget.box, filelist).then((value) { - fcHide(); - Future.delayed(Duration(milliseconds: 200), () { - Global.getTreeState(widget.box).pageRefreshNode(); - }); - PanData.clearTrash(); - BotToast.showText(text: "成功移到回收站" + value.toString() + "个文件"); - }); - } + return _buildBtn("回收站", MIcons.rest, (start, stop) { + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); + if (filelist.length > 0) { + start(); + AliFile.apiTrashBatch(widget.box, filelist).then((value) { + stop(); + Future.delayed(Duration(milliseconds: 600), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + PanData.clearTrash(); + BotToast.showText(text: "成功移到回收站" + value.toString() + "个文件"); }); + } + }); } Widget _buildTrashDelete() { var txt = "彻底删除"; - if (widget.selectCount > 1) txt = "批量" + txt; - return OutlinedButton.icon( - icon: Icon(MIcons.delete, size: 16), - label: Text(txt), - onPressed: () { - var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - if (filelist.length > 0) { - var fcHide = Loading.showLoading(); - AliFile.apiTrashDeleteBatch(widget.box, filelist).then((value) { - fcHide(); - Future.delayed(Duration(milliseconds: 200), () { - Global.getTreeState(widget.box).pageRefreshNode(); - }); - BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); - }); - } + return _buildBtn(txt, MIcons.delete, (start, stop) { + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); + if (filelist.length > 0) { + start(); + AliFile.apiTrashDeleteBatch(widget.box, filelist).then((value) { + stop(); + Future.delayed(Duration(milliseconds: 600), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); }); + } + }); } Widget _buildTrashRestore() { - var txt = "恢复文件"; - if (widget.selectCount > 1) txt = "批量" + txt; - return OutlinedButton.icon( - icon: Icon(MIcons.recover, size: 16), - label: Text(txt), - onPressed: () { - var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - if (filelist.length > 0) { - var fcHide = Loading.showLoading(); - - AliFile.apiTrashRestoreBatch(widget.box, filelist).then((value) { - fcHide(); - Future.delayed(Duration(milliseconds: 200), () { - Global.getTreeState(widget.box).pageRefreshNode(); - }); - BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); - }); - } + var txt = "恢复选中"; + return _buildBtn(txt, MIcons.recover, (start, stop) { + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); + if (filelist.length > 0) { + start(); + AliFile.apiTrashRestoreBatch(widget.box, filelist).then((value) { + stop(); + Future.delayed(Duration(milliseconds: 600), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); }); + } + }); } Widget _buildOpenDir() { @@ -556,23 +544,69 @@ class _PanRightTopButtonState extends State { Widget _buildFavor(bool isfavor) { var txt = "取消收藏"; if (isfavor) txt = "收藏"; - return OutlinedButton.icon( - icon: Icon(MIcons.crown, size: 16), - label: Text(txt), - onPressed: () { - var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); - if (filelist.length > 0) { - var fcHide = Loading.showLoading(); - - AliFile.apiFavorBatch(widget.box, isfavor, filelist).then((value) { - fcHide(); - Future.delayed(Duration(milliseconds: 200), () { - Global.getTreeState(widget.box).pageRefreshNode(); - }); - if (isfavor) PanData.clearFavor(); - BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); - }); - } + return _buildBtn(txt, MIcons.crown, (start, stop) { + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); + if (filelist.length > 0) { + start(); + AliFile.apiFavorBatch(widget.box, isfavor, filelist).then((value) { + stop(); + Future.delayed(Duration(milliseconds: 600), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + if (isfavor) PanData.clearFavor(); + BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); }); + } + }); + } + + Widget _buildBtn(String title, IconData icondata, Function(Function startLoading, Function stopLoading) onTap) { + double width = 70; + if (title.length == 3) width = 85; + if (title.length == 4) width = 100; + if (title.length == 5) width = 118; + return ArgonButton( + height: 26, + width: width, + minWidth: width, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.outlineBtnBG, + hoverColor: MColors.outlineBtnBGHover, + focusColor: MColors.outlineBtnBGHover, + highlightColor: MColors.outlineBtnBGActive, + splashColor: MColors.outlineBtnBGActive, + elevation: 0, + hoverElevation: 0, + focusElevation: 0, + highlightElevation: 0, + borderSide: BorderSide(color: MColors.outlineBtnBorderColor, width: 1), + child: Stack(alignment: Alignment.centerLeft, children: [ + Positioned( + left: 6, + child: Icon( + icondata, + size: 18, + color: MColors.outlineBtnColor, + )), + Positioned( + left: 28, + child: Text( + title, + style: TextStyle(fontSize: 14, color: MColors.outlineBtnColor, fontFamily: "opposans"), + )), + ]), + loader: Container( + child: SpinKitRing( + size: 19, + lineWidth: 3, + color: MColors.outlineBtnColor, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + if (btnState == ButtonState.Busy) return; + onTap(startLoading, stopLoading); + }, + ); } } diff --git a/alixby/lib/pagepan/RenameDialog.dart b/alixby/lib/pagepan/RenameDialog.dart index eedf24b..92a25ba 100644 --- a/alixby/lib/pagepan/RenameDialog.dart +++ b/alixby/lib/pagepan/RenameDialog.dart @@ -1,8 +1,9 @@ import 'package:alixby/api/AliFile.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -12,34 +13,16 @@ import 'package:alixby/states/SettingState.dart'; // ignore: must_be_immutable class RenameDialog extends StatelessWidget { // ignore: non_constant_identifier_names - RenameDialog({Key? key, required this.box, required this.fileid, required String filename}) : super(key: key) { + RenameDialog({Key? key, required this.box, required this.fileid, required this.filename}) : super(key: key) { controller.text = filename; } String box = ""; String fileid = ""; + String filename = ""; final TextEditingController controller = TextEditingController(); - void onSubmitted(BuildContext context) { - String dirname = controller.text; - dirname = dirname.replaceAll('"', '').trim(); - var fcHide = Loading.showLoading(); - - AliFile.apiRename(box, fileid, dirname).then((value) { - fcHide(); - if (value == "success") { - BotToast.showText(text: "重命名成功"); - Navigator.of(context).pop('ok'); - Future.delayed(Duration(milliseconds: 200), () { - Global.getTreeState(box).pageRefreshNode(); - }); - } else { - BotToast.showText(text: "重命名失败请重试"); - } - }); - } - @override Widget build(BuildContext context) { return Material( @@ -52,7 +35,7 @@ class RenameDialog extends StatelessWidget { style: TextStyle(color: MColors.textColor, fontFamily: "opposans"), child: Center( child: Container( - height: 200, + height: 240, width: 460, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), @@ -78,25 +61,26 @@ class RenameDialog extends StatelessWidget { Container(padding: EdgeInsets.only(top: 20)), Container( width: 380, - padding: EdgeInsets.only(top: 20), - child: Stack( + padding: EdgeInsets.only(top: 8), + child: Column( children: [ ConstrainedBox( - constraints: BoxConstraints(maxHeight: 60, maxWidth: 375), + constraints: BoxConstraints(maxWidth: 380), child: TextField( controller: controller, - maxLines: 1, + minLines: 1, + maxLines: 4, + scrollPhysics: NeverScrollableScrollPhysics(), autocorrect: false, enableSuggestions: false, - style: TextStyle( - fontSize: 14, color: MColors.textColor, fontFamily: "opposans", height: 1), + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), cursorColor: MColors.inputBorderHover, autofocus: true, decoration: InputDecoration( helperText: "文件名不要有特殊字符:<>!:*?\\/.'\"", helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: MColors.inputBorderHover, @@ -110,19 +94,51 @@ class RenameDialog extends StatelessWidget { ), ), ), - onSubmitted: (value) { - onSubmitted(context); - }, )), - Positioned.directional( - textDirection: TextDirection.rtl, - start: 0, - child: ElevatedButton( - onPressed: () { - onSubmitted(context); + Container( + alignment: Alignment.bottomRight, + child: ArgonButton( + height: 32, + width: 90, + minWidth: 90, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "重命名", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + String dirname = controller.text; + dirname = + dirname.replaceAll('"', '').replaceAll('\r', '').replaceAll('\n', '').trim(); + controller.text = dirname; + if (dirname == filename) { + BotToast.showText(text: "新的文件名不能与旧名完全相同"); + return; + } + if (btnState == ButtonState.Busy) return; + startLoading(); + AliFile.apiRename(box, fileid, dirname).then((value) { + stopLoading(); + if (value == "success") { + BotToast.showText(text: "重命名成功"); + Navigator.of(context).pop('ok'); + Future.delayed(Duration(milliseconds: 600), () { + Global.getTreeState(box).pageRefreshNode(); + }); + } else { + BotToast.showText(text: "重命名失败请重试"); + } + }); }, - child: Text(" 重命名 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), )), ], ), diff --git a/alixby/lib/pagepan/RenameMutlDialog.dart b/alixby/lib/pagepan/RenameMutlDialog.dart index 8abcb92..1664b8b 100644 --- a/alixby/lib/pagepan/RenameMutlDialog.dart +++ b/alixby/lib/pagepan/RenameMutlDialog.dart @@ -1,9 +1,10 @@ import 'package:alixby/api/AliFile.dart'; import 'package:alixby/models/PageRightFileItem.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -94,7 +95,7 @@ class _RenameMutlDialogState extends State { child: Center( child: Container( height: 540, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -118,7 +119,7 @@ class _RenameMutlDialogState extends State { TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), Container(padding: EdgeInsets.only(top: 20)), Container( - width: 440, + width: 480, height: 370, alignment: Alignment.topLeft, decoration: BoxDecoration( @@ -144,7 +145,7 @@ class _RenameMutlDialogState extends State { itemBuilder: _buildList, ))), Container( - width: 440, + width: 480, padding: EdgeInsets.only(top: 8), child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ Expanded( @@ -157,7 +158,7 @@ class _RenameMutlDialogState extends State { cursorColor: MColors.inputBorderHover, autofocus: false, decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: MColors.inputBorderHover, @@ -185,7 +186,7 @@ class _RenameMutlDialogState extends State { cursorColor: MColors.inputBorderHover, autofocus: false, decoration: InputDecoration( - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: MColors.inputBorderHover, @@ -203,7 +204,7 @@ class _RenameMutlDialogState extends State { ]), ), Container( - width: 440, + width: 480, padding: EdgeInsets.only(top: 8), child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ Expanded( @@ -220,8 +221,25 @@ class _RenameMutlDialogState extends State { style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { + ArgonButton( + height: 32, + width: 90, + minWidth: 90, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "重命名", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { List keyList = []; List nameList = []; for (var i = 0; i < widget.filelist.length; i++) { @@ -250,13 +268,14 @@ class _RenameMutlDialogState extends State { BotToast.showText(text: "没有需要重命名的文件"); return; } - var fcHide = Loading.showLoading(); + if (btnState == ButtonState.Busy) return; + startLoading(); AliFile.apiRenameBatch(widget.box, keyList, nameList).then((value) { - fcHide(); + stopLoading(); if (value > 0) { Navigator.of(context).pop('ok'); - Future.delayed(Duration(milliseconds: 200), () { + Future.delayed(Duration(milliseconds: 600), () { Global.getTreeState(widget.box).pageRefreshNode(); }); BotToast.showText(text: "成功重命名 " + value.toString() + " 个文件"); @@ -265,8 +284,6 @@ class _RenameMutlDialogState extends State { } }); }, - child: Text("重命名"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ]), ), diff --git a/alixby/lib/pagepan/SaveMiaoChuan115Dialog.dart b/alixby/lib/pagepan/SaveMiaoChuan115Dialog.dart index 872bde0..f1deac1 100644 --- a/alixby/lib/pagepan/SaveMiaoChuan115Dialog.dart +++ b/alixby/lib/pagepan/SaveMiaoChuan115Dialog.dart @@ -1,9 +1,10 @@ import 'package:alixby/api/Linker.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; import 'package:alixby/pagepan/SaveMiaoChuanBackDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -32,13 +33,11 @@ class SaveMiaoChuan115Dialog extends StatefulWidget { class _SaveMiaoChuan115DialogState extends State { final TextEditingController linkcontroller = TextEditingController(); - final TextEditingController pwdcontroller = TextEditingController(); final verticalScroll = ScrollController(); @override void dispose() { verticalScroll.dispose(); linkcontroller.dispose(); - pwdcontroller.dispose(); super.dispose(); } @@ -71,7 +70,7 @@ class _SaveMiaoChuan115DialogState extends State { child: Center( child: Container( height: 500, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -221,14 +220,32 @@ class _SaveMiaoChuan115DialogState extends State { }, )), Expanded(child: Container()), - ElevatedButton( - onPressed: () { + ArgonButton( + height: 32, + width: 90, + minWidth: 90, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "解析链接", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { String link = linkcontroller.text; - String pwd = pwdcontroller.text; - var fcHide = Loading.showLoading(); + String pwd = ""; + if (btnState == ButtonState.Busy) return; + startLoading(); Linker.goLinkParse(link, pwd, isPublic).then((value) { - fcHide(); + stopLoading(); if (value.hash == "") { Navigator.of(context).pop('ok'); BotToast.showText(text: "解析链接成功"); @@ -247,8 +264,6 @@ class _SaveMiaoChuan115DialogState extends State { } }); }, - child: Text(" 解析链接 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ], ), diff --git a/alixby/lib/pagepan/SaveMiaoChuanBackDialog.dart b/alixby/lib/pagepan/SaveMiaoChuanBackDialog.dart index 1d5d71c..07190ea 100644 --- a/alixby/lib/pagepan/SaveMiaoChuanBackDialog.dart +++ b/alixby/lib/pagepan/SaveMiaoChuanBackDialog.dart @@ -1,7 +1,10 @@ import 'package:alixby/api/Linker.dart'; -import 'package:alixby/utils/Loading.dart'; +import 'package:alixby/states/PanData.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:alixby/utils/StringUtils.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; @@ -75,7 +78,7 @@ class _SaveMiaoChuanBackDialogState extends State { child: Center( child: Container( height: 540, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -94,12 +97,12 @@ class _SaveMiaoChuanBackDialogState extends State { onTap: () => Navigator.of(context).pop('ok'), ))), Container( - child: Text("导入秒传短链接---" + widget.boxname, + child: Text("导入文件", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), Container(padding: EdgeInsets.only(top: 20)), Container( - width: 440, + width: 480, height: 370, alignment: Alignment.topLeft, decoration: BoxDecoration( @@ -125,12 +128,12 @@ class _SaveMiaoChuanBackDialogState extends State { itemBuilder: _buildList, ))), Container( - width: 440, + width: 480, height: 54, padding: EdgeInsets.only(top: 8), child: Text("备注信息:" + widget.link.name)), Container( - width: 440, + width: 480, padding: EdgeInsets.only(top: 8), child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ OutlinedButton( @@ -139,24 +142,59 @@ class _SaveMiaoChuanBackDialogState extends State { style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { + ArgonButton( + height: 32, + width: 140, + minWidth: 140, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "导入这些文件", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { if (widget.link.hash == "") { - var fcHide = Loading.showLoading(); - - Linker.goLinkUpload(widget.box, widget.parentid, widget.link.fulljson).then((value) { - fcHide(); - if (value > 0) { - Navigator.of(context).pop('ok'); - BotToast.showText(text: "成功创建 " + value.toString() + " 个文件的秒传任务"); - } else { - BotToast.showText(text: "导入秒传任务失败,请重试"); - } - }); + if (btnState == ButtonState.Busy) return; + startLoading(); + if (widget.link.shareid != "") { + Linker.goLinkShareUpload( + widget.box, widget.parentid, widget.link.shareid, widget.link.fulljson) + .then((value) { + stopLoading(); + if (value > 0) { + Future.delayed(Duration(milliseconds: 800), () { + PanData.loadFileList(widget.box, widget.parentid, "save"); //触发联网加载 + }); + Navigator.of(context).pop('ok'); + BotToast.showText(text: "成功创建 " + value.toString() + " 个文件的分享任务"); + } else { + BotToast.showText(text: "导入分享任务失败,请重试"); + } + }); + } else { + Linker.goLinkUpload(widget.box, widget.parentid, widget.link.fulljson).then((value) { + stopLoading(); + if (value > 0) { + Future.delayed(Duration(milliseconds: 800), () { + PanData.loadFileList(widget.box, widget.parentid, "save"); //触发联网加载 + }); + Navigator.of(context).pop('ok'); + BotToast.showText(text: "成功创建 " + value.toString() + " 个文件的秒传任务"); + } else { + BotToast.showText(text: "导入秒传任务失败,请重试"); + } + }); + } } }, - child: Text("导入这些文件"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ]), ), @@ -195,7 +233,8 @@ class _SaveMiaoChuanBackDialogState extends State { Expanded( child: Tooltip( message: item.name, - child: Text(item.name, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 1)), + child: Text(StringUtils.joinChar(item.name), + softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 1)), ), Container( width: 88, diff --git a/alixby/lib/pagepan/SaveMiaoChuanTxtDialog.dart b/alixby/lib/pagepan/SaveMiaoChuanTxtDialog.dart index 9360940..c31b80e 100644 --- a/alixby/lib/pagepan/SaveMiaoChuanTxtDialog.dart +++ b/alixby/lib/pagepan/SaveMiaoChuanTxtDialog.dart @@ -1,9 +1,10 @@ import 'package:alixby/api/Linker.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; import 'package:alixby/pagepan/SaveMiaoChuanBackDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -32,13 +33,11 @@ class SaveMiaoChuanTxtDialog extends StatefulWidget { class _SaveMiaoChuanTxtDialogState extends State { final TextEditingController linkcontroller = TextEditingController(); - final TextEditingController pwdcontroller = TextEditingController(); final verticalScroll = ScrollController(); @override void dispose() { verticalScroll.dispose(); linkcontroller.dispose(); - pwdcontroller.dispose(); super.dispose(); } @@ -71,7 +70,7 @@ class _SaveMiaoChuanTxtDialogState extends State { child: Center( child: Container( height: 480, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -214,14 +213,32 @@ class _SaveMiaoChuanTxtDialogState extends State { }, )), Expanded(child: Container()), - ElevatedButton( - onPressed: () { + ArgonButton( + height: 32, + width: 90, + minWidth: 90, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "解析链接", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { String link = linkcontroller.text; - String pwd = pwdcontroller.text; - var fcHide = Loading.showLoading(); + String pwd = ""; + if (btnState == ButtonState.Busy) return; + startLoading(); Linker.goLinkParse(link, pwd, isPublic).then((value) { - fcHide(); + stopLoading(); if (value.hash == "") { Navigator.of(context).pop('ok'); BotToast.showText(text: "解析链接成功"); @@ -240,8 +257,6 @@ class _SaveMiaoChuanTxtDialogState extends State { } }); }, - child: Text(" 解析链接 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ], ), diff --git a/alixby/lib/pagepan/SaveMiaoChuanXbyDialog.dart b/alixby/lib/pagepan/SaveMiaoChuanXbyDialog.dart index 5c411cc..300be46 100644 --- a/alixby/lib/pagepan/SaveMiaoChuanXbyDialog.dart +++ b/alixby/lib/pagepan/SaveMiaoChuanXbyDialog.dart @@ -1,9 +1,10 @@ import 'package:alixby/api/Linker.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; import 'package:alixby/pagepan/SaveMiaoChuanBackDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -78,7 +79,7 @@ class _SaveMiaoChuanXbyDialogState extends State { child: Center( child: Container( height: 330, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -214,7 +215,7 @@ class _SaveMiaoChuanXbyDialogState extends State { hintStyle: TextStyle(fontSize: 13, color: MColors.textColorGray, fontFamily: "opposans"), helperText: "密码", helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: MColors.inputBorderHover, @@ -233,14 +234,32 @@ class _SaveMiaoChuanXbyDialogState extends State { Padding(padding: EdgeInsets.only(left: 24)), Expanded(child: Container()), Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { + ArgonButton( + height: 32, + width: 90, + minWidth: 90, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "解析链接", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { String link = linkcontroller.text; String pwd = pwdcontroller.text; - var fcHide = Loading.showLoading(); + if (btnState == ButtonState.Busy) return; + startLoading(); Linker.goLinkParse(link, pwd, isPublic).then((value) { - fcHide(); + stopLoading(); if (value.hash == "") { Navigator.of(context).pop('ok'); BotToast.showText(text: "解析链接成功"); @@ -259,8 +278,6 @@ class _SaveMiaoChuanXbyDialogState extends State { } }); }, - child: Text(" 解析链接 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ], ), diff --git a/alixby/lib/pagepan/SaveShareDialog.dart b/alixby/lib/pagepan/SaveShareDialog.dart new file mode 100644 index 0000000..55409b4 --- /dev/null +++ b/alixby/lib/pagepan/SaveShareDialog.dart @@ -0,0 +1,306 @@ +import 'package:alixby/api/Linker.dart'; +import 'package:alixby/states/Global.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/pagepan/SaveMiaoChuanBackDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class SaveShareDialog extends StatefulWidget { + SaveShareDialog({Key? key, required this.box, required this.parentid, required this.parentname}) : super(key: key) { + if (box == "box") + boxname = "网盘"; + else if (box == "sbox") + boxname = "保险箱"; + else if (box == "xiangce") boxname = "相册"; + } + String box = ""; + String boxname = ""; + String parentid = ""; + String parentname = ""; + + @override + _SaveShareDialogState createState() => _SaveShareDialogState(); +} + +class _SaveShareDialogState extends State { + final TextEditingController linkcontroller = TextEditingController(); + final TextEditingController pwdcontroller = TextEditingController(); + final verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + linkcontroller.dispose(); + pwdcontroller.dispose(); + super.dispose(); + } + + bool isPublic = false; + @override + void initState() { + super.initState(); + //https://115.com/s/swnfmss3zbk?password=0000 + //https://www.aliyundrive.com/s/FGtXkA5SVZM + Clipboard.getData("text/plain").then((value) { + if (value != null) { + var text = value.text; + if (text != null) { + if (text.indexOf("115.com/s/") > 0 || text.indexOf("aliyundrive.com/s/") > 0) { + text = text.replaceAll("?password=", "密码:"); //115 + text = text.replaceAll("访问码:", "密码:"); //115 + text = text.replaceAll("提取码:", "密码:"); //115 + text = text.replaceAll("密码:", "密码:"); //115 + } + if (text.indexOf("密码:") > 0) { + var pwd = text.substring(text.indexOf("密码:") + "密码:".length).trim(); + if (text.indexOf("115.com/s/") > 0) { + pwd = pwd.substring(0, 4); //115是4位密码 + } else if (text.indexOf("aliyundrive.com/s/") > 0) { + pwd = pwd.substring(0, 4); //ali是4位密码 + } + + if (pwd.length == 4) { + pwdcontroller.text = pwd; + text = text.substring(0, text.indexOf("密码:")).trim(); + } + } + if (text.indexOf("115.com/s/") > 0 || text.indexOf("aliyundrive.com/s/") > 0) { + linkcontroller.text = text; + } + } + } + }); + } + + @override + Widget build(BuildContext context) { + return Material( + type: MaterialType.transparency, + child: MediaQuery( + data: MediaQuery.of(context) + .copyWith(textScaleFactor: double.parse(context.watch().setting.textScale)), + child: DefaultTextStyle( + //1.设置文本默认样式 + style: TextStyle(color: MColors.textColor, fontFamily: "opposans"), + child: Center( + child: Container( + height: 330, + width: 520, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: MColors.dialogBgColor, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + alignment: Alignment.topRight, + padding: EdgeInsets.only(top: 8, right: 8, bottom: 8), + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + child: Icon(MIcons.close, size: 18, color: MColors.textColor), + onTap: () => Navigator.of(context).pop('ok'), + ))), + Container( + child: Text("导入115 / 阿里云盘分享链接", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + padding: EdgeInsets.only(left: 20, right: 20), + alignment: Alignment.topLeft, + child: Column(children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 70, minWidth: double.infinity), + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan( + text: "文件会被保存在当前路径下:", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "/" + widget.boxname + "根目录" + widget.parentname, + style: TextStyle( + fontSize: 12, color: MColors.linkColor, fontFamily: "opposans")), + ])), + ), + Padding(padding: EdgeInsets.only(top: 12)), + _buildLink(context), + Padding(padding: EdgeInsets.only(top: 4)), + Container( + alignment: Alignment.topLeft, + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan( + text: "一条 阿里云盘分享 ", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "https://www.aliyundrive.com/s/xxxxxxxxxxx\n", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + TextSpan( + text: "一条 115分享链接 ", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "https://115.com/s/sssssssssss", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + ]))), + Padding(padding: EdgeInsets.only(top: 24)), + _buildCanShu(context), + ])), + ], + ), + )), + ))); + } + + Widget _buildLink(BuildContext context) { + return Container( + alignment: Alignment.topLeft, + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: 60, minWidth: double.infinity), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: TextField( + controller: linkcontroller, + scrollController: verticalScroll, + maxLines: 3, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + ))), + ); + } + + Widget _buildCanShu(BuildContext context) { + return Container( + alignment: Alignment.topLeft, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: ConstrainedBox( + constraints: BoxConstraints(maxHeight: 60, maxWidth: 120), + child: TextField( + controller: pwdcontroller, + maxLines: 1, + maxLength: 4, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: false, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp("[0-9a-zA-Z]")), //只允许输入数字字母 + ], + decoration: InputDecoration( + hintText: "无", + hintStyle: TextStyle(fontSize: 13, color: MColors.textColorGray, fontFamily: "opposans"), + helperText: "密码", + helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + )), + ), + Padding(padding: EdgeInsets.only(left: 24)), + Expanded(child: Container()), + Padding(padding: EdgeInsets.only(left: 24)), + ArgonButton( + height: 32, + width: 90, + minWidth: 90, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "解析链接", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + String link = linkcontroller.text; + String pwd = pwdcontroller.text; + if (btnState == ButtonState.Busy) return; + startLoading(); + + Linker.goLinkShare(link, pwd, isPublic).then((value) { + stopLoading(); + if (value.hash == "") { + Navigator.of(context).pop('ok'); + BotToast.showText(text: "解析链接成功"); + Global.pageRssMiaoChuanState.refreshLink(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: SaveMiaoChuanBackDialog( + box: widget.box, boxname: widget.boxname, parentid: widget.parentid, link: value)); + }); + } else { + BotToast.showText(text: "解析链接失败:" + value.hash); + } + }); + }, + ), + ], + ), + ); + } +} diff --git a/alixby/lib/pagepan/UnrarDialog.dart b/alixby/lib/pagepan/UnrarDialog.dart index 9993c99..8145406 100644 --- a/alixby/lib/pagepan/UnrarDialog.dart +++ b/alixby/lib/pagepan/UnrarDialog.dart @@ -1,8 +1,10 @@ import 'package:alixby/api/AliFile.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; import 'package:alixby/pagepan/UnrarBackDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:alixby/utils/StringUtils.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -70,7 +72,7 @@ class _UnrarDialogState extends State { child: Center( child: Container( height: 500, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -94,7 +96,7 @@ class _UnrarDialogState extends State { TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), Container(padding: EdgeInsets.only(top: 20)), Container( - width: 440, + width: 480, height: 370, alignment: Alignment.topLeft, decoration: BoxDecoration( @@ -141,7 +143,7 @@ class _UnrarDialogState extends State { )), ))), Container( - width: 440, + width: 480, padding: EdgeInsets.only(top: 12), child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ Expanded( @@ -156,7 +158,7 @@ class _UnrarDialogState extends State { decoration: InputDecoration( hintText: "解压密码。没有不填", hintStyle: TextStyle(fontSize: 13, color: MColors.textColorGray, fontFamily: "opposans"), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: MColors.inputBorderHover, @@ -178,12 +180,30 @@ class _UnrarDialogState extends State { style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { + ArgonButton( + height: 32, + width: 220, + minWidth: 220, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "解压缩到选中的文件夹内", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { var password = controller.text; - var fcHide = Loading.showLoading(); + if (btnState == ButtonState.Busy) return; + startLoading(); AliFile.apiUncompress(widget.box, widget.fileid, selectKey, password).then((value) { - fcHide(); + stopLoading(); if (value.length == 1) { BotToast.showText(text: "失败:" + value[0]); return; @@ -201,8 +221,6 @@ class _UnrarDialogState extends State { }); }); }, - child: Text("解压缩到选中的文件夹内"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ]), ), @@ -297,7 +315,7 @@ class DirNode2 { hoverDecoration: hoverDecoration, child: Container( key: Key("pdt_unrar_rchc_" + key), - width: 400 - leve * 20, + width: 440 - leve * 20, height: 24, padding: padding, child: Row(key: Key("pdt_unrar_rchcr_" + key), children: [ @@ -305,7 +323,7 @@ class DirNode2 { padding2, Expanded( child: Text( - label, + StringUtils.joinChar(label), key: Key("pdt_unrar_rchcrt_" + key), style: style, maxLines: 1, @@ -328,7 +346,7 @@ class DirNode2 { hoverDecoration: hoverDecorations, child: Container( key: Key("pdt_unrar_rchc_" + key), - width: 400 - leve * 20, + width: 440 - leve * 20, height: 24, padding: padding, child: Row(key: Key("pdt_unrar_rchcr_" + key), children: [ @@ -336,7 +354,7 @@ class DirNode2 { padding2, Expanded( child: Text( - label, + StringUtils.joinChar(label), key: Key("pdt_unrar_rchcrt_" + key), style: styles, maxLines: 1, diff --git a/alixby/lib/pagerss/PageRightRssHelp.dart b/alixby/lib/pagerss/PageRightRssHelp.dart index cee97e9..e112a48 100644 --- a/alixby/lib/pagerss/PageRightRssHelp.dart +++ b/alixby/lib/pagerss/PageRightRssHelp.dart @@ -26,12 +26,7 @@ class _PageRightRssHelpState extends State { // ignore: must_call_super Widget build(BuildContext context) { var stylegray = TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"); - var styleQ = TextStyle( - fontFamily: "opposans", - decoration: TextDecoration.underline, - decorationStyle: TextDecorationStyle.solid, - decorationThickness: 2, - decorationColor: Colors.yellowAccent.shade700); + var styleQ = TextStyle(fontFamily: "opposans", color: MColors.textColorYellow); return Column(children: [ Container( height: 52, @@ -147,12 +142,12 @@ class _PageRightRssHelpState extends State { ), Padding(padding: EdgeInsets.only(top: 32)), Container( - child: Text("Q∷不能导入115分享链接?百度分享链接?磁力链接?", style: styleQ), + child: Text("Q∷不能导入百度分享链接?磁力链接?电驴链接?", style: styleQ), ), Padding(padding: EdgeInsets.only(top: 8)), Container( child: Text( - "答:当然都 不可以,但是可以导入115秒传链接(115://........)和阿里云盘秒传链接(aliyunpan://........)", + "答:不可以,但是可以导入:\n1. 115分享链接(http://115.com/s/......)\n2. 115秒传链接(115://........)\n3. 阿里云盘分享链接(http://www.aliyundrive.com/s/........)\n4. 阿里云盘秒传链接(aliyunpan://........)\n5. txt格式的秒传文件", style: stylegray, softWrap: true, ), diff --git a/alixby/lib/pagerss/PageRightRssSearch.dart b/alixby/lib/pagerss/PageRightRssSearch.dart index 332cf2f..39ea8da 100644 --- a/alixby/lib/pagerss/PageRightRssSearch.dart +++ b/alixby/lib/pagerss/PageRightRssSearch.dart @@ -3,6 +3,9 @@ import 'package:alixby/states/pageRssSearchState.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; import 'package:alixby/pagerss/ZhuanCunDialog.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; +import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:hovering/hovering.dart'; import 'package:provider/provider.dart'; @@ -17,17 +20,15 @@ class _PageRightRssSearchState extends State { void initState() { super.initState(); Global.pageRssSearchState.searchcontroller.addListener(() { - print(Global.pageRssSearchState.searchcontroller.text); + //print(Global.pageRssSearchState.searchcontroller.text); }); } @override void dispose() { - verticalScroll.dispose(); super.dispose(); } - final verticalScroll = ScrollController(); @override // ignore: must_call_super Widget build(BuildContext context) { @@ -36,17 +37,17 @@ class _PageRightRssSearchState extends State { return Column( children: [ Container( - height: 52, + height: 46, width: double.infinity, alignment: Alignment.center, child: Stack( children: [ ConstrainedBox( - constraints: BoxConstraints(maxHeight: 60, maxWidth: 275), + constraints: BoxConstraints(maxHeight: 60, maxWidth: 375), child: TextField( controller: Global.pageRssSearchState.searchcontroller, onSubmitted: (val) { - Global.pageRssSearchState.pageSearch(1); + Global.pageRssSearchState.pageSearch(1, null); }, maxLines: 1, autocorrect: false, @@ -75,29 +76,50 @@ class _PageRightRssSearchState extends State { Positioned.directional( textDirection: TextDirection.rtl, start: 0, - child: ElevatedButton( - onPressed: () { - Global.pageRssSearchState.pageSearch(1); + child: ArgonButton( + height: 32, + width: 80, + minWidth: 80, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "搜索", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { + if (btnState == ButtonState.Busy) return; + startLoading(); + Global.pageRssSearchState.pageSearch(1, stopLoading); }, - child: Text(" 搜索 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), )), ], ), ), Container( - height: 34, + height: 40, width: double.infinity, child: Row( children: [ Container( - width: 166, + width: 324, child: Row(children: [ OutlinedButton.icon( icon: Icon(MIcons.chuanshu, size: 16), label: Text('转存选中项'), onPressed: () { var filelist = Global.pageRssSearchState.getSelectedFiles(); + if (filelist.length == 0) { + BotToast.showText(text: "请先选中要转存的文件"); + return; + } showDialog( barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 context: context, @@ -107,7 +129,44 @@ class _PageRightRssSearchState extends State { child: ZhuanCunDialog(filelist: filelist)); }); }), - Expanded(child: Container()), + Padding(padding: EdgeInsets.only(left: 12)), + Expanded( + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: TextStyle(fontSize: 12, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan( + text: "搜索", style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: " a空格b ", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + TextSpan( + text: "是搜索包含", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "a 或者 b", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + TextSpan( + text: "\n搜索", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: " a+b ", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + TextSpan( + text: "是搜索包含a ", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "并且", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + TextSpan( + text: " 包含b", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + ]))), ])), Expanded(child: context.watch().navBtns), ], @@ -151,13 +210,13 @@ class _PageRightRssSearchState extends State { decoration: BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), alignment: Alignment.topLeft, child: Scrollbar( - controller: verticalScroll, + controller: Global.pageRssSearchState.verticalScroll, isAlwaysShown: true, showTrackOnHover: true, thickness: 9, hoverThickness: 9, child: ListView.builder( - controller: verticalScroll, + controller: Global.pageRssSearchState.verticalScroll, shrinkWrap: false, primary: false, addSemanticIndexes: false, diff --git a/alixby/lib/pagerss/ZhuanCunDialog.dart b/alixby/lib/pagerss/ZhuanCunDialog.dart index 3479e50..0973a3d 100644 --- a/alixby/lib/pagerss/ZhuanCunDialog.dart +++ b/alixby/lib/pagerss/ZhuanCunDialog.dart @@ -2,9 +2,11 @@ import 'package:alixby/api/AliFile.dart'; import 'package:alixby/api/Linker.dart'; import 'package:alixby/models/PageRightFileItem.dart'; import 'package:alixby/states/PanData.dart'; -import 'package:alixby/utils/Loading.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/utils/SpinKitRing.dart'; +import 'package:alixby/utils/StringUtils.dart'; +import 'package:argon_buttons_flutter/argon_buttons_flutter.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -61,7 +63,7 @@ class _ZhuanCunDialogState extends State { child: Center( child: Container( height: 500, - width: 500, + width: 520, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: MColors.dialogBgColor, @@ -85,7 +87,7 @@ class _ZhuanCunDialogState extends State { TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), Container(padding: EdgeInsets.only(top: 20)), Container( - width: 440, + width: 480, height: 370, alignment: Alignment.topLeft, decoration: BoxDecoration( @@ -132,7 +134,7 @@ class _ZhuanCunDialogState extends State { )), ))), Container( - width: 440, + width: 480, padding: EdgeInsets.only(top: 12), child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ UnconstrainedBox( @@ -182,8 +184,25 @@ class _ZhuanCunDialogState extends State { style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { + ArgonButton( + height: 32, + width: 220, + minWidth: 220, + borderRadius: 3.0, + roundLoadingShape: false, + color: MColors.elevatedBtnBG, + child: Text( + "转存到选中的文件夹内", + style: TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans"), + ), + loader: Container( + child: SpinKitRing( + size: 22, + lineWidth: 3, + color: Colors.white, + ), + ), + onTap: (startLoading, stopLoading, btnState) { var linkstr = '{"DirList":[],"FileList":['; int totalsize = 0; bool isadd = false; @@ -204,10 +223,11 @@ class _ZhuanCunDialogState extends State { totalsize += item.fileSize; } linkstr += '],"Name":"无","Size":' + totalsize.toString() + ',"Message":""}'; - var fcHide = Loading.showLoading(); + if (btnState == ButtonState.Busy) return; + startLoading(); Linker.goLinkUpload(movetobox, selectKey, linkstr).then((value) { - fcHide(); - Future.delayed(Duration(milliseconds: 500), () { + stopLoading(); + Future.delayed(Duration(milliseconds: 600), () { PanData.loadFileList(movetobox, selectKey, "zhuancun"); //触发联网加载 }); @@ -216,8 +236,6 @@ class _ZhuanCunDialogState extends State { BotToast.showText(text: "成功转存" + value.toString() + "个文件"); }); }, - child: Text("转存到选中的文件夹内"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), ), ]), ), @@ -321,7 +339,7 @@ class DirNode2 { hoverDecoration: hoverDecoration, child: Container( key: Key("pdt_zhuan_rchc_" + key), - width: 400 - leve * 20, + width: 440 - leve * 20, height: 24, padding: padding, child: Row(key: Key("pdt_zhuan_rchcr_" + key), children: [ @@ -329,7 +347,7 @@ class DirNode2 { padding2, Expanded( child: Text( - label, + StringUtils.joinChar(label), key: Key("pdt_zhuan_rchcrt_" + key), style: style, maxLines: 1, @@ -352,7 +370,7 @@ class DirNode2 { hoverDecoration: hoverDecorations, child: Container( key: Key("pdt_zhuan_rchc_" + key), - width: 400 - leve * 20, + width: 440 - leve * 20, height: 24, padding: padding, child: Row(key: Key("pdt_zhuan_rchcr_" + key), children: [ @@ -360,7 +378,7 @@ class DirNode2 { padding2, Expanded( child: Text( - label, + StringUtils.joinChar(label), key: Key("pdt_zhuan_rchcrt_" + key), style: styles, maxLines: 1, diff --git a/alixby/lib/states/FileState.dart b/alixby/lib/states/FileState.dart index 1da3aa0..3f19244 100644 --- a/alixby/lib/states/FileState.dart +++ b/alixby/lib/states/FileState.dart @@ -344,7 +344,7 @@ class FileState extends ChangeNotifier { var box = boxs[i]; var fileid = ids[i]; - if (name.length > 11) name = name.substring(0, 4) + "..." + name.substring(name.length - 4); + if (name.length > 15) name = name.substring(0, 6) + "..." + name.substring(name.length - 6); var link = WidgetSpan( child: Linkify( @@ -449,6 +449,10 @@ class FileState extends ChangeNotifier { } else if (pageRightFileOrderBy == "上传时间 从大到小") { pageRightFileList.sort((a, b) => b.fileTime.compareTo(a.fileTime)); filelist.sort((a, b) => b.fileTime.compareTo(a.fileTime)); + } else if (pageRightFileOrderBy == "文件类型") { + pageRightFileList.sort((a, b) => StringUtils.sortNumber1(a.title, b.title)); + filelist.sort((a, b) => StringUtils.sortNumber1(a.title, b.title)); + filelist.sort((a, b) => a.fileext.compareTo(b.fileext)); } pageRightFileList.addAll(filelist); } diff --git a/alixby/lib/states/Global.dart b/alixby/lib/states/Global.dart index dc9be35..6e4b240 100644 --- a/alixby/lib/states/Global.dart +++ b/alixby/lib/states/Global.dart @@ -25,8 +25,8 @@ class XiangCeTreeState extends TreeState { class Global { // 是否为release版 static bool get isRelease => bool.fromEnvironment("dart.vm.product"); - static String get appTitle => "阿里云盘小白羊版 v1.6.21"; - static String get appVer => "v1.6.21"; + static String get appTitle => "阿里云盘小白羊版 v1.6.29"; + static String get appVer => "v1.6.29"; static PanTreeState panTreeState = PanTreeState(); static XiangCeTreeState xiangceTreeState = XiangCeTreeState(); diff --git a/alixby/lib/states/pageRssSearchState.dart b/alixby/lib/states/pageRssSearchState.dart index da9b78d..2c23eb9 100644 --- a/alixby/lib/states/pageRssSearchState.dart +++ b/alixby/lib/states/pageRssSearchState.dart @@ -122,7 +122,7 @@ class PageRssSearchState extends ChangeNotifier { notifyListeners(); } - pageSearch(int pageindex) { + pageSearch(int pageindex, Function? stopLoading) { var txt = searchcontroller.text; if (pageindex < 1) pageindex = 1; if (pageindex > 9) pageindex = 9; @@ -132,8 +132,10 @@ class PageRssSearchState extends ChangeNotifier { pageCount = value.pageCount; fileCount = value.fileCount; _updateNavBtns(); + verticalScroll.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.easeOut); notifyListeners(); + if (stopLoading != null) stopLoading(); if (fileCount == 0) { BotToast.showText(text: "搜不到结果哦,换个关键字试试?"); } @@ -171,22 +173,23 @@ class PageRssSearchState extends ChangeNotifier { return selectKeys; } + final verticalScroll = ScrollController(); _updateNavBtns() { List list = []; if (pageCount > 0) { - list.add(Text("搜索结果分页:")); + list.add(Text("结果:")); for (var i = 1; i <= 9 && i <= pageCount; i++) { if (i == pageIndex) { list.add(OutlinedButton( child: Text(i.toString()), onPressed: () { - Global.pageRssSearchState.pageSearch(i); + Global.pageRssSearchState.pageSearch(i, null); })); } else { list.add(TextButton( child: Text(i.toString()), onPressed: () { - Global.pageRssSearchState.pageSearch(i); + Global.pageRssSearchState.pageSearch(i, null); })); } list.add(Padding(padding: EdgeInsets.only(left: 4))); diff --git a/alixby/lib/utils/MColors.dart b/alixby/lib/utils/MColors.dart index 9909243..1819cc8 100644 --- a/alixby/lib/utils/MColors.dart +++ b/alixby/lib/utils/MColors.dart @@ -81,6 +81,7 @@ class MColors { static get textColor => mcolor.textColor; static get textColorGray => mcolor.textColorGray; static get textColorRed => mcolor.textColorRed; + static get textColorYellow => mcolor.textColorYellow; } class MColorsLight { @@ -152,6 +153,7 @@ class MColorsLight { Color textColor = Color(0xee000000); Color textColorGray = Color(0xaa333333); Color textColorRed = Color(0xffeb8381); + Color textColorYellow = Color(0xfffc5531); } class MColorsDark extends MColorsLight { @@ -224,4 +226,5 @@ class MColorsDark extends MColorsLight { Color textColor = Colors.white; Color textColorGray = Color(0x99ffffff); Color textColorRed = Color(0xffeb8381); + Color textColorYellow = Color(0xfffbc02d); } diff --git a/alixby/lib/utils/SpinKitRing.dart b/alixby/lib/utils/SpinKitRing.dart new file mode 100644 index 0000000..6aba4b9 --- /dev/null +++ b/alixby/lib/utils/SpinKitRing.dart @@ -0,0 +1,114 @@ +import 'dart:math'; + +import 'package:flutter/widgets.dart'; + +class SpinKitRing extends StatefulWidget { + const SpinKitRing({ + Key? key, + required this.color, + this.lineWidth = 7.0, + this.size = 50.0, + this.duration = const Duration(milliseconds: 1200), + this.controller, + }) : super(key: key); + + final Color color; + final double size; + final double lineWidth; + final Duration duration; + final AnimationController? controller; + + @override + _SpinKitRingState createState() => _SpinKitRingState(); +} + +class _SpinKitRingState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation1; + late Animation _animation2; + late Animation _animation3; + + @override + void initState() { + super.initState(); + + _controller = (widget.controller ?? AnimationController(vsync: this, duration: widget.duration)) + ..addListener(() => setState(() {})) + ..repeat(); + _animation1 = Tween(begin: 0.0, end: 1.0) + .animate(CurvedAnimation(parent: _controller, curve: const Interval(0.0, 1.0, curve: Curves.linear))); + _animation2 = Tween(begin: -2 / 3, end: 1 / 2) + .animate(CurvedAnimation(parent: _controller, curve: const Interval(0.5, 1.0, curve: Curves.linear))); + _animation3 = Tween(begin: 0.25, end: 5 / 6) + .animate(CurvedAnimation(parent: _controller, curve: const Interval(0.0, 1.0, curve: SpinKitRingCurve()))); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: Transform( + transform: Matrix4.identity()..rotateZ((_animation1.value) * 5 * pi / 6), + alignment: FractionalOffset.center, + child: SizedBox.fromSize( + size: Size.square(widget.size), + child: CustomPaint( + foregroundPainter: RingPainter( + paintWidth: widget.lineWidth, + trackColor: widget.color, + progressPercent: _animation3.value, + startAngle: pi * _animation2.value, + ), + ), + ), + ), + ); + } +} + +class RingPainter extends CustomPainter { + RingPainter({ + required this.paintWidth, + this.progressPercent, + this.startAngle, + required this.trackColor, + }) : trackPaint = Paint() + ..color = trackColor + ..style = PaintingStyle.stroke + ..strokeWidth = paintWidth + ..strokeCap = StrokeCap.square; + + final double paintWidth; + final Paint trackPaint; + final Color trackColor; + final double? progressPercent; + final double? startAngle; + + @override + void paint(Canvas canvas, Size size) { + final center = Offset(size.width / 2, size.height / 2); + final radius = (min(size.width, size.height) - paintWidth) / 2; + canvas.drawArc( + Rect.fromCircle(center: center, radius: radius), + startAngle!, + 2 * pi * progressPercent!, + false, + trackPaint, + ); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => true; +} + +class SpinKitRingCurve extends Curve { + const SpinKitRingCurve(); + + @override + double transform(double t) => (t <= 0.5) ? 2 * t : 2 * (1 - t); +} diff --git a/alixby/lib/utils/SpinKitRotatingCircle.dart b/alixby/lib/utils/SpinKitRotatingCircle.dart new file mode 100644 index 0000000..3a4763a --- /dev/null +++ b/alixby/lib/utils/SpinKitRotatingCircle.dart @@ -0,0 +1,65 @@ +import 'package:flutter/widgets.dart'; + +class SpinKitRotatingCircle extends StatefulWidget { + const SpinKitRotatingCircle({ + Key? key, + this.color, + this.size = 50.0, + this.itemBuilder, + this.duration = const Duration(milliseconds: 1200), + this.controller, + }) : assert(!(itemBuilder is IndexedWidgetBuilder && color is Color) && !(itemBuilder == null && color == null), + 'You should specify either a itemBuilder or a color'), + super(key: key); + + final Color? color; + final double size; + final IndexedWidgetBuilder? itemBuilder; + final Duration duration; + final AnimationController? controller; + + @override + _SpinKitRotatingCircleState createState() => _SpinKitRotatingCircleState(); +} + +class _SpinKitRotatingCircleState extends State with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation1; + late Animation _animation2; + + @override + void initState() { + super.initState(); + + _controller = (widget.controller ?? AnimationController(vsync: this, duration: widget.duration)) + ..addListener(() => setState(() {})) + ..repeat(); + _animation1 = Tween(begin: 0.0, end: 180.0) + .animate(CurvedAnimation(parent: _controller, curve: const Interval(0.0, 0.5, curve: Curves.easeIn))); + _animation2 = Tween(begin: 0.0, end: 180.0) + .animate(CurvedAnimation(parent: _controller, curve: const Interval(0.5, 1.0, curve: Curves.easeOut))); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: Transform( + transform: Matrix4.identity() + ..rotateX((0 - _animation1.value) * 0.0174533) + ..rotateY((0 - _animation2.value) * 0.0174533), + alignment: FractionalOffset.center, + child: SizedBox.fromSize(size: Size.square(widget.size), child: _itemBuilder(0)), + ), + ); + } + + Widget _itemBuilder(int index) => widget.itemBuilder != null + ? widget.itemBuilder!(context, index) + : DecoratedBox(decoration: BoxDecoration(color: widget.color, shape: BoxShape.circle)); +} diff --git a/alixby/lib/utils/StringUtils.dart b/alixby/lib/utils/StringUtils.dart index fa82e2f..7fc4413 100644 --- a/alixby/lib/utils/StringUtils.dart +++ b/alixby/lib/utils/StringUtils.dart @@ -1,5 +1,7 @@ import 'dart:math'; +import 'package:flutter/widgets.dart'; + class StringUtils { StringUtils(); @@ -52,6 +54,10 @@ class StringUtils { return info; } + static String joinChar(String str) { + return Characters(str).replaceAll(Characters(''), Characters('\u{200B}')).toString(); + } + static int sortNumber1(String a, String b) { RegExp exp = new RegExp(r"[0-9]+"); var aNums = exp.allMatches(a); diff --git a/alixby/lib/views/PageRightSetting.dart b/alixby/lib/views/PageRightSetting.dart index 9fc3c12..0b87f9c 100644 --- a/alixby/lib/views/PageRightSetting.dart +++ b/alixby/lib/views/PageRightSetting.dart @@ -291,6 +291,7 @@ class _PageRightSettingState extends State with AutomaticKeepA label: Text('保存'), onPressed: () { Global.settingState.downSpeed(Global.settingState.downSpeedController.text); + BotToast.showText(text: "设置已保存"); }))), ], ), diff --git a/alixby/pubspec.yaml b/alixby/pubspec.yaml index c051d38..ab5788d 100644 --- a/alixby/pubspec.yaml +++ b/alixby/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.21 +version: 1.6.29 environment: sdk: ">=2.12.0 <3.0.0" @@ -39,10 +39,11 @@ dependencies: url_launcher: ^6.0.3 file_selector: ^0.8.2 file_selector_windows: ^0.0.2 - gradient_widgets: ^0.6.0 extended_image: ^4.1.0 styled_text: ^3.0.1 dropfiles_window: ^0.0.2 + percent_indicator: ^3.0.1 + argon_buttons_flutter: ^1.1.0 dev_dependencies: flutter_test: sdk: flutter diff --git a/changelog.txt b/changelog.txt index 059c315..f343e5c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,11 @@ +#### 2021/06/29 +Fix 优化重命名、搜索输入框大小 +Fix 修正下载中、上传中页面因进度条动画导致的GPU占用过高的BUG +Fix 中文名导致偶有macos启动失败的BUG +Add 导入阿里云盘分享链接的功能 +Add 导入115网盘分享链接的功能 + + #### 2021/06/21 Fix 显示用户昵称和头像 Fix 完善对字体的支持(可以随意更换自己喜欢的字体了),完善文字大小设置功能