diff --git a/aliserver/aliyun/ApiFile.go b/aliserver/aliyun/ApiFile.go index 10aba3c..7f61505 100644 --- a/aliserver/aliyun/ApiFile.go +++ b/aliserver/aliyun/ApiFile.go @@ -24,17 +24,17 @@ type FileItemModel struct { P_file_icon string `json:"file_icon"` } -func ApiFileList(parentid string, marker string) (retjsonstr string) { +func ApiFileList(boxid string, parentid string, marker string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiFileListError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("next_marker", "", "items", "[]") + retjsonstr = `{"code":503,"message":"error","next_marker":"","items":[]}` } }() var apiurl = "https://api.aliyundrive.com/v2/file/list" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "parent_file_id": parentid, "limit": 100, "all": false, @@ -59,7 +59,7 @@ func ApiFileList(parentid string, marker string) (retjsonstr string) { code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) } if code != 200 || !gjson.Valid(body) { - return utils.ToSuccessJSON2("next_marker", "", "items", "[]") + return `{"code":503,"message":"error","next_marker":"","items":[]}` } info := gjson.Parse(body) next_marker := info.Get("next_marker").String() @@ -91,7 +91,7 @@ func ApiFileList(parentid string, marker string) (retjsonstr 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", ext) > 0 { + 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 { @@ -99,7 +99,10 @@ func ApiFileList(parentid string, marker string) (retjsonstr string) { } } } - if file_icon != "folder" && file_icon != "image" && file_icon != "video" && file_icon != "audio" && 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() @@ -140,17 +143,17 @@ func ApiFileList(parentid string, marker string) (retjsonstr string) { return builder.String() } -func ApiDirList(parentid string) (retjsonstr string) { +func ApiDirList(boxid string, parentid string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiDirListError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("next_marker", "", "items", "[]") + retjsonstr = `{"code":503,"message":"error","next_marker":"","items":[]}` } }() var apiurl = "https://api.aliyundrive.com/v2/file/list" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "parent_file_id": parentid, "limit": 100, "all": false, @@ -172,7 +175,7 @@ func ApiDirList(parentid string) (retjsonstr string) { code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) } if code != 200 || !gjson.Valid(body) { - return utils.ToSuccessJSON2("next_marker", "", "items", "[]") + return `{"code":503,"message":"error","next_marker":"","items":[]}` } info := gjson.Parse(body) next_marker := info.Get("next_marker").String() @@ -225,20 +228,20 @@ func ApiDirList(parentid string) (retjsonstr string) { builder.WriteString(`]}`) return builder.String() } -func ApiFavorFileList(marker string) (retjsonstr string) { +func ApiFavorFileList(boxid string, marker string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiFileListError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("next_marker", "", "items", "[]") + retjsonstr = `{"code":503,"message":"error","next_marker":"","items":[]}` } }() //https://api.aliyundrive.com/v2/file/list_by_custom_index_key - //{"custom_index_key":"starred_yes","parent_file_id":"root","drive_id":"8699982","fields":"*","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"} + //{"custom_index_key":"starred_yes","parent_file_id":"root","drive_id":"9999999","fields":"*","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_by_custom_index_key" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "custom_index_key": "starred_yes", "parent_file_id": "root", "limit": 100, @@ -263,7 +266,7 @@ func ApiFavorFileList(marker string) (retjsonstr string) { code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) } if code != 200 || !gjson.Valid(body) { - return utils.ToSuccessJSON2("next_marker", "", "items", "[]") + return `{"code":503,"message":"error","next_marker":"","items":[]}` } info := gjson.Parse(body) next_marker := info.Get("next_marker").String() @@ -295,7 +298,7 @@ func ApiFavorFileList(marker string) (retjsonstr string) { 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", ext) > 0 { + 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 { @@ -303,6 +306,13 @@ func ApiFavorFileList(marker string) (retjsonstr string) { } } } + 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" @@ -340,19 +350,19 @@ func ApiFavorFileList(marker string) (retjsonstr string) { builder.WriteString(`]}`) return builder.String() } -func ApiTrashFileList(marker string) (retjsonstr string) { +func ApiTrashFileList(boxid string, marker string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiTrashFileListError ", " error=", errr) - retjsonstr = utils.ToSuccessJSON2("next_marker", "", "items", "[]") + retjsonstr = `{"code":503,"message":"error","next_marker":"","items":[]}` } }() //https://api.aliyundrive.com/v2/recyclebin/list - //{"drive_id":"8699982","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"} + //{"drive_id":"9999999","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/recyclebin/list" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "limit": 100, "fields": "thumbnail", "order_by": "name", @@ -375,7 +385,7 @@ func ApiTrashFileList(marker string) (retjsonstr string) { code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) } if code != 200 || !gjson.Valid(body) { - return utils.ToSuccessJSON2("next_marker", "", "items", "[]") + return `{"code":503,"message":"error","next_marker":"","items":[]}` } info := gjson.Parse(body) next_marker := info.Get("next_marker").String() @@ -404,10 +414,9 @@ func ApiTrashFileList(marker string) (retjsonstr string) { 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", ext) > 0 { + 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 { @@ -415,6 +424,12 @@ func ApiTrashFileList(marker string) (retjsonstr string) { } } } + 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 { @@ -454,7 +469,7 @@ func ApiTrashFileList(marker string) (retjsonstr string) { return builder.String() } -func ApiCreatForder(parentid string, name string) (retjsonstr string) { +func ApiCreatForder(boxid string, parentid string, name string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiCreatForderError ", " error=", errr) @@ -463,7 +478,7 @@ func ApiCreatForder(parentid string, name string) (retjsonstr string) { }() var apiurl = "https://api.aliyundrive.com/v2/file/create" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "parent_file_id": parentid, "name": name, "check_name_mode": "refuse", @@ -491,7 +506,134 @@ func ApiCreatForder(parentid string, name string) (retjsonstr string) { return utils.ToSuccessJSON2("file_id", file_id, "file_name", file_name) } -func ApiRename(file_id string, name string) (retjsonstr string) { +func ApiUncompress(boxid string, file_id string, target_file_id string, password string) (retjsonstr string) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiUncompressError ", " error=", errr) + retjsonstr = utils.ToErrorMessageJSON("解压缩失败:程序出错") + } + }() + + var apiurl = "https://api.aliyundrive.com/v2/file/get" + + 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) + } + if code != 200 || !gjson.Valid(body) { + return utils.ToErrorMessageJSON("获取文件信息失败") + } + info := gjson.Parse(body) + domain_id := info.Get("domain_id").String() + drive_id := info.Get("drive_id").String() + file_extension := info.Get("file_extension").String() + apiurl = "https://api.aliyundrive.com/v2/archive/uncompress" + //{"drive_id":"9999999","file_id":"60c4caff927ef76afef1454e9ac6b5d57ec9d1e1","domain_id":"bj29","target_drive_id":"9999999","target_file_id":"60c3462fb1abcdd8c6e54de69843a26155e069c7","archive_type":"rar","password":"123456"} + //202 {"state":"Running","task_id":"666ccf683eb915b372c82126cb2b4e90"} + //403 {"code":"InvalidPassword","message":"Password is invalid"} + postjson = map[string]interface{}{"drive_id": drive_id, + "file_id": file_id, + "domain_id": domain_id, + "target_drive_id": drive_id, //只支持保存在网盘内,不支持保险箱 + "target_file_id": target_file_id, + "archive_type": file_extension} + 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) + } + if code != 202 && code != 400 && code != 500 || !gjson.Valid(body) { //注意这里是202 + return utils.ToErrorMessageJSON("创建解压缩任务失败") + } + info = gjson.Parse(body) + if info.Get("state").Exists() { + state := info.Get("state").String() + task_id := info.Get("task_id").String() + return utils.ToSuccessJSON4("state", state, "task_id", task_id, "domain_id", domain_id, "file_id", file_id) + } else { + message := info.Get("message").String() + if message == "Password is invalid" { + message = "解压密码错误" + } + if strings.Index(message, "ArchiveTypeNotSupported") > 0 { + message = "不支持解压" + file_extension + } + if strings.Index(message, "some unknown error") > 0 { + message = "解压时发生未知错误无法解压" + } + return utils.ToErrorMessageJSON("解压缩失败:" + message) + } +} + +func ApiUncompressCheck(boxid string, domain_id, file_id, task_id string) (retjsonstr string) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiUncompressCheckError ", " error=", errr) + retjsonstr = utils.ToErrorMessageJSON("获取解压进度失败") + } + }() + + var apiurl = "https://api.aliyundrive.com/v2/archive/status" + //{"drive_id":"9999999","domain_id":"bj29","file_id":"60c4ca099c494a23bae74349a7396c270b354c20","task_id":"220812f78dbd8375a7cad6d9c46102ef"} + //200 {"state":"Running","file_list":{},"task_id":"220812f78dbd8375a7cad6d9c46102ef","progress":0} + + var postjson = map[string]interface{}{"drive_id": boxid, + "domain_id": domain_id, + "file_id": file_id, + "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) + } + if code != 200 && code != 400 && code != 500 || !gjson.Valid(body) { + return utils.ToErrorMessageJSON("获取解压缩进度失败") + } + info := gjson.Parse(body) + + if info.Get("state").Exists() { + state := info.Get("state").String() + progress := info.Get("progress").Int() + return utils.ToSuccessJSON4("state", state, "progress", progress, "task_id", task_id, "file_id", file_id) + } else { + message := info.Get("message").String() + if message == "Password is invalid" { + message = "解压密码错误" + } + if strings.Index(message, "some unknown error") > 0 { + message = "解压时发生未知错误无法解压" + } + return utils.ToErrorMessageJSON("解压缩失败:" + message) + } +} + +//https://api.aliyundrive.com/v2/archive/uncompress + +func ApiRename(boxid string, file_id string, name string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiRenameError ", " error=", errr) @@ -499,10 +641,10 @@ func ApiRename(file_id string, name string) (retjsonstr string) { } }() //https://api.aliyundrive.com/v2/file/update - //{"drive_id":"8699982","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","name":"ffffff222","check_name_mode":"refuse"} + //{"drive_id":"9999999","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","name":"ffffff222","check_name_mode":"refuse"} var apiurl = "https://api.aliyundrive.com/v2/file/update" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id, "name": name, "check_name_mode": "refuse"} @@ -528,8 +670,43 @@ func ApiRename(file_id string, name string) (retjsonstr string) { } return utils.ToSuccessJSON2("file_id", file_id, "file_name", file_name) } +func ApiRenameBatch(boxid string, keylist []string, namelist []string) (retjsonstr string) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiRenameBatchError ", " error=", errr) + retjsonstr = utils.ToSuccessJSON2("count", 0, "error", len(keylist)) + } + }() + //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"9999999","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} + //https://api.aliyundrive.com/v2/batch {"requests":[{"body":{"drive_id":"9999999","file_id":"60a9276610ca470f2289432cada6e8336ba81e4a"},"headers":{"Content-Type":"application/json"},"id":"60a9276610ca470f2289432cada6e8336ba81e4a","method":"POST","url":"/recyclebin/trash"},{"body":{"drive_id":"9999999","file_id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878"},"headers":{"Content-Type":"application/json"},"id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878","method":"POST","url":"/recyclebin/trash"}],"resource":"file"} + //删除文件是204 删除文件夹是202 + + var postdata = `{"requests":[` + var max = len(keylist) - 1 + var add = 0 + + var blist = make([]string, 0) + for i := 0; i < len(keylist); i++ { + postdata += `{"body":{"drive_id":"` + boxid + `","file_id":"` + keylist[i] + `","name":"` + utils.ToJSONString(namelist[i]) + `","check_name_mode":"refuse"},"headers":{"Content-Type":"application/json"},"id":"` + keylist[i] + `","method":"POST","url":"/file/update"}` + 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("count", count, "error", len(keylist)-int(count)) +} -func ApiFavor(file_id string, isfavor bool) (retjsonstr string) { +func ApiFavor(boxid string, file_id string, isfavor bool) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiFavorError ", " error=", errr) @@ -537,17 +714,17 @@ func ApiFavor(file_id string, isfavor bool) (retjsonstr string) { } }() //https://api.aliyundrive.com/v2/file/update - //收藏{"custom_index_key":"starred_yes","drive_id":"8699982","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","starred":true} - //取消收藏{"custom_index_key":"","drive_id":"8699982","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","starred":false} + //收藏{"custom_index_key":"starred_yes","drive_id":"9999999","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","starred":true} + //取消收藏{"custom_index_key":"","drive_id":"9999999","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","starred":false} var apiurl = "https://api.aliyundrive.com/v2/file/update" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "custom_index_key": "starred_yes", "file_id": file_id, "starred": true} if !isfavor { - postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + postjson = map[string]interface{}{"drive_id": boxid, "custom_index_key": "", "file_id": file_id, "starred": false} @@ -574,15 +751,15 @@ func ApiFavor(file_id string, isfavor bool) (retjsonstr string) { } return utils.ToSuccessJSON2("file_id", file_id, "file_name", file_name) } -func ApiTrashBatch(filelist []string) (retjsonstr string) { +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)) } }() - //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"8699982","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} - //https://api.aliyundrive.com/v2/batch {"requests":[{"body":{"drive_id":"8699982","file_id":"60a9276610ca470f2289432cada6e8336ba81e4a"},"headers":{"Content-Type":"application/json"},"id":"60a9276610ca470f2289432cada6e8336ba81e4a","method":"POST","url":"/recyclebin/trash"},{"body":{"drive_id":"8699982","file_id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878"},"headers":{"Content-Type":"application/json"},"id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878","method":"POST","url":"/recyclebin/trash"}],"resource":"file"} + //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"9999999","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} + //https://api.aliyundrive.com/v2/batch {"requests":[{"body":{"drive_id":"9999999","file_id":"60a9276610ca470f2289432cada6e8336ba81e4a"},"headers":{"Content-Type":"application/json"},"id":"60a9276610ca470f2289432cada6e8336ba81e4a","method":"POST","url":"/recyclebin/trash"},{"body":{"drive_id":"9999999","file_id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878"},"headers":{"Content-Type":"application/json"},"id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878","method":"POST","url":"/recyclebin/trash"}],"resource":"file"} //删除文件是204 删除文件夹是202 var postdata = `{"requests":[` @@ -591,7 +768,7 @@ func ApiTrashBatch(filelist []string) (retjsonstr string) { var blist = make([]string, 0) for i := 0; i < len(filelist); i++ { - postdata += `{"body":{"drive_id":"` + _user.UserToken.P_default_drive_id + `","file_id":"` + filelist[i] + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/recyclebin/trash"}` + postdata += `{"body":{"drive_id":"` + boxid + `","file_id":"` + filelist[i] + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/recyclebin/trash"}` add++ if add == 90 && i < max { postdata += `],"resource":"file"}` @@ -610,15 +787,15 @@ func ApiTrashBatch(filelist []string) (retjsonstr string) { return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) } -func ApiFavorBatch(filelist []string, isfavor bool) (retjsonstr string) { +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)) } }() - //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"8699982","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} - //https://api.aliyundrive.com/v2/batch {"requests":[{"body":{"drive_id":"8699982","file_id":"60a9276610ca470f2289432cada6e8336ba81e4a"},"headers":{"Content-Type":"application/json"},"id":"60a9276610ca470f2289432cada6e8336ba81e4a","method":"POST","url":"/recyclebin/trash"},{"body":{"drive_id":"8699982","file_id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878"},"headers":{"Content-Type":"application/json"},"id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878","method":"POST","url":"/recyclebin/trash"}],"resource":"file"} + //https://api.aliyundrive.com/v2/recyclebin/trash {"drive_id":"9999999","file_id":"60a92692849dfed0c585482fa71aecd2e790ba64"} + //https://api.aliyundrive.com/v2/batch {"requests":[{"body":{"drive_id":"9999999","file_id":"60a9276610ca470f2289432cada6e8336ba81e4a"},"headers":{"Content-Type":"application/json"},"id":"60a9276610ca470f2289432cada6e8336ba81e4a","method":"POST","url":"/recyclebin/trash"},{"body":{"drive_id":"9999999","file_id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878"},"headers":{"Content-Type":"application/json"},"id":"60a9275b7a25fc02f7e84f5ca170d8b0fc030878","method":"POST","url":"/recyclebin/trash"}],"resource":"file"} //返回200 var postdata = `{"requests":[` @@ -628,9 +805,9 @@ func ApiFavorBatch(filelist []string, isfavor bool) (retjsonstr string) { var blist = make([]string, 0) for i := 0; i < len(filelist); i++ { - var favdata = `{"body":{"drive_id":"` + _user.UserToken.P_default_drive_id + `","file_id":"` + filelist[i] + `","custom_index_key":"starred_yes","starred":true},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/update"}` + var favdata = `{"body":{"drive_id":"` + boxid + `","file_id":"` + filelist[i] + `","custom_index_key":"starred_yes","starred":true},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/update"}` if !isfavor { - favdata = `{"body":{"drive_id":"` + _user.UserToken.P_default_drive_id + `","file_id":"` + filelist[i] + `","custom_index_key":"","starred":false},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/update"}` + favdata = `{"body":{"drive_id":"` + boxid + `","file_id":"` + filelist[i] + `","custom_index_key":"","starred":false},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/update"}` } postdata += favdata add++ @@ -651,7 +828,7 @@ func ApiFavorBatch(filelist []string, isfavor bool) (retjsonstr string) { return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) } -func ApiMoveBatch(movetoid string, filelist []string) (retjsonstr string) { +func ApiMoveBatch(boxid string, filelist []string, movetobox, movetoid string) (retjsonstr string) { defer func() { if errr := recover(); errr != nil { log.Println("ApiMoveBatchError ", " error=", errr) @@ -659,7 +836,7 @@ func ApiMoveBatch(movetoid string, filelist []string) (retjsonstr string) { } }() //https://api.aliyundrive.com/v2/batch - //{"requests":[{"body":{"drive_id":"8699982","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","to_parent_file_id":"60a937763fb6e0e751004ffcb1bb5168bd490ae4"},"headers":{"Content-Type":"application/json"},"id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","method":"POST","url":"/file/move"}],"resource":"file"} + //{"requests":[{"body":{"drive_id":"9999999","file_id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","to_parent_file_id":"60a937763fb6e0e751004ffcb1bb5168bd490ae4"},"headers":{"Content-Type":"application/json"},"id":"60a9265d37316002699a4d7285d2aa9ced3b6d2c","method":"POST","url":"/file/move"}],"resource":"file"} //移动文件 返回值200 var postdata = `{"requests":[` @@ -668,7 +845,11 @@ func ApiMoveBatch(movetoid string, filelist []string) (retjsonstr string) { var blist = make([]string, 0) for i := 0; i < len(filelist); i++ { - postdata += `{"body":{"drive_id":"` + _user.UserToken.P_default_drive_id + `","file_id":"` + filelist[i] + `","to_parent_file_id":"` + movetoid + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/move"}` + if boxid == movetobox { + postdata += `{"body":{"drive_id":"` + boxid + `","file_id":"` + filelist[i] + `","to_parent_file_id":"` + movetoid + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/move"}` + } else { + postdata += `{"body":{"drive_id":"` + boxid + `","file_id":"` + filelist[i] + `","to_drive_id":"` + movetobox + `","to_parent_file_id":"` + movetoid + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/move"}` + } add++ if add == 90 && i < max { postdata += `],"resource":"file"}` @@ -687,14 +868,14 @@ func ApiMoveBatch(movetoid string, filelist []string) (retjsonstr string) { return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) } -func ApiTrashDeleteBatch(filelist []string) (retjsonstr string) { +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)) } }() - //{"requests":[{"body":{"drive_id":"8699982","file_id":"60a5bb43bf60766feada4eca9d0da23a501eb7c8"},"headers":{"Content-Type":"application/json"},"id":"60a5bb43bf60766feada4eca9d0da23a501eb7c8","method":"POST","url":"/file/delete"}],"resource":"file"} + //{"requests":[{"body":{"drive_id":"9999999","file_id":"60a5bb43bf60766feada4eca9d0da23a501eb7c8"},"headers":{"Content-Type":"application/json"},"id":"60a5bb43bf60766feada4eca9d0da23a501eb7c8","method":"POST","url":"/file/delete"}],"resource":"file"} //彻底删除返回204 202 var postdata = `{"requests":[` @@ -703,7 +884,7 @@ func ApiTrashDeleteBatch(filelist []string) (retjsonstr string) { var blist = make([]string, 0) for i := 0; i < len(filelist); i++ { - postdata += `{"body":{"drive_id":"` + _user.UserToken.P_default_drive_id + `","file_id":"` + filelist[i] + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/delete"}` + postdata += `{"body":{"drive_id":"` + boxid + `","file_id":"` + filelist[i] + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/file/delete"}` add++ if add == 90 && i < max { postdata += `],"resource":"file"}` @@ -721,14 +902,14 @@ func ApiTrashDeleteBatch(filelist []string) (retjsonstr string) { return utils.ToSuccessJSON2("count", count, "error", len(filelist)-int(count)) } -func ApiTrashRestoreBatch(filelist []string) (retjsonstr string) { +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)) } }() - //{"requests":[{"body":{"drive_id":"8699982","file_id":"60a5bb4394b2ad243fb84509a576506afc890397"},"headers":{"Content-Type":"application/json"},"id":"60a5bb4394b2ad243fb84509a576506afc890397","method":"POST","url":"/recyclebin/restore"}],"resource":"file"} + //{"requests":[{"body":{"drive_id":"9999999","file_id":"60a5bb4394b2ad243fb84509a576506afc890397"},"headers":{"Content-Type":"application/json"},"id":"60a5bb4394b2ad243fb84509a576506afc890397","method":"POST","url":"/recyclebin/restore"}],"resource":"file"} //恢复文件返回204 202 var postdata = `{"requests":[` @@ -737,7 +918,7 @@ func ApiTrashRestoreBatch(filelist []string) (retjsonstr string) { var blist = make([]string, 0) for i := 0; i < len(filelist); i++ { - postdata += `{"body":{"drive_id":"` + _user.UserToken.P_default_drive_id + `","file_id":"` + filelist[i] + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/recyclebin/restore"}` + postdata += `{"body":{"drive_id":"` + boxid + `","file_id":"` + filelist[i] + `"},"headers":{"Content-Type":"application/json"},"id":"` + filelist[i] + `","method":"POST","url":"/recyclebin/restore"}` add++ if add == 90 && i < max { postdata += `],"resource":"file"}` diff --git a/aliserver/aliyun/ApiFileDown.go b/aliserver/aliyun/ApiFileDown.go index 678fbab..4af159f 100644 --- a/aliserver/aliyun/ApiFileDown.go +++ b/aliserver/aliyun/ApiFileDown.go @@ -22,7 +22,7 @@ type FileUrlModel struct { //文件相对路径 P_file_path string `json:"path"` //P_url string `json:"url"` - //P_domain_id string `json:"domain_id"` + P_drive_id string `json:"drive_id"` //P_crc64_hash string `json:"crc64_hash"` P_sha1 string `json:"sha1"` P_size int64 `json:"size"` @@ -30,7 +30,7 @@ type FileUrlModel struct { IsDir bool } -func ApiFileDownloadUrl(file_id string, expire_sec int) (downurl string, size int64, err error) { +func ApiFileDownloadUrl(boxid string, file_id string, expire_sec int) (downurl string, size int64, err error) { defer func() { if errr := recover(); errr != nil { log.Println("ApiFileDownloadUrlError ", " error=", errr) @@ -39,7 +39,7 @@ func ApiFileDownloadUrl(file_id string, expire_sec int) (downurl string, size in }() var apiurl = "https://api.aliyundrive.com/v2/file/get_download_url" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id, "expire_sec": expire_sec, } @@ -61,15 +61,16 @@ func ApiFileDownloadUrl(file_id string, expire_sec int) (downurl string, size in return "", 0, errors.New("error") } info := gjson.Parse(body) - url := info.Get("url").String() + //url := info.Get("internal_url").String() //internal_url url + url := info.Get("url").String() //internal_url url size = info.Get("size").Int() return url, size, nil } //ApiFileGetUrl 读取一个文件的信息 -func ApiFileGetUrl(file_id string, parentpath string) (urlinfo FileUrlModel, err error) { +func ApiFileGetUrl(boxid string, file_id string, parentpath string) (urlinfo FileUrlModel, err error) { //https://api.aliyundrive.com/v2/file/get - //{"drive_id":"8699982","file_id":"60a521893abc43ae8386480788b1016a214724ac"} + //{"drive_id":"9999999","file_id":"60a521893abc43ae8386480788b1016a214724ac"} //download_url url 15分钟有效 defer func() { if errr := recover(); errr != nil { @@ -80,7 +81,7 @@ func ApiFileGetUrl(file_id string, parentpath string) (urlinfo FileUrlModel, err var apiurl = "https://api.aliyundrive.com/v2/file/get" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} b, _ := json.Marshal(postjson) @@ -120,17 +121,17 @@ func ApiFileGetUrl(file_id string, parentpath string) (urlinfo FileUrlModel, err if info.Get("thumbnail").Exists() && strings.Index(info.Get("thumbnail").String(), "illegal_thumbnail") > 0 { size = 9560 //违规视频大小 } - return FileUrlModel{P_file_id: file_id, P_file_path: parentpath, P_file_name: name, P_sha1: content_hash, P_size: size, IsUrl: true, IsDir: false}, nil + return FileUrlModel{P_drive_id: boxid, P_file_id: file_id, P_file_path: parentpath, P_file_name: name, P_sha1: content_hash, P_size: size, IsUrl: true, IsDir: false}, nil } else { - return FileUrlModel{P_file_id: file_id, P_file_path: parentpath, P_file_name: name, IsUrl: false, IsDir: true}, nil + return FileUrlModel{P_drive_id: boxid, P_file_id: file_id, P_file_path: parentpath, P_file_name: name, IsUrl: false, IsDir: true}, nil } } //ApiFileListAllForDown 读取一个文件夹包含的文件列表 isfull==true时遍历所有子文件夹 -func ApiFileListAllForDown(parentid string, parentpath string, isfull bool) (list []*FileUrlModel, err error) { +func ApiFileListAllForDown(boxid string, parentid string, parentpath string, isfull bool) (list []*FileUrlModel, err error) { for i := 0; i < 3; i++ { var list []*FileUrlModel - list, err := _ApiFileListAllForDown(parentid, parentpath, isfull) + list, err := _ApiFileListAllForDown(boxid, parentid, parentpath, isfull) if err == nil { return list, nil } @@ -139,7 +140,7 @@ func ApiFileListAllForDown(parentid string, parentpath string, isfull bool) (lis } //_ApiFileListAllForDown 读取一个文件夹包含的文件列表 isfull==true时遍历所有子文件夹 -func _ApiFileListAllForDown(parentid string, parentpath string, isfull bool) (list []*FileUrlModel, err error) { +func _ApiFileListAllForDown(boxid string, parentid string, parentpath string, isfull bool) (list []*FileUrlModel, err error) { defer func() { if errr := recover(); errr != nil { log.Println("_ApiFileListAllForDownError ", " error=", errr) @@ -148,7 +149,7 @@ func _ApiFileListAllForDown(parentid string, parentpath string, isfull bool) (li }() var marker = "" for { - flist, next, ferr := ApiFileListUrl(parentid, parentpath, marker) + flist, next, ferr := ApiFileListUrl(boxid, parentid, parentpath, marker) if ferr != nil { return nil, errors.New("error") //有错误直接退出 } @@ -169,7 +170,7 @@ func _ApiFileListAllForDown(parentid string, parentpath string, isfull bool) (li if list[i].IsDir { wg.Add(1) go func(i int) { - rlist, rerr := ApiFileListAllForDown(list[i].P_file_id, list[i].P_file_path+"/"+list[i].P_file_name, true) + rlist, rerr := ApiFileListAllForDown(boxid, list[i].P_file_id, list[i].P_file_path+"/"+list[i].P_file_name, true) //注意这里,如果子文件夹遍历时出错了,直接退出,确保要么全部成功,要么全部失败,不丢失 if rerr != nil { errnum++ @@ -191,10 +192,10 @@ func _ApiFileListAllForDown(parentid string, parentpath string, isfull bool) (li } //ApiFileListUrl 真的读取子文件列表,不能有catch,出错要直接崩溃,上级调用会catch -func ApiFileListUrl(parentid string, parentpath string, marker string) (list []*FileUrlModel, next_marker string, err error) { +func ApiFileListUrl(boxid string, parentid string, parentpath string, marker string) (list []*FileUrlModel, next_marker string, err error) { var apiurl = "https://api.aliyundrive.com/v2/file/list" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "parent_file_id": parentid, "limit": 100, "all": false, @@ -250,9 +251,9 @@ func ApiFileListUrl(parentid string, parentpath string, marker string) (list []* size = 9560 //违规视频大小 } - list = append(list, &FileUrlModel{P_file_id: file_id, P_file_path: parentpath, P_file_name: name, P_sha1: content_hash, P_size: size, IsUrl: true, IsDir: false}) + list = append(list, &FileUrlModel{P_drive_id: boxid, P_file_id: file_id, P_file_path: parentpath, P_file_name: name, P_sha1: content_hash, P_size: size, IsUrl: true, IsDir: false}) } else { - list = append(list, &FileUrlModel{P_file_id: file_id, P_file_path: parentpath, P_file_name: name, IsUrl: false, IsDir: true}) + list = append(list, &FileUrlModel{P_drive_id: boxid, P_file_id: file_id, P_file_path: parentpath, P_file_name: name, IsUrl: false, IsDir: true}) } } @@ -260,7 +261,7 @@ func ApiFileListUrl(parentid string, parentpath string, marker string) (list []* } //ApiPlay 调用本地播放器 -func ApiPlay(file_id string) string { +func ApiPlay(boxid string, file_id string) string { defer func() { if errr := recover(); errr != nil { log.Println("ApiPlayError ", " error=", errr) @@ -282,7 +283,7 @@ func ApiPlay(file_id string) string { mpvpath = "mpv" } - downurl, _, err := ApiFileDownloadUrl(file_id, 60*60*4) + downurl, _, err := ApiFileDownloadUrl(boxid, file_id, 60*60*3) if err != nil { return utils.ToErrorMessageJSON("获取视频链接失败") } @@ -296,7 +297,7 @@ func ApiPlay(file_id string) string { } //ApiImage 在线预览图片 -func ApiImage(file_id string) string { +func ApiImage(boxid string, file_id string) string { defer func() { if errr := recover(); errr != nil { log.Println("ApiImageError ", " error=", errr) @@ -305,7 +306,7 @@ func ApiImage(file_id string) string { var apiurl = "https://api.aliyundrive.com/v2/file/get" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} b, _ := json.Marshal(postjson) @@ -337,7 +338,7 @@ func ApiImage(file_id string) string { } //ApiText 在线预览文本 -func ApiText(file_id string) string { +func ApiText(boxid string, file_id string) string { defer func() { if errr := recover(); errr != nil { log.Println("ApiTextError ", " error=", errr) @@ -346,7 +347,7 @@ func ApiText(file_id string) string { var apiurl = "https://api.aliyundrive.com/v2/file/get" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} b, _ := json.Marshal(postjson) @@ -373,45 +374,50 @@ func ApiText(file_id string) string { return utils.ToErrorMessageJSON("获取文本链接失败") } bodybs := *bodybs1 - if bodybs[0] == 0xFF && bodybs[1] == 0xFE { - conbs, err := utils.UTF16LEToUtf8(bodybs) - if err == nil { - bodybs = conbs - } - } else if bodybs[0] == 0xFE && bodybs[1] == 0xFF { - conbs, err := utils.UTF16BEToUtf8(bodybs) - if err == nil { - bodybs = conbs - } - } else if bodybs[0] == 0xEF && bodybs[1] == 0xBB && bodybs[2] == 0xBF { - //utf8 - } else { - plist := chardet.Possible(bodybs) - if utils.IsContain(plist, "utf-8") { - //utf8 - } else if utils.IsContain(plist, "gb18030") { - conbs, err := utils.GB18030ToUtf8(bodybs) + if len(bodybs) > 0 { + if bodybs[0] == 0xFF && bodybs[1] == 0xFE { + conbs, err := utils.UTF16LEToUtf8(bodybs) if err == nil { bodybs = conbs } - } else if utils.IsContain(plist, "gbk") { - conbs, err := utils.GbkToUtf8(bodybs) + } else if bodybs[0] == 0xFE && bodybs[1] == 0xFF { + conbs, err := utils.UTF16BEToUtf8(bodybs) if err == nil { bodybs = conbs } - } else if utils.IsContain(plist, "big5") { - conbs, err := utils.Big5ToUtf8(bodybs) - if err == nil { - bodybs = conbs + } else if bodybs[0] == 0xEF && bodybs[1] == 0xBB && bodybs[2] == 0xBF { + //utf8 + } else { + plist := chardet.Possible(bodybs) + if utils.IsContain(plist, "utf-8") { + //utf8 + } else if utils.IsContain(plist, "gb18030") { + conbs, err := utils.GB18030ToUtf8(bodybs) + if err == nil { + bodybs = conbs + } + } else if utils.IsContain(plist, "gbk") { + conbs, err := utils.GbkToUtf8(bodybs) + if err == nil { + bodybs = conbs + } + } else if utils.IsContain(plist, "big5") { + conbs, err := utils.Big5ToUtf8(bodybs) + if err == nil { + bodybs = conbs + } } } } text := string(bodybs) temp := []rune(text) length4 := len(temp) - if length4 > 20480 { //1万字 - text = string(temp[0:20480]) + "\n\n\n\n剩余" + strconv.FormatInt(int64(length4-20480), 10) + "字被省略.....\n\n\n\n" + 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" } text = strings.ReplaceAll(text, " ", " ") + if text == "" { + text = "文件内容是空的" + } return utils.ToSuccessJSON("text", text) } diff --git a/aliserver/aliyun/ApiFileUpload.go b/aliserver/aliyun/ApiFileUpload.go index 8151d27..7de5448 100644 --- a/aliserver/aliyun/ApiFileUpload.go +++ b/aliserver/aliyun/ApiFileUpload.go @@ -10,7 +10,7 @@ import ( "github.com/tidwall/gjson" ) -func UploadCreatForder(parentid string, name string) (dirid string, err error) { +func UploadCreatForder(boxid string, parentid string, name string) (dirid string, err error) { defer func() { if errr := recover(); errr != nil { log.Println("UploadCreatForderError ", " error=", errr) @@ -20,7 +20,7 @@ func UploadCreatForder(parentid string, name string) (dirid string, err error) { }() var apiurl = "https://api.aliyundrive.com/v2/file/create" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "parent_file_id": parentid, "name": name, "check_name_mode": "refuse", @@ -49,18 +49,19 @@ func UploadCreatForder(parentid string, name string) (dirid string, err error) { return file_id, nil } -func UploadCreatFile(parentid string, name string, size int64, hash string) (israpid bool, upload_id string, file_id string, err error) { +func UploadCreatFile(boxid string, parentid string, name string, size int64, hash string) (israpid bool, upload_id string, file_id string, uploadurl string, err error) { defer func() { if errr := recover(); errr != nil { log.Println("UploadCreatForderError ", " error=", errr) upload_id = "" file_id = "" + uploadurl = "" err = errors.New("UploadCreatForderError") } }() var apiurl = "https://api.aliyundrive.com/v2/file/create" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "parent_file_id": parentid, "name": name, "size": size, @@ -81,7 +82,7 @@ func UploadCreatFile(parentid string, name string, size int64, hash string) (isr code, _, body = utils.PostHTTPString(apiurl, GetAuthorization(), postdata) } if code != 201 || !gjson.Valid(body) { //注意这里是201 - return false, "", "", errors.New("创建文件失败") + return false, "", "", "", errors.New("创建文件失败") } info := gjson.Parse(body) //如果文件已存在,也会正常返回,只是多了一个 exist=True @@ -89,26 +90,28 @@ func UploadCreatFile(parentid string, name string, size int64, hash string) (isr if info.Get("exist").Exists() { //已存在同名文件 - Same, err := UploadFileCheckHash(file_id, hash) //检查hash是否一致 + Same, err := UploadFileCheckHash(boxid, file_id, hash) //检查hash是否一致 if err != nil { - return false, "", "", err + return false, "", "", "", err } if Same { - return true, "", "", nil //成功秒传保存了 + return true, "", "", "", nil //成功秒传保存了 } - UploadFileDelete(file_id) //删除 - return UploadCreatFile(parentid, name, size, hash) //重新上传 + UploadFileDelete(boxid, file_id) //删除 + return UploadCreatFile(boxid, parentid, name, size, hash) //重新上传 } rapid_upload := info.Get("rapid_upload").Bool() if rapid_upload { - return true, "", "", nil //成功秒传保存了 + return true, "", "", "", nil //成功秒传保存了 } upload_id = info.Get("upload_id").String() - return false, upload_id, file_id, nil //返回上传ID,继续上传 + uploadurl = info.Get("part_info_list").Array()[0].Get("upload_url").String() + + return false, upload_id, file_id, uploadurl, nil //返回上传ID,继续上传 } -func UploadFileCheckHash(file_id string, hash string) (Same bool, err error) { +func UploadFileCheckHash(boxid string, file_id string, hash string) (Same bool, err error) { //https://api.aliyundrive.com/v2/file/get defer func() { if errr := recover(); errr != nil { @@ -118,7 +121,7 @@ func UploadFileCheckHash(file_id string, hash string) (Same bool, err error) { }() var apiurl = "https://api.aliyundrive.com/v2/file/get" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} b, _ := json.Marshal(postjson) @@ -145,7 +148,7 @@ func UploadFileCheckHash(file_id string, hash string) (Same bool, err error) { return content_hash == hash, nil } -func UploadFileDelete(file_id string) (Delete bool, err error) { +func UploadFileDelete(boxid string, file_id string) (Delete bool, err error) { defer func() { if errr := recover(); errr != nil { log.Println("ApiFileDelete ", " error=", errr) @@ -154,7 +157,7 @@ func UploadFileDelete(file_id string) (Delete bool, err error) { }() var apiurl = "https://api.aliyundrive.com/v2/recyclebin/trash" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "file_id": file_id} b, _ := json.Marshal(postjson) @@ -176,7 +179,7 @@ func UploadFileDelete(file_id string) (Delete bool, err error) { return true, nil } -func UploadFileComplete(parentid string, name string, file_id string, upload_id string) (err error) { +func UploadFileComplete(boxid string, parentid string, name string, file_id string, upload_id string) (err error) { defer func() { if errr := recover(); errr != nil { log.Println("ApiFileComplete ", " error=", errr) @@ -185,7 +188,7 @@ func UploadFileComplete(parentid string, name string, file_id string, upload_id }() var apiurl = "https://api.aliyundrive.com/v2/file/complete" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "upload_id": upload_id, "file_id": file_id, "parent_file_id": parentid, @@ -217,7 +220,7 @@ func UploadFileComplete(parentid string, name string, file_id string, upload_id return nil } -func UploadFilePartUrl(parentid string, name string, file_id string, upload_id string, part_number int, part_size int64) (url string, err error) { +func UploadFilePartUrl(boxid string, parentid string, name string, file_id string, upload_id string, part_number int, part_size int64) (url string, err error) { defer func() { if errr := recover(); errr != nil { log.Println("UploadFilePartUrl ", " error=", errr) @@ -227,7 +230,7 @@ func UploadFilePartUrl(parentid string, name string, file_id string, upload_id s }() var apiurl = "https://api.aliyundrive.com/v2/file/get_upload_url" - var postjson = map[string]interface{}{"drive_id": _user.UserToken.P_default_drive_id, + var postjson = map[string]interface{}{"drive_id": boxid, "upload_id": upload_id, "file_id": file_id, "parent_file_id": parentid, @@ -258,5 +261,6 @@ func UploadFilePartUrl(parentid string, name string, file_id string, upload_id s info := gjson.Parse(body) uinfo := info.Get("part_info_list").Array()[0] upload_url := uinfo.Get("upload_url").String() + //upload_url = strings.Replace(upload_url, "bj29.cn-beijing.data.alicloudccp.com", "ccp-bj29-bj-1592982087.oss-cn-beijing-internal.aliyuncs.com", -1)//内网 return upload_url, nil } diff --git a/aliserver/aliyun/ApiLink.go b/aliserver/aliyun/ApiLink.go index de91f4e..580cb36 100644 --- a/aliserver/aliyun/ApiLink.go +++ b/aliserver/aliyun/ApiLink.go @@ -13,24 +13,38 @@ type LinkFileModel struct { FileList []string `json:"FileList"` Name string `json:"Name"` Size int64 `json:"Size"` - Message string + Message string `json:"-"` } -func (b LinkFileModel) GetDirCount() int { +type LinkSearchModel struct { + Count int64 `json:"Count"` + FileList []*LinkSearchFileModel `json:"FileList"` +} + +type LinkSearchFileModel struct { + Key string `json:"Key"` + Name string `json:"Name"` + Size int64 `json:"Size"` + Hash string `json:"Hash"` + Time int64 `json:"Time"` + Icon string +} + +func (b *LinkFileModel) GetDirCount() int { count := len(b.DirList) for i := 0; i < len(b.DirList); i++ { count += b.DirList[i].GetDirCount() } return count } -func (b LinkFileModel) GetFileCount() int { +func (b *LinkFileModel) GetFileCount() int { count := len(b.FileList) for i := 0; i < len(b.DirList); i++ { count += b.DirList[i].GetFileCount() } return count } -func (b LinkFileModel) GetTotalSize() int64 { +func (b *LinkFileModel) GetTotalSize() int64 { count := b.Size for i := 0; i < len(b.DirList); i++ { count += b.DirList[i].GetTotalSize() @@ -38,10 +52,19 @@ func (b LinkFileModel) GetTotalSize() int64 { return count } +func (b *LinkFileModel) GetAliyun() []string { + var list = make([]string, 0, len(b.FileList)) + list = append(list, b.FileList...) + for i := 0; i < len(b.DirList); i++ { + list = append(list, b.DirList[i].GetAliyun()...) + } + return list +} + //ApiFileListAllForLink 读取一个文件夹的信息(文件列表)(遍历子文件夹) -func ApiFileListAllForLink(file_id string, name string) (link *LinkFileModel, err error) { +func ApiFileListAllForLink(boxid string, file_id string, name string) (link *LinkFileModel, err error) { for i := 0; i < 3; i++ { - link, err = _ApiFileListAllForLink(file_id, name) + link, err = _ApiFileListAllForLink(boxid, file_id, name) if err == nil { return link, nil } @@ -50,7 +73,7 @@ func ApiFileListAllForLink(file_id string, name string) (link *LinkFileModel, er } //_ApiFileListAllForLink 读取一个文件夹的信息(文件列表)(遍历子文件夹) -func _ApiFileListAllForLink(file_id string, name string) (link *LinkFileModel, err error) { +func _ApiFileListAllForLink(boxid string, file_id string, name string) (link *LinkFileModel, err error) { defer func() { if errr := recover(); errr != nil { log.Println("_ApiFileListAllForLinkError ", " error=", errr) @@ -60,7 +83,7 @@ func _ApiFileListAllForLink(file_id string, name string) (link *LinkFileModel, e var marker = "" var list = []*FileUrlModel{} for { - flist, next, ferr := ApiFileListUrl(file_id, name, marker) + flist, next, ferr := ApiFileListUrl(boxid, file_id, name, marker) if ferr != nil { return nil, errors.New("error") //有错误直接退出 } @@ -88,7 +111,7 @@ func _ApiFileListAllForLink(file_id string, name string) (link *LinkFileModel, e if item.IsDir { wg.Add(1) go func(item *FileUrlModel) { - dir, derr := ApiFileListAllForLink(item.P_file_id, item.P_file_name) + dir, derr := ApiFileListAllForLink(boxid, item.P_file_id, item.P_file_name) //注意这里,如果子文件夹遍历时出错了,直接退出,确保要么全部成功,要么全部失败,不丢失 if derr != nil { errnum++ @@ -118,12 +141,18 @@ func ApiPostLinkToServer(urldata string, postdata *[]byte) (link string) { link = "error" } }() - //出于服务器数据安全考虑,此处已被屏蔽 + return "error" } func ApiParseLinkToServer(urldata string, postdata *[]byte) (link *LinkFileModel, xbylink string) { - + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiPostLinkToServerError ", " error=", errr) + xbylink = "" + link.Message = "error" + } + }() link = &LinkFileModel{ DirList: []*LinkFileModel{}, FileList: []string{}, @@ -132,6 +161,19 @@ func ApiParseLinkToServer(urldata string, postdata *[]byte) (link *LinkFileModel Size: 0, } - //出于服务器数据安全考虑,此处已被屏蔽 return link, "" } + +func ApiSearchLinkToServer(urldata string, postdata *[]byte) (LinkSearchModel, error) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiPostLinkToServerError ", " error=", errr) + } + }() + var result = LinkSearchModel{ + Count: 0, + FileList: []*LinkSearchFileModel{}, + } + + return result, errors.New("error") +} diff --git a/aliserver/aliyun/ApiMemUpload.go b/aliserver/aliyun/ApiMemUpload.go new file mode 100644 index 0000000..c6affc5 --- /dev/null +++ b/aliserver/aliyun/ApiMemUpload.go @@ -0,0 +1,56 @@ +package aliyun + +import ( + "bytes" + "crypto/tls" + "errors" + "log" + "net/http" +) + +func MemUpload(boxid string, parentid string, filename string, buff *[]byte) (err error) { + defer func() { + if errr := recover(); errr != nil { + log.Println("MemUploadError ", " error=", errr) + err = errors.New("MemUploadError") + } + }() + var buffer bytes.Buffer + buffer.Write([]byte{0xEF, 0xBB, 0xBF}) + buffer.Write(*buff) + size := int64(buffer.Len()) + reader := bytes.NewReader(buffer.Bytes()) + hash, err := ComputeAliBuffSha1(reader, size) + if err != nil { + return err + } + + israpid, upload_id, file_id, upload_url, err := UploadCreatFile(boxid, parentid, filename, size, hash.Hash) + if err != nil { + return err + } + if israpid == false { + reader.Seek(0, 0) + request, err := http.NewRequest("PUT", upload_url, reader) + if err != nil { + return err + } + request.Header.Set("Expect", "100-continue") + //var proxyurl, _ = url.Parse("http://192.168.31.75:8888") + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + // Proxy: http.ProxyURL(proxyurl), + } + resp, err := (&http.Client{Transport: tr}).Do(request) + if err != nil { + return err + } + defer resp.Body.Close() + + err = UploadFileComplete(boxid, parentid, filename, file_id, upload_id) + if err != nil { + return err + } + } + return nil +} diff --git a/aliserver/aliyun/ApiUser.go b/aliserver/aliyun/ApiUser.go index 43a8829..894d2f1 100644 --- a/aliserver/aliyun/ApiUser.go +++ b/aliserver/aliyun/ApiUser.go @@ -20,10 +20,22 @@ func CheckUserID(userid string) bool { return _user.UserID == userid } +func GetUserBoxID() string { + return _user.UserToken.P_default_drive_id +} +func GetUserSBoxID() string { + return _user.UserToken.P_default_sbox_drive_id +} +func GetUserXiangCeID() string { + return _user.UserXiangCeID +} + var _user = data.UserLoginModel{ UserLoginType: "", UserID: "", UserName: "", + UserFace: "", + UserXiangCeID: "", UserAccessToken: "", UserRefreshToken: "", UserToken: data.UserTokenModel{}, @@ -34,7 +46,9 @@ func SetUserToken(logintype string, token data.UserTokenModel) { var userLogin = data.UserLoginModel{ UserLoginType: logintype, UserID: token.P_user_id, - UserName: token.P_user_name, + UserName: token.P_nick_name, //昵称 + UserFace: token.P_avatar, //头像 + UserXiangCeID: "", //相册ID UserAccessToken: token.P_access_token, UserRefreshToken: token.P_refresh_token, UserToken: token, @@ -43,13 +57,16 @@ func SetUserToken(logintype string, token data.UserTokenModel) { if _user.UserID == token.P_user_id { userLogin.UserInfo = _user.UserInfo } - _user = userLogin + _user = userLogin //先登录 + _user.UserXiangCeID = ApiUserXiangCeID() //后相册 + b, _ := json.Marshal(_user) data.SetUser(_user.UserID, string(b)) } func GetAuthorization() string { return "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36\n" + + "Origin: https://www.aliyundrive.com\n" + "Referer: https://www.aliyundrive.com/\n" + "Authorization: " + _user.UserToken.P_token_type + " " + _user.UserToken.P_access_token } @@ -102,11 +119,75 @@ func ApiUserInfo() (retjsonstr string) { data.SetUser(_user.UserID, string(b)) } + if _user.UserXiangCeID == "" { + _user.UserXiangCeID = ApiUserXiangCeID() + } + var infostr = `{"userID":"` + _user.UserID + `","userName":"` + utils.ToJSONString(_user.UserName) + `","panUsed":"` + _user.UserInfo.P_used_size + `","panTotal":"` + _user.UserInfo.P_total_size + `",` - infostr = infostr + `"drive_size":"` + _user.UserInfo.P_drive_size + `","safe_box_size":"` + _user.UserInfo.P_safe_box_size + `","upload_size":"` + _user.UserInfo.P_upload_size + `"}` + infostr = infostr + `"drive_size":"` + _user.UserInfo.P_drive_size + `","safe_box_size":"` + _user.UserInfo.P_safe_box_size + `","upload_size":"` + _user.UserInfo.P_upload_size + `","userFace":"` + utils.ToJSONString(_user.UserFace) + `"}` return utils.ToSuccessJSON("info", infostr) } +func ApiUserXiangCeID() (driveId string) { + + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiUserXiangCeIDError ", " error=", errr) + driveId = "" + } + }() + + if _user.UserID == "" { + return "" + } + 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(), "{}") + } + + if code != 200 || !gjson.Valid(body) { + return "" + } + var info = gjson.Parse(body) + driveId = info.Get("data.driveId").String() + return driveId +} + +func ApiUserSboxID() (driveId string) { + + defer func() { + if errr := recover(); errr != nil { + log.Println("ApiUserSboxError ", " error=", errr) + driveId = "" + } + }() + + if _user.UserID == "" { + return "" + } + 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(), "{}") + } + + if code != 200 || !gjson.Valid(body) { + return "" + } + var info = gjson.Parse(body) + driveId = info.Get("drive_id").String() + return driveId +} + func ApiUserLogoff() string { data.DelUser(_user.UserID) _user = data.UserLoginModel{} diff --git a/aliserver/aliyun/Sha1Hash.go b/aliserver/aliyun/Sha1Hash.go index 8526818..c0d2f69 100644 --- a/aliserver/aliyun/Sha1Hash.go +++ b/aliserver/aliyun/Sha1Hash.go @@ -1,6 +1,7 @@ package aliyun import ( + "bytes" "crypto/sha1" "errors" "fmt" @@ -50,3 +51,33 @@ func ComputeAliFileSha1(filePtr *os.File, size int64) (hash AliFileHash, err err return hash, nil } + +func ComputeAliBuffSha1(filePtr *bytes.Reader, size int64) (hash AliFileHash, err error) { + defer func() { + if errr := recover(); errr != nil { + log.Println("ComputeAliBuffSha1Error ", " error=", errr) + err = errors.New("sha1 error") + } + }() + + //filePtr := bytes.NewReader(buff.Bytes()) + + hashbytes, err := computeSha1(filePtr) + if err != nil { + return hash, errors.New("sha1 error") + } + hash.Hash = fmt.Sprintf("%X", hashbytes) + + filePtr.Seek(0, 0) + if size > 1024 { + size = 1024 + } + perbody := io.LimitReader(filePtr, size) + prehashbytes, err := computeSha1(perbody) + if err != nil { + return hash, errors.New("sha1 error pre") + } + hash.Pre_hash = fmt.Sprintf("%X", prehashbytes) + + return hash, nil +} diff --git a/aliserver/data/Setting.go b/aliserver/data/Setting.go index ba55c79..07ef3df 100644 --- a/aliserver/data/Setting.go +++ b/aliserver/data/Setting.go @@ -62,7 +62,7 @@ type ISettingModel struct { var Setting = ISettingModel{ SavePath: "", SavePathCheck: false, - TextScale: "1.0", + TextScale: "1.1", Theme: "day", DownSpeed: "0", //全局不限速 DownMax: "3", //3文件 @@ -84,7 +84,7 @@ type IConfigModel struct { } //LocalExeVer 文件版本 -const LocalExeVer = "1.6.10.0" +const LocalExeVer = "1.6.21.0" //Config 全局,serverconfig var Config = IConfigModel{ diff --git a/aliserver/data/User.go b/aliserver/data/User.go index 1a2aa59..7afe02a 100644 --- a/aliserver/data/User.go +++ b/aliserver/data/User.go @@ -44,6 +44,8 @@ type UserLoginModel struct { UserLoginType string `json:"UserLoginType"` UserID string `json:"UserID"` UserName string `json:"UserName"` + UserFace string `json:"UserFace"` + UserXiangCeID string `json:"UserXiangCeID"` UserAccessToken string `json:"UserAccessToken"` UserRefreshToken string `json:"UserRefreshToken"` UserToken UserTokenModel `json:"UserToken"` diff --git a/aliserver/download/Aria2.go b/aliserver/download/Aria2.go index 0a6f99d..672cc87 100644 --- a/aliserver/download/Aria2.go +++ b/aliserver/download/Aria2.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "log" + "strings" "time" ) @@ -53,7 +54,7 @@ func Aria2Connect() error { option["max-overall-download-limit"] = 0 } Aria2Rpc.ChangeGlobalOption(option) - log.Println("connectTo", Aria2Server, version.Version) + log.Println("connectSuccess", Aria2Server, version.Version) go ariaDisconnectionMonitoring() } @@ -87,8 +88,12 @@ func ariaDisconnectionMonitoring() { time.Sleep(time.Second * time.Duration(2)) _, terr := Aria2Rpc.GetVersion() + if terr != nil && strings.Index(terr.Error(), "timeout awaiting response headers") > 0 { + //aria正忙(分配硬盘空间) + terr = nil + } if terr != nil { - log.Println("ariaDisconnect") + log.Println("ariaDisconnect", terr.Error()) fmt.Println("ariaDisconnect") Aria2Rpc.Close() LaunchAria2c() diff --git a/aliserver/download/DownModel.go b/aliserver/download/DownModel.go index 8159f4a..8a6674e 100644 --- a/aliserver/download/DownModel.go +++ b/aliserver/download/DownModel.go @@ -23,6 +23,7 @@ type DownFileModel struct { DownServer string `json:"DownServer"` //FileInfo Identity string `json:"identity"` + BoxID string `json:"boxid"` //要下载的文件名--IMG_2020_01.jpg Name string `json:"name"` //要下载的文件大小 diff --git a/aliserver/download/downaria2.go b/aliserver/download/downaria2.go index a2e13fe..874cbe2 100644 --- a/aliserver/download/downaria2.go +++ b/aliserver/download/downaria2.go @@ -31,7 +31,10 @@ func MakeDownloadAria(item *DownFileModel) { } func openSaveFile(item *DownFileModel) (isexist bool, issame bool, err error) { - FileSave := filepath.Join(item.DownSavePath, item.Name) + if utils.IsWindows() && item.Name == "." { + return false, false, errors.New("windows不允许文件名.") //未下载,路径错误 + } + FileSave := utils.JoinFilePath(item.DownSavePath, item.Name) if utils.IsDir(FileSave) { return false, false, errors.New("SaveFile cannot be dir") //未下载,路径错误 } @@ -67,6 +70,9 @@ func openSaveFile(item *DownFileModel) (isexist bool, issame bool, err error) { //StartDownAsync StartDownAsync func StartDownAsync(item *DownFileModel, threadcount int) { item.AutoGID = -1 //标识,不需要刷新进度,在下面Aria2Rpc.AddURI成功后UpdateStateDowning时会置0 + if item.BoxID == "" { + item.BoxID = aliyun.GetUserBoxID() //修正旧版本升级 + } //处理文件夹 if item.Hash == "dir" { @@ -74,7 +80,7 @@ func StartDownAsync(item *DownFileModel, threadcount int) { os.MkdirAll(SavePathFull, 0777) UserID := aliyun.GetUserID() //遍历子文件,添加到下载队列,保存为已完成 - clist, cerr := aliyun.ApiFileListAllForDown(item.Identity, "", false) //列出文件夹下的所有文件 + clist, cerr := aliyun.ApiFileListAllForDown(item.BoxID, item.Identity, "", false) //列出文件夹下的所有文件 if cerr != nil { UpdateStateError(item, "解析文件夹失败:"+cerr.Error()) return @@ -101,7 +107,7 @@ func StartDownAsync(item *DownFileModel, threadcount int) { url := "" //无法访问资源,可能需要登录 for i := 0; i < 3; i++ { - downurl, _, err := aliyun.ApiFileDownloadUrl(item.Identity, 60*60*2) + downurl, _, err := aliyun.ApiFileDownloadUrl(item.BoxID, item.Identity, 60*60*2) if err != nil { fmt.Println("DownloadAddress", err) time.Sleep(time.Duration(2) * time.Second) @@ -124,6 +130,15 @@ func StartDownAsync(item *DownFileModel, threadcount int) { _, ed := Aria2Rpc.TellStatus(item.GID) if ed == nil { Aria2Rpc.Remove(item.GID) + } else { + if !strings.Contains(ed.Error(), "is not found") { + log.Println("aria2cerror4", ed) //GID 8d3ccdcde3c2e241 is not found + } + if strings.Contains(ed.Error(), "timeout awaiting response headers") { + //aria2c正忙,稍后再重试 + UpdateStateError(item, "aria2c正忙稍后重试") + return + } } } @@ -141,11 +156,19 @@ func StartDownAsync(item *DownFileModel, threadcount int) { optionData["referer"] = data.Config.AliDownReferer optionData["user-agent"] = data.Config.AliDownAgent optionData["check-certificate"] = "false" + optionData["file-allocation"] = "trunc" if data.Setting.DownSha1Check && item.Hash != "" { optionData["checksum"] = "sha-1=" + item.Hash } - infos, _ := Aria2Rpc.TellActive("gid", "status", "totalLength", "completedLength", "downloadSpeed") + infos, ed2 := Aria2Rpc.TellActive("gid", "status", "totalLength", "completedLength", "downloadSpeed") + + if ed2 != nil { + log.Println("aria2cerror5", ed2) + UpdateStateError(item, "aria2c正忙稍后重试") + return + } + for j := 0; j < len(infos); j++ { if infos[j].Gid[0:10] == item.GID[0:10] { Aria2Rpc.Remove(infos[j].Gid) @@ -156,15 +179,11 @@ func StartDownAsync(item *DownFileModel, threadcount int) { _, erradd := Aria2Rpc.AddURI(uriData, optionData) if erradd != nil { + log.Println("aria2cerroradd", erradd) msg := "创建aria任务失败:" + erradd.Error() if strings.Contains(msg, "No URI to") { msg = "创建aria任务失败,稍后自动重试" } - if strings.Contains(msg, "Post ") { - log.Println("aria2Rpc.AddURI: ", msg, erradd) - Aria2Rpc.ForceShutdown() - msg = "链接到aria失败,稍后自动重试 " + msg - } UpdateStateError(item, msg) return } else { diff --git a/aliserver/download/downmanage.go b/aliserver/download/downmanage.go index d401361..e5def34 100644 --- a/aliserver/download/downmanage.go +++ b/aliserver/download/downmanage.go @@ -112,7 +112,7 @@ func DownedList() string { //DownFileMutil 下载一堆文件 //SavePath= DownSavePath+RootPath 下载保存位置 + 该文件相对root的路径 + filelist里每个文件名 //RealPath= D:\Down\ +新建文件夹\002\ + filelist[name] -func DownFileMutil(ParentID string, SavePath string, keylist []string) string { +func DownFileMutil(boxid string, ParentID string, SavePath string, keylist []string) string { if SavePath == "" { return utils.ToErrorMessageJSON("没有提供下载保存位置") } @@ -136,7 +136,7 @@ func DownFileMutil(ParentID string, SavePath string, keylist []string) string { if fileid != "" { wg.Add(1) go func(fileid string) { - finfo, ferr := aliyun.ApiFileGetUrl(fileid, "") + finfo, ferr := aliyun.ApiFileGetUrl(boxid, fileid, "") if ferr != nil { errnum++ } else { @@ -154,7 +154,7 @@ func DownFileMutil(ParentID string, SavePath string, keylist []string) string { } } else { //文件数量较多,批量读取文件信息 - flist, ferr := aliyun.ApiFileListAllForDown(ParentID, "", false) + flist, ferr := aliyun.ApiFileListAllForDown(boxid, ParentID, "", false) if ferr != nil { return utils.ToErrorMessageJSON("列出文件信息时出错") } @@ -195,7 +195,7 @@ func _DownFileAddList(UserID string, SavePath string, list []*aliyun.FileUrlMode hash = "dir" size = 0 } - downing, err := DowningAdd(UserID, SavePath, info.P_file_id, name, path, hash, size, dtime) + downing, err := DowningAdd(UserID, SavePath, info.P_drive_id, info.P_file_id, name, path, hash, size, dtime) if err == nil { downinglist = append(downinglist, downing) filecount++ diff --git a/aliserver/download/downwork.go b/aliserver/download/downwork.go index c9cea8a..7293b54 100644 --- a/aliserver/download/downwork.go +++ b/aliserver/download/downwork.go @@ -6,7 +6,6 @@ import ( "aliserver/utils" "encoding/json" "errors" - "fmt" "log" "os" "path/filepath" @@ -119,7 +118,7 @@ func DownedAdd(Item *DownFileModel) error { } //DowningAdd 创建一个下载任务 -func DowningAdd(userid, savepath, identity, name, path, hash string, size int64, dtime int64) (downing *DownFileModel, err error) { +func DowningAdd(userid, savepath, boxid string, identity, name, path, hash string, size int64, dtime int64) (downing *DownFileModel, err error) { defer func() { if errr := recover(); errr != nil { log.Println("DowningAddError ", " error=", errr) @@ -151,6 +150,7 @@ func DowningAdd(userid, savepath, identity, name, path, hash string, size int64, Name: name, Size: size, + BoxID: boxid, Identity: identity, //Path: path, Hash: hash, @@ -304,8 +304,18 @@ func downingMakeDowning(TaskCountMax int, DowningCount int) { func downingUpdateProgress() { //1. 读取tellActive获得list - infos, _ := Aria2Rpc.TellActive("gid", "status", "totalLength", "completedLength", "downloadSpeed", "errorCode", "errorMessage") - infos2, _ := Aria2Rpc.TellStopped(0, 100, "gid", "status", "totalLength", "completedLength", "downloadSpeed", "errorCode", "errorMessage") + infos, e1 := Aria2Rpc.TellActive("gid", "status", "totalLength", "completedLength", "downloadSpeed", "errorCode", "errorMessage") + infos2, e2 := Aria2Rpc.TellStopped(0, 100, "gid", "status", "totalLength", "completedLength", "downloadSpeed", "errorCode", "errorMessage") + + if e1 != nil { + log.Println("aria2cerror1", e1, infos) + } + if e2 != nil { + log.Println("aria2cerror2", e2, infos2) + } + if e1 != nil || e2 != nil { + return //出错了跳过更新 + } infos = append(infos, infos2...) //2. 遍历队列,对downing的item,匹配list更新下载速度,不存在就tellStatus(失败、已完成) DataDowningList := DataDowningReadCopy() @@ -329,6 +339,9 @@ func downingUpdateProgress() { isFind = true UpdateStateTell(item, info) } + if err2 != nil { + log.Println("aria2cerror3", err2, info) + } } if !isFind { //最后找不到信息,说明丢失了,比如aria崩溃重启 @@ -356,11 +369,11 @@ func UpdateStateTellStatus(GID string, Status string) { if Status == "error" { info2, err2 := Aria2Rpc.TellStatus(GID, "gid", "status", "totalLength", "completedLength", "downloadSpeed", "errorCode", "errorMessage") - fmt.Println("error", info2) if err2 == nil { info.ErrorCode = info2.ErrorCode info.ErrorMessage = info2.ErrorMessage } else { + log.Println("aria2cerror6", err2, info2) info.ErrorCode = "-1" info.ErrorMessage = "下载失败,稍后自动重试" } @@ -513,7 +526,7 @@ func oncomplete(item *DownFileModel) { item.AutoGID = -1 //标识,不需要刷新进度 fileSaveTD := filepath.Join(item.DownSavePath, item.Name+".td") fileSaveAria := fileSaveTD + ".aria2" - fileSave := filepath.Join(item.DownSavePath, item.Name) + fileSave := utils.JoinFilePath(item.DownSavePath, item.Name) //修正文件名. if !utils.PathExists(fileSave) { err := os.Rename(fileSaveTD, fileSave) if err != nil { //移动文件时出错 diff --git a/aliserver/link/copymanage.go b/aliserver/link/copymanage.go new file mode 100644 index 0000000..40af61d --- /dev/null +++ b/aliserver/link/copymanage.go @@ -0,0 +1,108 @@ +package link + +import ( + "aliserver/aliyun" + "aliserver/upload" + "aliserver/utils" + "strconv" + "strings" + "sync" +) + +func GoCopyCreat(boxid string, parentid string, keylist []string, copytobox string, copytoid string) string { + + UserID := aliyun.GetUserID() + if UserID == "" { + return utils.ToErrorMessageJSON("还没有登录阿里云盘账号") + } + var wg sync.WaitGroup + var lock sync.Mutex + errnum := 0 + var list []*aliyun.FileUrlModel + if len(keylist) <= 5 { + //文件数量5个,单文件读取信息 + for k := 0; k < len(keylist); k++ { + fileid := keylist[k] + if fileid != "" { + wg.Add(1) + go func(fileid string) { + finfo, ferr := aliyun.ApiFileGetUrl(boxid, fileid, "") + if ferr != nil { + errnum++ + } else { + lock.Lock() + list = append(list, &finfo) + lock.Unlock() + } + defer wg.Done() + }(fileid) + } + } + wg.Wait() + if errnum > 0 { + return utils.ToErrorMessageJSON("列出文件信息时出错") + } + } else { + //文件数量较多,批量读取文件信息 + flist, ferr := aliyun.ApiFileListAllForDown(boxid, parentid, "", false) + if ferr != nil { + return utils.ToErrorMessageJSON("列出文件信息时出错") + } + for k := 0; k < len(keylist); k++ { + fileid := keylist[k] + if fileid != "" { + for j := 0; j < len(flist); j++ { + if flist[j].P_file_id == fileid { //找到了 + list = append(list, flist[j]) + break + } + } + } + } + } + + link := aliyun.LinkFileModel{ + DirList: []*aliyun.LinkFileModel{}, + FileList: []string{}, + Name: "", + Message: "", + Size: 0, + } + + errnum = 0 + lmax := len(list) + for m := 0; m < lmax; m++ { + item := list[m] + if item.IsDir { + wg.Add(1) + go func(m int) { + dir, derr := aliyun.ApiFileListAllForLink(boxid, 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() + }(m) + } 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_sha1) + } + } + wg.Wait() + if errnum > 0 { + return utils.ToErrorMessageJSON("列出文件信息时出错") + } + + if link.GetFileCount() == 0 { + return utils.ToErrorMessageJSON("不能复制空文件夹") + } + //生成SelectFileList []*UploadSelectModel + SelectFileList, err := GetFilesWithDir(copytobox, copytoid, &link) + if err != nil { + return utils.ToErrorMessageJSON("创建保存路径失败") + } + return upload.UploadSelectFile(UserID, copytoid, SelectFileList) +} diff --git a/aliserver/link/linkmanage.go b/aliserver/link/linkmanage.go index 343aee0..a13c047 100644 --- a/aliserver/link/linkmanage.go +++ b/aliserver/link/linkmanage.go @@ -10,7 +10,6 @@ import ( "encoding/json" "errors" "log" - "net/url" "strconv" "strings" "sync" @@ -49,7 +48,7 @@ func GoLinkDelete(link string) string { return utils.ToSuccessJSON("link", link) } -func GoLinkCreat(jianjie string, ispublic bool, password, outday, outsave, parentid string, keylist []string) string { +func GoLinkCreatFile(filename, jianjie string, boxid string, parentid string, keylist []string) string { UserID := aliyun.GetUserID() if UserID == "" { @@ -66,7 +65,7 @@ func GoLinkCreat(jianjie string, ispublic bool, password, outday, outsave, paren if fileid != "" { wg.Add(1) go func(fileid string) { - finfo, ferr := aliyun.ApiFileGetUrl(fileid, "") + finfo, ferr := aliyun.ApiFileGetUrl(boxid, fileid, "") if ferr != nil { errnum++ } else { @@ -84,7 +83,7 @@ func GoLinkCreat(jianjie string, ispublic bool, password, outday, outsave, paren } } else { //文件数量较多,批量读取文件信息 - flist, ferr := aliyun.ApiFileListAllForDown(parentid, "", false) + flist, ferr := aliyun.ApiFileListAllForDown(boxid, parentid, "", false) if ferr != nil { return utils.ToErrorMessageJSON("列出文件信息时出错") } @@ -100,9 +99,6 @@ func GoLinkCreat(jianjie string, ispublic bool, password, outday, outsave, paren } } } - if jianjie == "" { - jianjie = "无" - } link := aliyun.LinkFileModel{ DirList: []*aliyun.LinkFileModel{}, @@ -119,7 +115,7 @@ func GoLinkCreat(jianjie string, ispublic bool, password, outday, outsave, paren if item.IsDir { wg.Add(1) go func(m int) { - dir, derr := aliyun.ApiFileListAllForLink(item.P_file_id, item.P_file_name) + dir, derr := aliyun.ApiFileListAllForLink(boxid, item.P_file_id, item.P_file_name) if derr != nil { errnum++ } else { @@ -142,40 +138,35 @@ func GoLinkCreat(jianjie string, ispublic bool, password, outday, outsave, paren if link.GetFileCount() == 0 { return utils.ToErrorMessageJSON("短链接内不包含任何文件") } - - b, _ := json.Marshal(link) - var buf bytes.Buffer - zw := gzip.NewWriter(&buf) - zw.Write(b) - err := zw.Close() - if err != nil { - log.Println("zw.Close", err) - return utils.ToErrorMessageJSON("gzip时出错") + /*不需要了 + var outlist = link.GetAliyun() + var builder strings.Builder + builder.Grow(100 * (len(outlist) + 1)) + for o := 0; o < len(outlist); o++ { + oitem := strings.Split(outlist[o], "|") + builder.WriteString("aliyunpan://" + oitem[0] + "|" + oitem[2] + "|" + oitem[1] + "|\r\n") } - bs := buf.Bytes() - - urldata := "password=" + password + "&outday=" + outday + "&outsave=" + outsave + "&filecount=" + strconv.FormatInt(int64(link.GetFileCount()), 10) + "&dircount=" + strconv.FormatInt(int64(link.GetDirCount()), 10) - urldata += "&totalsize=" + strconv.FormatInt(int64(link.GetTotalSize()), 10) - urldata += "&ispublic=" + strconv.FormatBool(ispublic) + "&jianjie=" + url.QueryEscape(jianjie) - linkstr := aliyun.ApiPostLinkToServer(urldata, &bs) - if linkstr != "error" { - if linkstr != "" { - linklog := LinkLogModel{ - Link: linkstr, - LogTime: time.Now().Unix(), - IsCreater: true, - } - b, _ := json.Marshal(linklog) - data.SetLink("Link:"+linkstr, string(b)) + var outstring = builder.String() + builder.Reset() + */ + infostr := strconv.FormatInt(int64(link.GetFileCount()), 10) + "个文件 " + utils.FormateSizeString(link.GetTotalSize()) + b, err := json.Marshal(link) //需要把文件数据上传 + for i := 0; i < 3; i++ { + err = aliyun.MemUpload(boxid, parentid, filename, &b) + if err == nil { + break } - return utils.ToSuccessJSON("link", linkstr) + } + //执行上传操作 + if err == nil { + return utils.ToSuccessJSON2("info", infostr, "aliyun", "") } else { log.Println("postlink", err) - return utils.ToErrorMessageJSON("上传数据时出错") + return utils.ToErrorMessageJSON("向网盘内创建文件" + filename + "时出错") } } -func GoLinkParse(linkstr string, password string) string { +func GoLinkParse(linkstr string, password string, ispublic bool) string { UserID := aliyun.GetUserID() if UserID == "" { @@ -192,7 +183,7 @@ func GoLinkParse(linkstr string, password string) string { } bs := buf.Bytes() - urldata := "password=" + password + urldata := "password=" + password + "&ispublic=" + strconv.FormatBool(ispublic) link, xbylink := aliyun.ApiParseLinkToServer(urldata, &bs) if link.Message == "" { if xbylink != "" { @@ -204,13 +195,14 @@ func GoLinkParse(linkstr string, password string) string { b, _ := json.Marshal(linklog) data.SetLink("Link:"+xbylink, string(b)) } - return utils.ToSuccessJSON2("xbylink", xbylink, "link", link) + infostr := strconv.FormatInt(int64(link.GetFileCount()), 10) + "个文件 " + utils.FormateSizeString(link.GetTotalSize()) + return utils.ToSuccessJSON3("xbylink", xbylink, "info", infostr, "link", link) } else { log.Println("parselink", err) return utils.ToErrorMessageJSON(link.Message) } } -func GoLinkUpload(ParentID string, linkstr string) string { +func GoLinkUpload(boxid string, ParentID string, linkstr string) string { if ParentID == "" { ParentID = "root" } @@ -233,13 +225,13 @@ func GoLinkUpload(ParentID string, linkstr string) string { } //生成SelectFileList []*UploadSelectModel - SelectFileList, err := GetFilesWithDir(ParentID, &link) + SelectFileList, err := GetFilesWithDir(boxid, ParentID, &link) if err != nil { return utils.ToErrorMessageJSON("创建保存路径失败") } return upload.UploadSelectFile(UserID, ParentID, SelectFileList) } -func GetFilesWithDir(ParentID string, link *aliyun.LinkFileModel) (files []*upload.UploadSelectModel, err error) { +func GetFilesWithDir(boxid string, ParentID string, link *aliyun.LinkFileModel) (files []*upload.UploadSelectModel, err error) { files = make([]*upload.UploadSelectModel, 0, len(link.FileList)+len(link.DirList)) @@ -254,6 +246,7 @@ func GetFilesWithDir(ParentID string, link *aliyun.LinkFileModel) (files []*uplo m.Name = str[0:index] m.Path = "miaochuan|" + hash m.ParentID = ParentID + m.BoxID = boxid files = append(files, &m) } var wg sync.WaitGroup @@ -264,12 +257,12 @@ func GetFilesWithDir(ParentID string, link *aliyun.LinkFileModel) (files []*uplo go func(n int) { dir := link.DirList[n] //先在网盘里创建对应的文件夹,获得文件夹ID - DirID, err3 := aliyun.UploadCreatForder(ParentID, dir.Name) + DirID, err3 := aliyun.UploadCreatForder(boxid, ParentID, dir.Name) if err3 != nil { errnum++ } else { // 然后递归遍历 - childfiles, err2 := GetFilesWithDir(DirID, dir) + childfiles, err2 := GetFilesWithDir(boxid, DirID, dir) if err2 != nil { errnum++ } @@ -288,3 +281,32 @@ func GetFilesWithDir(ParentID string, link *aliyun.LinkFileModel) (files []*uplo } return files, nil } + +func GoLinkSearch(search string, pageindex int64) string { + if search == "" { + search = "search" + } + if pageindex < 1 { + pageindex = 1 + } + if pageindex > 9 { + pageindex = 9 + } + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + zw.Write([]byte(search)) + err := zw.Close() + if err != nil { + log.Println("zw.Close", err) + return utils.ToErrorMessageJSON("gzip时出错") + } + bs := buf.Bytes() + + urldata := "pageindex=" + strconv.FormatInt(pageindex, 10) + result, err := aliyun.ApiSearchLinkToServer(urldata, &bs) + if err != nil { + return utils.ToErrorMessageJSON("gzip时出错") + } + return utils.ToSuccessJSON2("fileCount", result.Count, "items", result.FileList) + +} diff --git a/aliserver/localhost/Action.go b/aliserver/localhost/Action.go index cf33eda..5bcd55f 100644 --- a/aliserver/localhost/Action.go +++ b/aliserver/localhost/Action.go @@ -111,77 +111,131 @@ func HookAction(url string, postdata string) (ishook bool, hookresult string) { refreshToken := gjson.Get(postdata, "refreshToken").String() return true, aliyun.ApiTokenRefresh(refreshToken) case "ApiFileList": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) parentid := gjson.Get(postdata, "parentid").String() marker := gjson.Get(postdata, "marker").String() - return true, HookActionFileList(parentid, marker) + return true, HookActionFileList(boxid, parentid, marker) case "ApiDirList": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) parentid := gjson.Get(postdata, "parentid").String() - return true, aliyun.ApiDirList(parentid) + return true, aliyun.ApiDirList(boxid, parentid) case "ApiCreatForder": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) parentid := gjson.Get(postdata, "parentid").String() name := gjson.Get(postdata, "name").String() - return true, aliyun.ApiCreatForder(parentid, name) + return true, aliyun.ApiCreatForder(boxid, parentid, name) case "ApiRename": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) file_id := gjson.Get(postdata, "file_id").String() name := gjson.Get(postdata, "name").String() - return true, aliyun.ApiRename(file_id, name) - case "ApiMoveBatch": //移动文件功能还没做 + return true, aliyun.ApiRename(boxid, file_id, name) + case "ApiRenameBatch": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + keylist := gjson.Get(postdata, "keylist").Array() + keylist2 := make([]string, len(keylist)) + for i := 0; i < len(keylist); i++ { + keylist2[i] = keylist[i].String() + } + namelist := gjson.Get(postdata, "namelist").Array() + namelist2 := make([]string, len(namelist)) + for i := 0; i < len(namelist); i++ { + namelist2[i] = namelist[i].String() + } + return true, aliyun.ApiRenameBatch(boxid, keylist2, namelist2) + + case "ApiUncompress": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + file_id := gjson.Get(postdata, "file_id").String() + target_file_id := gjson.Get(postdata, "target_file_id").String() + password := gjson.Get(postdata, "password").String() + return true, aliyun.ApiUncompress(boxid, file_id, target_file_id, password) + case "ApiUncompressCheck": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + file_id := gjson.Get(postdata, "file_id").String() + domain_id := gjson.Get(postdata, "domain_id").String() + task_id := gjson.Get(postdata, "task_id").String() + return true, aliyun.ApiUncompressCheck(boxid, domain_id, file_id, task_id) + case "ApiMoveBatch": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + movetobox := GetBoxID(gjson.Get(postdata, "movetobox").String()) movetoid := gjson.Get(postdata, "movetoid").String() filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { list[i] = filelist[i].String() } - return true, aliyun.ApiMoveBatch(movetoid, list) + return true, aliyun.ApiMoveBatch(boxid, list, movetobox, movetoid) + case "ApiCopyBatch": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + copytobox := GetBoxID(gjson.Get(postdata, "copytobox").String()) + copytoid := gjson.Get(postdata, "copytoid").String() + parentid := gjson.Get(postdata, "parentid").String() + filelist := gjson.Get(postdata, "filelist").Array() + list := make([]string, len(filelist)) + for i := 0; i < len(filelist); i++ { + list[i] = filelist[i].String() + } + return true, link.GoCopyCreat(boxid, parentid, list, copytobox, copytoid) case "ApiTrashBatch": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { list[i] = filelist[i].String() } - return true, aliyun.ApiTrashBatch(list) + return true, aliyun.ApiTrashBatch(boxid, list) case "ApiTrashDeleteBatch": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { list[i] = filelist[i].String() } - return true, aliyun.ApiTrashDeleteBatch(list) + return true, aliyun.ApiTrashDeleteBatch(boxid, list) case "ApiTrashRestoreBatch": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { list[i] = filelist[i].String() } - return true, aliyun.ApiTrashRestoreBatch(list) + return true, aliyun.ApiTrashRestoreBatch(boxid, list) case "ApiTrashFileList": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) marker := gjson.Get(postdata, "marker").String() - return true, aliyun.ApiTrashFileList(marker) + return true, aliyun.ApiTrashFileList(boxid, marker) case "ApiFavorFileList": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) marker := gjson.Get(postdata, "marker").String() - return true, aliyun.ApiFavorFileList(marker) + return true, aliyun.ApiFavorFileList(boxid, marker) case "ApiFavor": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) file_id := gjson.Get(postdata, "file_id").String() isfavor := gjson.Get(postdata, "isfavor").Bool() - return true, aliyun.ApiFavor(file_id, isfavor) + return true, aliyun.ApiFavor(boxid, file_id, isfavor) case "ApiFavorBatch": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { list[i] = filelist[i].String() } isfavor := gjson.Get(postdata, "isfavor").Bool() - return true, aliyun.ApiFavorBatch(list, isfavor) + return true, aliyun.ApiFavorBatch(boxid, list, isfavor) case "GoPlay": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) file_id := gjson.Get(postdata, "file_id").String() - return true, aliyun.ApiPlay(file_id) + return true, aliyun.ApiPlay(boxid, file_id) case "GoImage": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) file_id := gjson.Get(postdata, "file_id").String() - return true, aliyun.ApiImage(file_id) + return true, aliyun.ApiImage(boxid, file_id) case "GoText": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) file_id := gjson.Get(postdata, "file_id").String() - return true, aliyun.ApiText(file_id) + return true, aliyun.ApiText(boxid, file_id) case "GoDownFile": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { @@ -189,7 +243,7 @@ func HookAction(url string, postdata string) (ishook bool, hookresult string) { } savepath := gjson.Get(postdata, "savepath").String() //DownSavePath+RootPath 下载保存位置+该文件相对root的路径 parentid := gjson.Get(postdata, "parentid").String() //D:\Down\ +新建文件夹\002\ + filelist[name] - return true, download.DownFileMutil(parentid, savepath, list) + return true, download.DownFileMutil(boxid, parentid, savepath, list) case "GoDowningList": return true, download.DowningList() case "GoDownedList": @@ -227,17 +281,28 @@ func HookAction(url string, postdata string) (ishook bool, hookresult string) { return true, download.DownedForder(downid) case "GoUploadFile": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { list[i] = filelist[i].String() } parentid := gjson.Get(postdata, "parentid").String() - return true, upload.UploadFile(parentid, list) + return true, upload.UploadFile(boxid, parentid, list) case "GoUploadDir": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) parentid := gjson.Get(postdata, "parentid").String() dirpath := gjson.Get(postdata, "dirpath").String() - return true, upload.UploadDir(parentid, dirpath) + return true, upload.UploadDir(boxid, parentid, dirpath) + case "GoUploadFileAndDir": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + filelist := gjson.Get(postdata, "filelist").Array() + list := make([]string, len(filelist)) + for i := 0; i < len(filelist); i++ { + list[i] = filelist[i].String() + } + parentid := gjson.Get(postdata, "parentid").String() + return true, upload.UploadFileAndDir(boxid, parentid, list) case "GoUploadingList": return true, upload.UploadingList() case "GoUploadList": @@ -283,44 +348,56 @@ func HookAction(url string, postdata string) (ishook bool, hookresult string) { case "GoLinkDelete": linkstr := gjson.Get(postdata, "link").String() return true, link.GoLinkDelete(linkstr) - case "GoLinkCreat": - ispublic := gjson.Get(postdata, "ispublic").Bool() + case "GoLinkCreatFile": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) + filename := gjson.Get(postdata, "filename").String() jianjie := gjson.Get(postdata, "jianjie").String() - password := gjson.Get(postdata, "password").String() - outday := gjson.Get(postdata, "outday").String() - outsave := gjson.Get(postdata, "outsave").String() parentid := gjson.Get(postdata, "parentid").String() filelist := gjson.Get(postdata, "filelist").Array() list := make([]string, len(filelist)) for i := 0; i < len(filelist); i++ { list[i] = filelist[i].String() } - return true, link.GoLinkCreat(jianjie, ispublic, password, outday, outsave, parentid, list) + return true, link.GoLinkCreatFile(filename, jianjie, boxid, parentid, list) case "GoLinkParse": linkstr := gjson.Get(postdata, "link").String() password := gjson.Get(postdata, "password").String() - return true, link.GoLinkParse(linkstr, password) + ispublic := gjson.Get(postdata, "ispublic").Bool() + return true, link.GoLinkParse(linkstr, password, ispublic) case "GoLinkUpload": + boxid := GetBoxID(gjson.Get(postdata, "box").String()) parentid := gjson.Get(postdata, "parentid").String() linkstr := gjson.Get(postdata, "linkstr").String() - return true, link.GoLinkUpload(parentid, linkstr) + return true, link.GoLinkUpload(boxid, parentid, linkstr) + + case "GoLinkSearch": + search := gjson.Get(postdata, "search").String() + pageindex := gjson.Get(postdata, "pageindex").Int() + return true, link.GoLinkSearch(search, pageindex) + } return false, "" } //HookActionFileList 特殊处理 1.识别回收站、收藏夹、保险箱、最近访问 2.出错自动重试3次 -func HookActionFileList(parentid string, marker string) string { +func HookActionFileList(boxid, parentid string, marker string) string { jsonstr := "" for i := 0; i < 3; i++ { if parentid == "trash" { - jsonstr = aliyun.ApiTrashFileList(marker) + jsonstr = aliyun.ApiTrashFileList(boxid, marker) if len(jsonstr) > 60 { break } } else if parentid == "favorite" { - jsonstr = aliyun.ApiFavorFileList(marker) + jsonstr = aliyun.ApiFavorFileList(boxid, marker) + if len(jsonstr) > 60 { + break + } + } else if strings.HasPrefix(parentid, "xiangce:") { + parentid = parentid[len("xiangce:"):] + jsonstr = aliyun.ApiFileList(boxid, parentid, marker) if len(jsonstr) > 60 { break } @@ -331,7 +408,7 @@ func HookActionFileList(parentid string, marker string) string { jsonstr = `{"code":0,"message":"success","next_marker":"","items":[]}` break } else { - jsonstr = aliyun.ApiFileList(parentid, marker) + jsonstr = aliyun.ApiFileList(boxid, parentid, marker) if len(jsonstr) > 60 { break } @@ -339,3 +416,14 @@ func HookActionFileList(parentid string, marker string) string { } return jsonstr } + +func GetBoxID(box string) string { + if box == "box" { + return aliyun.GetUserBoxID() + } else if box == "sbox" { + return aliyun.GetUserSBoxID() + } else if box == "xiangce" { + return aliyun.GetUserXiangCeID() + } + return "" +} diff --git a/aliserver/upload/UploadModel.go b/aliserver/upload/UploadModel.go index 42248ae..e391117 100644 --- a/aliserver/upload/UploadModel.go +++ b/aliserver/upload/UploadModel.go @@ -15,6 +15,7 @@ type UploadFileModel struct { LocalPath string `json:"localpath"` IsDir bool `json:"IsDir"` ParentID string `json:"ParentID"` + BoxID string `json:"BoxID"` //downworker DownTime int64 `json:"DownTime"` DownSize int64 `json:"DownSize"` diff --git a/aliserver/upload/UploadWork.go b/aliserver/upload/UploadWork.go index d831514..b5f2f34 100644 --- a/aliserver/upload/UploadWork.go +++ b/aliserver/upload/UploadWork.go @@ -1,6 +1,7 @@ package upload import ( + "aliserver/aliyun" "aliserver/data" "aliserver/utils" "encoding/json" @@ -114,7 +115,7 @@ func UploadAdd(Item *UploadFileModel) error { } //UploadingAdd 创建一个上传任务 -func UploadingAdd(UserID, localpath, uptoname, ParentID string, size int64, isdir bool, dtime int64) (upload *UploadFileModel, err error) { +func UploadingAdd(UserID, localpath, uptoname, boxid string, ParentID string, size int64, isdir bool, dtime int64) (upload *UploadFileModel, err error) { defer func() { if errr := recover(); errr != nil { log.Println("UploadingAddError ", " error=", errr) @@ -136,6 +137,7 @@ func UploadingAdd(UserID, localpath, uptoname, ParentID string, size int64, isdi LocalPath: localpath, IsDir: isdir, ParentID: ParentID, + BoxID: boxid, DownTime: dtime, // time.Now().UnixNano() DownSpeedStr: "", @@ -257,9 +259,12 @@ func downingMakeDowning(TaskCountMax int, UploadingCount int) { } func MakeUpload(item *UploadFileModel) { - threadcount := int(1) //阿里云盘必须按顺序,一个一个的上传,不能并发 + threadcount := int(1) //阿里云盘必须按顺序,同一个文件的全部分片一个一个的按顺序上传,不能并发 + if item.BoxID == "" { + item.BoxID = aliyun.GetUserBoxID() //修正旧版本升级 + } if item.Uploader == nil { - info, err := NewBigUploadInfoAutoBlock(item.ParentID, item.LocalPath, item.Name, item.Size, item.IsDir, 1024*1024*10, threadcount) + info, err := NewBigUploadInfoAutoBlock(item.BoxID, item.ParentID, item.LocalPath, item.Name, item.Size, item.IsDir, 1024*1024*10, threadcount) if err != nil { b, _ := json.Marshal(*item) log.Println("上传启动失败", string(b)) //不可能出现 diff --git a/aliserver/upload/bigupload.go b/aliserver/upload/bigupload.go index 2d2f052..6d03a8d 100644 --- a/aliserver/upload/bigupload.go +++ b/aliserver/upload/bigupload.go @@ -127,7 +127,7 @@ func (worker *BigUploadWorker) StartUploadSync() { if worker.UploadInfo.FileFullPath == "miaochuan" { //单独执行秒传 - same, _, _, err := aliyun.UploadCreatFile(worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileSize, worker.UploadInfo.FileHash) + same, _, _, _, err := aliyun.UploadCreatFile(worker.UploadInfo.BoxID, worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileSize, worker.UploadInfo.FileHash) if err != nil { worker._UpdateStateError(err.Error()) } else if same { @@ -141,13 +141,13 @@ func (worker *BigUploadWorker) StartUploadSync() { if worker.UploadInfo.FileHash == "dir" { //单独执行文件夹 - DirID, err3 := aliyun.UploadCreatForder(worker.UploadInfo.ParentID, worker.UploadInfo.FileName) + DirID, err3 := aliyun.UploadCreatForder(worker.UploadInfo.BoxID, worker.UploadInfo.ParentID, worker.UploadInfo.FileName) if err3 != nil { worker._UpdateStateError("云盘创建路径失败:" + worker.UploadInfo.FileName) return } //遍历文件夹,获取文件树,并在网盘里创建对应的文件夹 - SelectFileList, err := GetFilesWithDir(DirID, worker.UploadInfo.FileFullPath) + SelectFileList, err := GetFilesWithDir(worker.UploadInfo.BoxID, DirID, worker.UploadInfo.FileFullPath) if err != nil { worker._UpdateStateError(err.Error()) return @@ -204,7 +204,7 @@ func (worker *BigUploadWorker) StartUploadSync() { } //这里是,联网获取阿里的UploadID,检测是否能秒传 if worker.UploadInfo.UploadID == "" { - same, uploadid, fileid, err := aliyun.UploadCreatFile(worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileSize, worker.UploadInfo.FileHash) + same, uploadid, fileid, _, err := aliyun.UploadCreatFile(worker.UploadInfo.BoxID, worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileSize, worker.UploadInfo.FileHash) if err != nil { worker._UpdateStateError(err.Error()) worker.finishUpload() @@ -302,7 +302,7 @@ func (worker *BigUploadWorker) finishUpload() { if worker.IsCompleted && worker.IsMakeFile == false { //合并文件 worker.FailedMessage = "正在合并文件" - errmk := aliyun.UploadFileComplete(worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileID, worker.UploadInfo.UploadID) + errmk := aliyun.UploadFileComplete(worker.UploadInfo.BoxID, worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileID, worker.UploadInfo.UploadID) worker.FailedMessage = "" //fmt.Println(time.Now(), "MakeFile", errmk) if errmk != nil { @@ -412,7 +412,7 @@ func blockWorkerUpload(worker *BigUploadWorker, blockIndex int) (err error) { return errors.New("upload Read Buff From File Error") } //联网读取url - uploadurl, err := aliyun.UploadFilePartUrl(worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileID, worker.UploadInfo.UploadID, blockIndex+1, blockSize) + uploadurl, err := aliyun.UploadFilePartUrl(worker.UploadInfo.BoxID, worker.UploadInfo.ParentID, worker.UploadInfo.FileName, worker.UploadInfo.FileID, worker.UploadInfo.UploadID, blockIndex+1, blockSize) if err != nil { return err } diff --git a/aliserver/upload/biguploadinfo.go b/aliserver/upload/biguploadinfo.go index ad96e6e..844d9a7 100644 --- a/aliserver/upload/biguploadinfo.go +++ b/aliserver/upload/biguploadinfo.go @@ -12,6 +12,7 @@ type BigUploadInfo struct { //上传任务的ID UploadID string UploadTime int64 + BoxID string ParentID string FileID string @@ -81,7 +82,7 @@ func (info *BigUploadInfo) creatBlockList() error { } //NewBigUploadInfoAutoBlock 创建一个文件上传信息(根据threadMax自动计算分片大小)(err 没有文件大小联网请求大小出错) -func NewBigUploadInfoAutoBlock(ParentID string, FileFullPath string, FileName string, fileSize int64, isdir bool, blockSize int64, threadMax int) (info *BigUploadInfo, err error) { +func NewBigUploadInfoAutoBlock(boxid string, ParentID string, FileFullPath string, FileName string, fileSize int64, isdir bool, blockSize int64, threadMax int) (info *BigUploadInfo, err error) { if blockSize <= 0 { blockSize = 1024 * 1024 * 4 //必须是4MB的倍数 } @@ -91,6 +92,7 @@ func NewBigUploadInfoAutoBlock(ParentID string, FileFullPath string, FileName st info = &BigUploadInfo{ UploadID: "", + BoxID: boxid, ParentID: ParentID, FileFullPath: "", FileName: FileName, diff --git a/aliserver/upload/uploadmanage.go b/aliserver/upload/uploadmanage.go index 5ce6874..b2f64a2 100644 --- a/aliserver/upload/uploadmanage.go +++ b/aliserver/upload/uploadmanage.go @@ -21,6 +21,7 @@ type UploadSelectModel struct { Name string `json:"name"` IsDir bool `json:"IsDir"` ParentID string `json:"ParentID"` + BoxID string `json:"BoxID"` } //UploadingList 上传中文件列表(显示小->大) @@ -124,7 +125,7 @@ func UploadList() string { } //UploadFile 上传一堆文件(只有文件) -func UploadFile(ParentID string, fileList []string) string { +func UploadFile(boxid string, ParentID string, fileList []string) string { if ParentID == "" { ParentID = "root" @@ -145,6 +146,7 @@ func UploadFile(ParentID string, fileList []string) string { Path: fileList[m], Name: fi.Name(), ParentID: ParentID, + BoxID: boxid, } SelectFileList = append(SelectFileList, &m) } @@ -153,7 +155,7 @@ func UploadFile(ParentID string, fileList []string) string { } //UploadDir 上传一个文件夹(只有一个) -func UploadDir(ParentID string, DirPath string) string { +func UploadDir(boxid string, ParentID string, DirPath string) string { if ParentID == "" { ParentID = "root" @@ -166,12 +168,12 @@ func UploadDir(ParentID string, DirPath string) string { var SelectFileList = make([]*UploadSelectModel, 0, 100) fi, err := os.Stat(DirPath) if err == nil && fi != nil && fi.IsDir() == true { - DirID, err3 := aliyun.UploadCreatForder(ParentID, fi.Name()) + DirID, err3 := aliyun.UploadCreatForder(boxid, ParentID, fi.Name()) if err3 != nil { return utils.ToErrorMessageJSON("网盘创建路径失败:" + fi.Name()) } //遍历文件夹,获取文件树,并在网盘里创建对应的文件夹 - SelectFileList, err = GetFilesWithDir(DirID, DirPath) + SelectFileList, err = GetFilesWithDir(boxid, DirID, DirPath) if err != nil { return utils.ToErrorMessageJSON(err.Error()) } @@ -181,6 +183,50 @@ func UploadDir(ParentID string, DirPath string) string { return UploadSelectFile(UserID, ParentID, SelectFileList) } + +func UploadFileAndDir(boxid string, ParentID string, fileList []string) string { + + if ParentID == "" { + ParentID = "root" + } + UserID := aliyun.GetUserID() + if UserID == "" { + return utils.ToErrorMessageJSON("还没有登录阿里云盘账号") + } + + var SelectFileList = make([]*UploadSelectModel, 0, 100) + + LEN := len(fileList) + for m := 0; m < LEN; m++ { + fi, err := os.Stat(fileList[m]) + if err == nil && fi != nil { + if fi.IsDir() == false { + m := UploadSelectModel{ + Size: fi.Size(), + Path: fileList[m], + Name: fi.Name(), + ParentID: ParentID, + BoxID: boxid, + } + SelectFileList = append(SelectFileList, &m) + } else { + DirID, err3 := aliyun.UploadCreatForder(boxid, ParentID, fi.Name()) + if err3 != nil { + return utils.ToErrorMessageJSON("网盘创建路径失败:" + fi.Name()) + } + //遍历文件夹,获取文件树,并在网盘里创建对应的文件夹 + clist, err := GetFilesWithDir(boxid, DirID, fileList[m]) + if err != nil { + return utils.ToErrorMessageJSON(err.Error()) + } + SelectFileList = append(SelectFileList, clist...) + } + } + } + + return UploadSelectFile(UserID, ParentID, SelectFileList) +} + func UploadSelectFile(UserID string, ParentID string, SelectFileList []*UploadSelectModel) string { LEN := len(SelectFileList) if LEN == 0 { @@ -192,7 +238,7 @@ func UploadSelectFile(UserID string, ParentID string, SelectFileList []*UploadSe uploadinglist := make([]*UploadFileModel, 0, LEN) for i := 0; i < LEN; i++ { item := SelectFileList[i] - uploading, err := UploadingAdd(UserID, item.Path, item.Name, item.ParentID, item.Size, item.IsDir, dtime) + uploading, err := UploadingAdd(UserID, item.Path, item.Name, item.BoxID, item.ParentID, item.Size, item.IsDir, dtime) if err == nil { uploadinglist = append(uploadinglist, uploading) filecount++ @@ -223,7 +269,7 @@ func UploadSelectFile(UserID string, ParentID string, SelectFileList []*UploadSe } // GetFilesWithDir 获取指定目录下的所有文件和目录 -func GetFilesWithDir(ParentID, DirPath string) (files []*UploadSelectModel, err error) { +func GetFilesWithDir(boxid string, ParentID, DirPath string) (files []*UploadSelectModel, err error) { dir, err := ioutil.ReadDir(DirPath) if err != nil { return nil, err @@ -237,6 +283,7 @@ func GetFilesWithDir(ParentID, DirPath string) (files []*UploadSelectModel, err Path: filepath.Join(DirPath, fi.Name()), Name: fi.Name(), ParentID: ParentID, + BoxID: boxid, } if fi.IsDir() { m.IsDir = true diff --git a/aliserver/utils/ActionResult.go b/aliserver/utils/ActionResult.go index f5ff8f4..9d68ad1 100644 --- a/aliserver/utils/ActionResult.go +++ b/aliserver/utils/ActionResult.go @@ -94,9 +94,11 @@ func ToJSONString(str string) string { if str == "" { return "" } - str = strings.Replace(str, `\`, `\\`, -1) - str = strings.Replace(str, `"`, `\"`, -1) - str = strings.Replace(str, `\r`, `\\r`, -1) - str = strings.Replace(str, `\n`, `\\n`, -1) - return str + mapInstance := make(map[string]interface{}) + mapInstance["message"] = str + jsonStr, _ := json.Marshal(mapInstance) + js := string(jsonStr) + + js = js[12 : len(js)-2] + return js } diff --git a/aliserver/utils/FileHelper.go b/aliserver/utils/FileHelper.go index 0566948..f01e025 100644 --- a/aliserver/utils/FileHelper.go +++ b/aliserver/utils/FileHelper.go @@ -137,23 +137,26 @@ func ExePath() string { //ClearFileName 清理文件名 func ClearFileName(name string, file bool) string { - name = filepath.Clean(name) - if name == "." { - return "" + if name != "." { + name = filepath.Clean(name) + if name == "." { + return "" + } } + //< > / \ | : * ? - name = strings.Replace(name, "<", "", -1) - name = strings.Replace(name, ">", "", -1) - name = strings.Replace(name, "|", "", -1) - name = strings.Replace(name, ":", "", -1) - name = strings.Replace(name, "*", "", -1) - name = strings.Replace(name, "?", "", -1) + name = strings.Replace(name, "<", "_", -1) + name = strings.Replace(name, ">", "_", -1) + name = strings.Replace(name, "|", "_", -1) + name = strings.Replace(name, ":", "_", -1) + name = strings.Replace(name, "*", "_", -1) + name = strings.Replace(name, "?", "_", -1) name = strings.Replace(name, "\\", "/", -1) //name = strings.Replace(name, "//", "/", -1) //name = strings.Replace(name, "//", "/", -1) //name = strings.Replace(name, "..", ".", -1) if file { - name = strings.Replace(name, "/", "", -1) //文件名清理掉/ + name = strings.Replace(name, "/", "_", -1) //文件名清理掉/ } else { var pathchar = string(os.PathSeparator) //mac linux if pathchar != "/" { @@ -162,3 +165,11 @@ func ClearFileName(name string, file bool) string { } return name } + +func JoinFilePath(dir string, file string) string { + if file != "." { + return filepath.Join(dir, file) + } + var pathchar = string(os.PathSeparator) + return strings.TrimRight(strings.TrimRight(dir, "\\"), "/") + pathchar + file +} diff --git a/aliserver/utils/darwin.go b/aliserver/utils/darwin.go index 9d7efa4..7940409 100644 --- a/aliserver/utils/darwin.go +++ b/aliserver/utils/darwin.go @@ -74,7 +74,7 @@ func RunAria() (bool, error) { } pid := strconv.Itoa(os.Getpid()) - args := []string{"--conf-path=aria2.conf", "--stop-with-process=" + pid} + args := []string{"--conf-path=aria2.conf", "--stop-with-process=" + pid, "-D"} cmd := exec.Command(aria2c, args...) cmd.Dir = dir @@ -91,7 +91,6 @@ func ProcessCheck() bool { if err != nil { return true } - log.Println(string(result)) var index = strings.Index(string(result), "/Contents/MacOS/alixby") return index > 0 } diff --git a/aliserver/utils/linux.go b/aliserver/utils/linux.go index e569ce1..615116a 100644 --- a/aliserver/utils/linux.go +++ b/aliserver/utils/linux.go @@ -55,7 +55,7 @@ func RunAria() (bool, error) { } pid := strconv.Itoa(os.Getpid()) - args := []string{"--conf-path=aria2.conf", "--stop-with-process=" + pid} + args := []string{"--conf-path=aria2.conf", "--stop-with-process=" + pid, "-D"} cmd := exec.Command(aria2c, args...) cmd.Dir = dir diff --git a/aliserver/utils/win.go b/aliserver/utils/win.go index b7fba8a..cef2bb2 100644 --- a/aliserver/utils/win.go +++ b/aliserver/utils/win.go @@ -73,7 +73,7 @@ func RunAria() (bool, error) { } pid := strconv.Itoa(os.Getpid()) - args := []string{"--conf-path=aria2.conf", "--stop-with-process=" + pid} + args := []string{"--conf-path=aria2.conf", "--stop-with-process=" + pid, "-D"} cmd := exec.Command(aria2c, args...) cmd.Dir = dir diff --git a/alixby/.flutter-plugins b/alixby/.flutter-plugins new file mode 100644 index 0000000..dbe7629 --- /dev/null +++ b/alixby/.flutter-plugins @@ -0,0 +1,14 @@ +# This is a generated file; do not edit or check into version control. +dropfiles_window=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\dropfiles_window-0.0.2\\ +file_selector=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\file_selector-0.8.2\\ +file_selector_web=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\file_selector_web-0.8.1\\ +file_selector_windows=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\file_selector_windows-0.0.2\\ +path_provider=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\path_provider-2.0.1\\ +path_provider_linux=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\path_provider_linux-2.0.0\\ +path_provider_macos=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\path_provider_macos-2.0.0\\ +path_provider_windows=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\path_provider_windows-2.0.1\\ +url_launcher=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\url_launcher-6.0.3\\ +url_launcher_linux=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\url_launcher_linux-2.0.0\\ +url_launcher_macos=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\url_launcher_macos-2.0.0\\ +url_launcher_web=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\url_launcher_web-2.0.0\\ +url_launcher_windows=D:\\flutter\\.pub-cache\\hosted\\pub.flutter-io.cn\\url_launcher_windows-2.0.0\\ diff --git a/alixby/.flutter-plugins-dependencies b/alixby/.flutter-plugins-dependencies new file mode 100644 index 0000000..92301db --- /dev/null +++ b/alixby/.flutter-plugins-dependencies @@ -0,0 +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 diff --git a/alixby/.gitignore b/alixby/.gitignore deleted file mode 100644 index 0fa6b67..0000000 --- a/alixby/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/alixby/.metadata b/alixby/.metadata deleted file mode 100644 index be74985..0000000 --- a/alixby/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: adc687823a831bbebe28bdccfac1a628ca621513 - channel: stable - -project_type: app diff --git a/alixby/README.md b/alixby/README.md deleted file mode 100644 index c1a81c9..0000000 --- a/alixby/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# alixby - -阿里云盘小白羊版 - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) - -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/alixby/assets/fonts/OPPOSans-R.ttf b/alixby/assets/fonts/OPPOSans-R.ttf index 72e1faa..ddadfba 100644 Binary files a/alixby/assets/fonts/OPPOSans-R.ttf and b/alixby/assets/fonts/OPPOSans-R.ttf differ diff --git a/alixby/assets/fonts/iconfont.ttf b/alixby/assets/fonts/iconfont.ttf index 1488121..19c99f3 100644 Binary files a/alixby/assets/fonts/iconfont.ttf and b/alixby/assets/fonts/iconfont.ttf differ diff --git a/alixby/lib/api/AliFile.dart b/alixby/lib/api/AliFile.dart index baf59d1..959b610 100644 --- a/alixby/lib/api/AliFile.dart +++ b/alixby/lib/api/AliFile.dart @@ -8,8 +8,9 @@ import 'package:flutter/material.dart'; import 'HttpHelper.dart'; class FileListModel { - FileListModel(this.time, this.key, this.name); + FileListModel(this.time, this.box, this.key, this.name); int time = 0; + String box = ""; String key = ""; String name = ""; List list = []; @@ -22,7 +23,8 @@ class AliFile { AliFile(); //name updated_at created_at size - static Future apiFileList(int time, String parentid, String name, {String marker = ""}) async { + static Future apiFileList(int time, String box, String parentid, String name, + {String marker = ""}) async { var fcHide = BotToast.showCustomLoading( toastBuilder: (cancelFunc) { return APILoadingWidget(cancelFunc: cancelFunc, title: (marker == "" ? '列文件:' : "分页中:") + name); @@ -37,17 +39,18 @@ class AliFile { backgroundColor: Colors.transparent); if (parentid == "") parentid = "root"; - var model = FileListModel(time, parentid, name); + var model = FileListModel(time, box, parentid, name); if (marker != "") model.isMarker = true; try { - var result = await HttpHelper.postToServer("ApiFileList", jsonEncode({'parentid': parentid, "marker": marker})); + var result = await HttpHelper.postToServer( + "ApiFileList", jsonEncode({'box': box, 'parentid': parentid, "marker": marker})); if (result["code"] == 0) { model.next_marker = result["next_marker"] as String; var items = result["items"]; List list = []; for (int i = 0; i < items.length; i++) { - var m = new FileItem.fromJson(items[i]); + var m = new FileItem.fromJson(box, items[i]); list.add(m); } model.list = list; @@ -66,7 +69,7 @@ class AliFile { } //name updated_at created_at size - static Future apiDirList(String parentid, String name) async { + static Future apiDirList(String box, String parentid, String name) async { var fcHide = BotToast.showCustomLoading( toastBuilder: (cancelFunc) { return APILoadingWidget(cancelFunc: cancelFunc, title: '列文件夹:' + name); @@ -81,16 +84,16 @@ class AliFile { backgroundColor: Colors.transparent); if (parentid == "") parentid = "root"; - var model = FileListModel(0, parentid, name); + var model = FileListModel(0, box, parentid, name); try { - var result = await HttpHelper.postToServer("ApiDirList", jsonEncode({'parentid': parentid})); + var result = await HttpHelper.postToServer("ApiDirList", jsonEncode({'box': box, 'parentid': parentid})); if (result["code"] == 0) { var items = result["items"]; List list = []; for (int i = 0; i < items.length; i++) { if (items[i]["key"] == "break") continue; - var m = new FileItem.fromJson(items[i]); + var m = new FileItem.fromJson(box, items[i]); list.add(m); } model.list = list; @@ -99,7 +102,7 @@ class AliFile { BotToast.showText(text: "拉取 " + name + " 失败"); } } catch (e) { - print('apiFileList ' + e.toString()); + print('apiDirList ' + e.toString()); model.key = "error"; BotToast.showText(text: "拉取 " + name + " 失败"); } finally { @@ -108,11 +111,10 @@ class AliFile { return model; } - static Future apiCreatForder(String parentkey, String dirname) async { + static Future apiCreatForder(String box, String parentkey, String dirname) async { try { - print('apiCreatForder'); - var result = - await HttpHelper.postToServer("ApiCreatForder", jsonEncode({'parentid': parentkey, 'name': dirname})); + var result = await HttpHelper.postToServer( + "ApiCreatForder", jsonEncode({'box': box, 'parentid': parentkey, 'name': dirname})); if (result["code"] == 0 && result["file_id"] != "") { return "success"; } @@ -122,10 +124,10 @@ class AliFile { return "error"; } - static Future apiRename(String key, String newname) async { + static Future apiRename(String box, String key, String newname) async { try { - print('apiRename'); - var result = await HttpHelper.postToServer("ApiRename", jsonEncode({'file_id': key, 'name': newname})); + var result = + await HttpHelper.postToServer("ApiRename", jsonEncode({'box': box, 'file_id': key, 'name': newname})); if (result["code"] == 0 && result["file_id"] != "") { return "success"; } @@ -135,10 +137,52 @@ class AliFile { return "error"; } - static Future apiTrashBatch(List filelist) async { + static Future apiRenameBatch(String box, List keylist, List namelist) async { + try { + var result = await HttpHelper.postToServer( + "ApiRenameBatch", jsonEncode({'box': box, 'keylist': keylist, "namelist": namelist})); + if (result["code"] == 0) { + return result["count"]; + } + } catch (e) { + print('apiRenameBatch ' + e.toString()); + } + return 0; + } + + // ignore: non_constant_identifier_names + static Future> apiUncompress(String box, String file_id, String target_file_id, String password) async { + try { + var result = await HttpHelper.postToServer("ApiUncompress", + jsonEncode({'box': box, 'file_id': file_id, 'target_file_id': target_file_id, "password": password})); + if (result["code"] == 0 && result["file_id"] != "") { + return [result["state"], result["task_id"], result["domain_id"], result["file_id"]]; + } else { + return [result["message"]]; + } + } catch (e) { + print('apiUncompress ' + e.toString()); + } + return ["error"]; + } + + // ignore: non_constant_identifier_names + static Future> apiUncompressCheck(String box, String file_id, String domain_id, String task_id) async { + try { + var result = await HttpHelper.postToServer("ApiUncompressCheck", + jsonEncode({'box': box, 'file_id': file_id, 'domain_id': domain_id, "task_id": task_id})); + if (result["code"] == 0 && result["file_id"] != "") { + return [result["state"], result["progress"].toString()]; + } + } catch (e) { + print('apiUncompressCheck ' + e.toString()); + } + return ["error"]; + } + + static Future apiTrashBatch(String box, List filelist) async { try { - print('apiTrashBatch'); - var result = await HttpHelper.postToServer("ApiTrashBatch", jsonEncode({'filelist': filelist})); + var result = await HttpHelper.postToServer("ApiTrashBatch", jsonEncode({'box': box, 'filelist': filelist})); if (result["code"] == 0) { return result["count"]; } @@ -148,11 +192,10 @@ class AliFile { return 0; } - static Future apiMoveBatch(List filelist, String movetoid) async { + static Future apiMoveBatch(String box, List filelist, String movetobox, String movetoid) async { try { - print('apiMoveBatch'); - var result = - await HttpHelper.postToServer("ApiMoveBatch", jsonEncode({'filelist': filelist, "movetoid": movetoid})); + var result = await HttpHelper.postToServer( + "ApiMoveBatch", jsonEncode({'box': box, 'filelist': filelist, "movetobox": movetobox, "movetoid": movetoid})); if (result["code"] == 0) { return result["count"]; } @@ -162,10 +205,25 @@ class AliFile { return 0; } - static Future apiTrashDeleteBatch(List filelist) async { + static Future apiCopyBatch( + String box, String parentid, List filelist, String copytobox, String copytoid) async { try { - print('apiTrashDeleteBatch'); - var result = await HttpHelper.postToServer("ApiTrashDeleteBatch", jsonEncode({'filelist': filelist})); + var result = await HttpHelper.postToServer( + "ApiCopyBatch", + jsonEncode( + {'box': box, "parentid": parentid, 'filelist': filelist, "copytobox": copytobox, "copytoid": copytoid})); + if (result["code"] == 0) { + return result["filecount"]; + } + } catch (e) { + print('apiCopyBatch ' + e.toString()); + } + return 0; + } + + static Future apiTrashDeleteBatch(String box, List filelist) async { + try { + var result = await HttpHelper.postToServer("ApiTrashDeleteBatch", jsonEncode({'box': box, 'filelist': filelist})); if (result["code"] == 0) { return result["count"]; } @@ -175,10 +233,10 @@ class AliFile { return 0; } - static Future apiTrashRestoreBatch(List filelist) async { + static Future apiTrashRestoreBatch(String box, List filelist) async { try { - print('apiTrashRestoreBatch'); - var result = await HttpHelper.postToServer("ApiTrashRestoreBatch", jsonEncode({'filelist': filelist})); + var result = + await HttpHelper.postToServer("ApiTrashRestoreBatch", jsonEncode({'box': box, 'filelist': filelist})); if (result["code"] == 0) { return result["count"]; } @@ -188,11 +246,10 @@ class AliFile { return 0; } - static Future apiFavorBatch(bool isfavor, List filelist) async { + static Future apiFavorBatch(String box, bool isfavor, List filelist) async { try { - print('apiFavorBatch'); - var result = - await HttpHelper.postToServer("ApiFavorBatch", jsonEncode({"isfavor": isfavor, 'filelist': filelist})); + var result = await HttpHelper.postToServer( + "ApiFavorBatch", jsonEncode({'box': box, "isfavor": isfavor, 'filelist': filelist})); if (result["code"] == 0) { return result["count"]; } diff --git a/alixby/lib/api/AliLogin.dart b/alixby/lib/api/AliLogin.dart index 8fb91a9..ab371cb 100644 --- a/alixby/lib/api/AliLogin.dart +++ b/alixby/lib/api/AliLogin.dart @@ -4,6 +4,7 @@ import 'HttpHelper.dart'; class AliUserInfo { String userID = ""; String userName = ""; + String userFace = ""; String panUsed = ""; String panTotal = ""; // ignore: non_constant_identifier_names @@ -19,7 +20,6 @@ class AliLogin { static Future apiUserInfo() async { try { - print('apiUserInfo'); var result = await HttpHelper.postToServer("ApiUserInfo", ""); if (result["code"] == 0) { String infojson = result["info"]; @@ -28,6 +28,7 @@ class AliLogin { var user = AliUserInfo(); user.userID = info["userID"]; user.userName = info["userName"]; + user.userFace = info["userFace"]; user.panUsed = info["panUsed"]; user.panTotal = info["panTotal"]; user.drive_size = info["drive_size"]; @@ -44,7 +45,6 @@ class AliLogin { static Future apiUserLogoff() async { try { - print('apiUserLogoff'); await HttpHelper.postToServer("ApiUserLogoff", ""); } catch (e) { print('apiUserLogoff ' + e.toString()); @@ -53,7 +53,6 @@ class AliLogin { static Future apiQrcodeGenerate() async { try { - print('apiQrcodeGenerate'); var result = await HttpHelper.postToServer("ApiQrcodeGenerate", ""); if (result["code"] == 0) return result["codeContent"]; } catch (e) { @@ -64,7 +63,6 @@ class AliLogin { static Future apiQrcodeQuery() async { try { - print('apiQrcodeQuery'); var result = await HttpHelper.postToServer("ApiQrcodeQuery", ""); if (result["code"] == 0) return result["loginResult"]; } catch (e) { @@ -76,7 +74,6 @@ class AliLogin { static Future apiTokenRefresh(String refreshToken) async { if (refreshToken == "") return "retry"; try { - print('apiTokenRefresh'); var result = await HttpHelper.postToServer("ApiTokenRefresh", jsonEncode({'refreshToken': refreshToken})); if (result["code"] == 0) return result["loginResult"]; } catch (e) { diff --git a/alixby/lib/api/Downloader.dart b/alixby/lib/api/Downloader.dart index 0f855e1..1e8d83d 100644 --- a/alixby/lib/api/Downloader.dart +++ b/alixby/lib/api/Downloader.dart @@ -6,11 +6,10 @@ import 'HttpHelper.dart'; class Downloader { //创建下载任务 - static Future goDownFile(String parentid, String savepath, List filelist) async { + static Future goDownFile(String box, String parentid, String savepath, List filelist) async { try { - print('goDownFile'); var result = await HttpHelper.postToServer( - "GoDownFile", jsonEncode({"parentid": parentid, "savepath": savepath, 'filelist': filelist})); + "GoDownFile", jsonEncode({'box': box, "parentid": parentid, "savepath": savepath, 'filelist': filelist})); if (result["code"] == 0) { return result["filecount"]; } @@ -24,7 +23,6 @@ class Downloader { static Future goDowningList() async { var downdata = PageRightDownModel(); try { - print('goDowningList'); var result = await HttpHelper.postToServer("GoDowningList", ""); if (result["code"] == 0) { downdata.filecount = result["filecount"]; @@ -45,7 +43,6 @@ class Downloader { //查询当前已下载的任务 static Future goDownedList() async { try { - print('goDownedList '); var result = await HttpHelper.postToServer("GoDownedList", ""); if (result["code"] == 0) { var downdata = PageRightDownModel(); @@ -66,7 +63,6 @@ class Downloader { static Future goDowningStart(String downid) async { try { - print('goDowningStart'); var result = await HttpHelper.postToServer("GoDowningStart", jsonEncode({"downid": downid})); if (result["code"] == 0) { return "success"; @@ -79,7 +75,6 @@ class Downloader { static Future goDowningStop(String downid) async { try { - print('goDowningStop'); var result = await HttpHelper.postToServer("GoDowningStop", jsonEncode({"downid": downid})); if (result["code"] == 0) { return "success"; @@ -92,7 +87,6 @@ class Downloader { static Future goDowningDelete(String downid) async { try { - print('goDowningDelete'); var result = await HttpHelper.postToServer("GoDowningDelete", jsonEncode({"downid": downid})); if (result["code"] == 0) { return "success"; @@ -105,7 +99,6 @@ class Downloader { static Future goDowningForder(String downid) async { try { - print('goDowningForder'); var result = await HttpHelper.postToServer("GoDowningForder", jsonEncode({"downid": downid})); if (result["code"] == 0) { return "success"; @@ -118,7 +111,6 @@ class Downloader { static Future goDownedDelete(String downid) async { try { - print('goDownedDelete '); var result = await HttpHelper.postToServer("GoDownedDelete", jsonEncode({"downid": downid})); if (result["code"] == 0) { return "success"; @@ -131,7 +123,6 @@ class Downloader { static Future goDownedForder(String downid) async { try { - print('goDownedForder'); var result = await HttpHelper.postToServer("GoDownedForder", jsonEncode({"downid": downid})); if (result["code"] == 0) { return "success"; @@ -142,10 +133,9 @@ class Downloader { return "error"; } - static Future goPlay(String key) async { + static Future goPlay(String box, String key) async { try { - print('goPlay'); - var result = await HttpHelper.postToServer("GoPlay", jsonEncode({"file_id": key})); + var result = await HttpHelper.postToServer("GoPlay", jsonEncode({'box': box, "file_id": key})); if (result["code"] == 0) { return "success"; } @@ -155,10 +145,9 @@ class Downloader { return "error"; } - static Future goImage(String key) async { + static Future goImage(String box, String key) async { try { - print('goImage'); - var result = await HttpHelper.postToServer("GoImage", jsonEncode({"file_id": key})); + var result = await HttpHelper.postToServer("GoImage", jsonEncode({'box': box, "file_id": key})); if (result["code"] == 0) { return result["url"]; } @@ -168,10 +157,9 @@ class Downloader { return "error"; } - static Future goText(String key) async { + static Future goText(String box, String key) async { try { - print('goText'); - var result = await HttpHelper.postToServer("GoText", jsonEncode({"file_id": key})); + var result = await HttpHelper.postToServer("GoText", jsonEncode({'box': box, "file_id": key})); if (result["code"] == 0) { return result["text"]; } diff --git a/alixby/lib/api/GoServer.dart b/alixby/lib/api/GoServer.dart index fc0d906..432a046 100644 --- a/alixby/lib/api/GoServer.dart +++ b/alixby/lib/api/GoServer.dart @@ -47,9 +47,10 @@ class GoServer { hideCloseButton: true, duration: null); } else { - Global.userState.loadUser(); + Global.userState.loadUser(true); Global.pageDownState.runTimer(); Global.panFileState.runTimer(); + Global.xiangceFileState.runTimer(); Global.pageRssMiaoChuanState.refreshLink(); } return true; diff --git a/alixby/lib/api/HttpHelper.dart b/alixby/lib/api/HttpHelper.dart index 3031165..8227ab0 100644 --- a/alixby/lib/api/HttpHelper.dart +++ b/alixby/lib/api/HttpHelper.dart @@ -26,6 +26,7 @@ class HttpHelper { return jsonDecode("{\"code\":503,\"message\":\"error\"}"); } } catch (exception) { + print(exception); return jsonDecode("{\"code\":503,\"message\":\"error\"}"); } } diff --git a/alixby/lib/api/Linker.dart b/alixby/lib/api/Linker.dart index c02e503..ae7fe2f 100644 --- a/alixby/lib/api/Linker.dart +++ b/alixby/lib/api/Linker.dart @@ -1,7 +1,13 @@ import 'dart:convert'; import 'package:alixby/api/HttpHelper.dart'; +import 'package:alixby/models/PageRightFileItem.dart'; import 'package:alixby/models/PageRightMiaoChuanItem.dart'; +import 'package:alixby/utils/APILoadingWidget.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; class LinkFileModel { LinkFileModel(); @@ -65,14 +71,19 @@ class LinkFileModel { } } +class LinkSearchModel { + List searchlist = []; + int pageIndex = 0; + int pageCount = 0; + int fileCount = 0; +} + class Linker { Linker(); -//查询当前已下载的任务 static Future> goLinkList() async { List filelist = []; try { - print('goLinkList '); var result = await HttpHelper.postToServer("GoLinkList", ""); if (result["code"] == 0) { var items = result["filelist"]; @@ -90,7 +101,6 @@ class Linker { static Future goLinkDelete(String link) async { try { - print('goLinkDelete '); var result = await HttpHelper.postToServer("GoLinkDelete", jsonEncode({"link": link})); if (result["code"] == 0) { return "success"; @@ -101,39 +111,39 @@ class Linker { return "error"; } - static Future goLinkCreat(String jianjie, bool ispublic, String password, String outday, String outsave, - String parentid, List filelist) async { + static Future> goLinkCreatFile( + String filename, String jianjie, String box, String parentid, List filelist) async { + List list = []; try { var result = await HttpHelper.postToServer( - "GoLinkCreat", - jsonEncode({ - "jianjie": jianjie, - "ispublic": ispublic, - "password": password, - "outday": outday, - "outsave": outsave, - "parentid": parentid, - "filelist": filelist - })); + "GoLinkCreatFile", + jsonEncode( + {"jianjie": jianjie, "filename": filename, 'box': box, "parentid": parentid, "filelist": filelist})); if (result["code"] == 0) { - return result["link"]; + list.add(result["info"]); //n个文件 n个文件夹 + list.add(result["aliyun"]); //aliyunpan://xxxx + return list; } else if (result["code"] == 503) { - return result["message"]; + list.add(result["message"]); + return list; } } catch (e) { - print('goLinkCreat ' + e.toString()); + print('goLinkCreatFile ' + e.toString()); } - return "未知错误"; + list.add("未知错误"); + return list; } - static Future goLinkParse(String link, String password) async { + static Future goLinkParse(String link, String password, bool ispublic) async { LinkFileModel parse = LinkFileModel.newFileItem("", 0, "error", true); try { - var result = await HttpHelper.postToServer("GoLinkParse", jsonEncode({"link": link, "password": password})); + var result = await HttpHelper.postToServer( + "GoLinkParse", 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; } else if (result["code"] == 503) { parse.hash = result["message"]; } @@ -143,10 +153,10 @@ class Linker { return parse; } - static Future goLinkUpload(String parentid, String linkstr) async { + static Future goLinkUpload(String box, String parentid, String linkstr) async { try { - var result = - await HttpHelper.postToServer("GoLinkUpload", jsonEncode({"parentid": parentid, "linkstr": linkstr})); + var result = await HttpHelper.postToServer( + "GoLinkUpload", jsonEncode({'box': box, "parentid": parentid, "linkstr": linkstr})); if (result["code"] == 0) { //正确返回文件列表 return result["filecount"]; @@ -156,4 +166,77 @@ class Linker { } return 0; } + +//name updated_at created_at size + static Future goLinkSearch(String search, int pageindex) async { + if (search == "") search = "search"; + LinkSearchModel linksearch = new LinkSearchModel(); + linksearch.searchlist = []; + linksearch.pageIndex = pageindex; + var fcHide = BotToast.showCustomLoading( + toastBuilder: (cancelFunc) { + return APILoadingWidget(cancelFunc: cancelFunc, title: "搜索中:" + search); + }, + allowClick: true, + clickClose: false, + crossPage: true, + duration: null, + align: Alignment.topRight, + backButtonBehavior: BackButtonBehavior.ignore, + ignoreContentClick: true, + backgroundColor: Colors.transparent); + + try { + var result = + await HttpHelper.postToServer("GoLinkSearch", jsonEncode({'search': search, "pageindex": pageindex})); + if (result["code"] == 0) { + linksearch.fileCount = result["fileCount"]; + linksearch.pageCount = (linksearch.fileCount / 100).ceil(); + + final Icon iconFile = Icon(MIcons.wenjian, key: Key("file"), size: 22, color: MColors.iconFile); + final Icon iconImage = Icon(MIcons.file_img, key: Key("image"), size: 22, color: MColors.iconImage); + final Icon iconVideo = Icon(MIcons.file_video, key: Key("video"), size: 22, color: MColors.iconVideo); + final Icon iconAudio = Icon(MIcons.file_audio, key: Key("audio"), size: 22, color: MColors.iconAudio); + final Icon iconZip = Icon(MIcons.file_zip, key: Key("zip"), size: 22, color: MColors.iconZip); + final Icon iconTxt = Icon(MIcons.file_txt2, key: Key("txt"), size: 22, color: MColors.iconTxt); + + var items = result["items"]; + List list = []; + for (int i = 0; i < items.length; i++) { + var item = items[i]; + var model = PageRightFileItem.newPageRightFileItem( + 'search', + item["Key"], + (item["Icon"] == "video" + ? iconVideo + : item["Icon"] == "audio" + ? iconAudio + : item["Icon"] == "image" + ? iconImage + : item["Icon"] == "txt" + ? iconTxt + : item["Icon"] == "zip" + ? iconZip + : iconFile), + item["Name"], + item["Size"], + DateTime.fromMillisecondsSinceEpoch(item["Time"] * 1000 as int), + false, + false, + item["Hash"]); + list.add(model); + } + linksearch.searchlist = list; + return linksearch; + } else { + BotToast.showText(text: "拉取搜索 " + search + " 失败"); + } + } catch (e) { + print('goLinkSearch ' + e.toString()); + BotToast.showText(text: "拉取搜索 " + search + " 失败"); + } finally { + fcHide(); + } + return linksearch; + } } diff --git a/alixby/lib/api/Uploader.dart b/alixby/lib/api/Uploader.dart index cbb34df..c9a8aa8 100644 --- a/alixby/lib/api/Uploader.dart +++ b/alixby/lib/api/Uploader.dart @@ -6,11 +6,10 @@ import 'HttpHelper.dart'; class Uploader { //创建上传任务 - static Future goUploadFile(String parentid, List filelist) async { + static Future goUploadFile(String box, String parentid, List filelist) async { try { - print('goUploadFile'); - var result = - await HttpHelper.postToServer("GoUploadFile", jsonEncode({"parentid": parentid, 'filelist': filelist})); + var result = await HttpHelper.postToServer( + "GoUploadFile", jsonEncode({'box': box, "parentid": parentid, 'filelist': filelist})); if (result["code"] == 0) { return result["filecount"]; } @@ -21,10 +20,10 @@ class Uploader { } //创建上传任务 - static Future goUploadDir(String parentid, String dirpath) async { + static Future goUploadDir(String box, String parentid, String dirpath) async { try { - print('goUploadDir'); - var result = await HttpHelper.postToServer("GoUploadDir", jsonEncode({"parentid": parentid, 'dirpath': dirpath})); + var result = await HttpHelper.postToServer( + "GoUploadDir", jsonEncode({'box': box, "parentid": parentid, 'dirpath': dirpath})); if (result["code"] == 0) { return result["filecount"]; } @@ -34,11 +33,24 @@ class Uploader { return 0; } + //创建上传任务 + static Future goUploadFileAndDir(String box, String parentid, List filelist) async { + try { + var result = await HttpHelper.postToServer( + "GoUploadFileAndDir", jsonEncode({'box': box, "parentid": parentid, 'filelist': filelist})); + if (result["code"] == 0) { + return result["filecount"]; + } + } catch (e) { + print('goUploadFileAndDir ' + e.toString()); + } + return 0; + } + //查询当前正在上传的任务 static Future goUploadingList() async { var uploaddata = PageRightDownModel(); try { - print('goUploadingList'); var result = await HttpHelper.postToServer("GoUploadingList", ""); if (result["code"] == 0) { uploaddata.filecount = result["filecount"]; @@ -59,7 +71,6 @@ class Uploader { //查询当前已上传的任务 static Future goUploadList() async { try { - print('goUploadList '); var result = await HttpHelper.postToServer("GoUploadList", ""); if (result["code"] == 0) { var uploaddata = PageRightDownModel(); @@ -80,7 +91,6 @@ class Uploader { static Future goUploadingStart(String uploadid) async { try { - print('goUploadingStart'); var result = await HttpHelper.postToServer("GoUploadingStart", jsonEncode({"uploadid": uploadid})); if (result["code"] == 0) { return "success"; @@ -93,7 +103,6 @@ class Uploader { static Future goUploadingStop(String uploadid) async { try { - print('goUploadingStop'); var result = await HttpHelper.postToServer("GoUploadingStop", jsonEncode({"uploadid": uploadid})); if (result["code"] == 0) { return "success"; @@ -106,7 +115,6 @@ class Uploader { static Future goUploadingDelete(String uploadid) async { try { - print('goUploadingDelete'); var result = await HttpHelper.postToServer("GoUploadingDelete", jsonEncode({"uploadid": uploadid})); if (result["code"] == 0) { return "success"; @@ -119,7 +127,6 @@ class Uploader { static Future goUploadingForder(String uploadid) async { try { - print('goUploadingForder'); var result = await HttpHelper.postToServer("GoUploadingForder", jsonEncode({"uploadid": uploadid})); if (result["code"] == 0) { return "success"; @@ -132,7 +139,6 @@ class Uploader { static Future goUploadDelete(String uploadid) async { try { - print('goUploadDelete '); var result = await HttpHelper.postToServer("GoUploadDelete", jsonEncode({"uploadid": uploadid})); if (result["code"] == 0) { return "success"; @@ -145,7 +151,6 @@ class Uploader { static Future goUploadForder(String uploadid) async { try { - print('goUploadForder'); var result = await HttpHelper.postToServer("GoUploadForder", jsonEncode({"uploadid": uploadid})); if (result["code"] == 0) { return "success"; diff --git a/alixby/lib/main.dart b/alixby/lib/main.dart index 96fb8d8..39d1f01 100644 --- a/alixby/lib/main.dart +++ b/alixby/lib/main.dart @@ -1,6 +1,10 @@ +import 'dart:io'; + import 'package:alixby/api/GoServer.dart'; import 'package:alixby/states/SettingState.dart'; +import 'package:alixby/pagepan/DropUploadDialog.dart'; import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:split_view/split_view.dart'; @@ -13,20 +17,25 @@ import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:provider/provider.dart'; import 'states/Global.dart'; -import 'package:flutter/painting.dart'; +//import 'package:flutter/painting.dart'; +import 'package:dropfiles_window/dropfiles_window.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); handleError(runApp( MultiProvider( + key: navigatorKey, providers: [ ChangeNotifierProvider(create: (_) => Global.userState, lazy: false), ChangeNotifierProvider(create: (_) => Global.settingState, lazy: false), ChangeNotifierProvider(create: (_) => Global.panTreeState, lazy: false), + ChangeNotifierProvider(create: (_) => Global.xiangceTreeState, lazy: false), ChangeNotifierProvider(create: (_) => Global.panFileState, lazy: false), + ChangeNotifierProvider(create: (_) => Global.xiangceFileState, lazy: false), ChangeNotifierProvider(create: (_) => Global.pageDownState, lazy: false), ChangeNotifierProvider(create: (_) => Global.pageRssMiaoChuanState, lazy: false), + ChangeNotifierProvider(create: (_) => Global.pageRssSearchState, lazy: false), ], child: MyApp(), ), @@ -35,8 +44,52 @@ void main() async { Future.delayed(Duration(milliseconds: 200), () { GoServer.connServer(); }); + + // + if (Platform.isWindows == true) { + print("DropfilesWindow"); + UniqueKey? upload; + // Platform messages may fail, so we use a try/catch PlatformException. + try { + DropfilesWindow.modifyWindowAcceptFiles((String files) { + var box = Global.userState.box; + var parentid = Global.getFileState(box).pageRightDirKey; + var parentname = Global.getFileState(box).getSelectedFileParentPath(); + if (upload != null) { + BotToast.remove(upload!, "upload"); + } + Future.delayed(Duration(milliseconds: 100), () { + var key = UniqueKey(); + upload = key; + BotToast.showEnhancedWidget( + toastBuilder: (_) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: DropUploadDialog( + ukey: key, box: box, parentid: parentid, parentname: parentname, files: files)); + }, + key: key, + groupKey: "upload", + allowClick: false, + clickClose: false, + crossPage: true, + duration: null, + backButtonBehavior: BackButtonBehavior.ignore, + ignoreContentClick: false, + backgroundColor: Color(0x99000000), + onClose: () { + upload = null; + }); + }); + }); + } on PlatformException { + BotToast.showText(text: '拖放文件出错,请重试'); + } + } } +final GlobalKey navigatorKey = new GlobalKey(); + class MyApp extends StatelessWidget { // This widget is the root of your application. @@ -44,6 +97,8 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( //showPerformanceOverlay: true, //性能监视器 + //checkerboardOffscreenLayers: true, + //checkerboardRasterCacheImages: true, title: Global.appTitle, localizationsDelegates: [ GlobalMaterialLocalizations.delegate, @@ -65,7 +120,8 @@ class MyApp extends StatelessWidget { visualDensity: VisualDensity.comfortable, shadowColor: MaterialStateProperty.all(Colors.transparent), backgroundColor: MaterialStateProperty.all(MColors.elevatedBtnBG), - textStyle: MaterialStateProperty.all(TextStyle(color: MColors.elevatedBtnColor)), + textStyle: + MaterialStateProperty.all(TextStyle(color: MColors.elevatedBtnColor, fontFamily: "opposans")), overlayColor: MaterialStateProperty.resolveWith((states) { if (states.contains(MaterialState.pressed)) return MColors.elevatedBtnBGActive; if (states.contains(MaterialState.focused)) return MColors.elevatedBtnBGHover; @@ -85,7 +141,8 @@ class MyApp extends StatelessWidget { visualDensity: VisualDensity.comfortable, shadowColor: MaterialStateProperty.all(Colors.transparent), backgroundColor: MaterialStateProperty.all(MColors.outlineBtnBG), - textStyle: MaterialStateProperty.all(TextStyle(color: MColors.outlineBtnColor)), + textStyle: + MaterialStateProperty.all(TextStyle(color: MColors.outlineBtnColor, fontFamily: "opposans")), overlayColor: MaterialStateProperty.resolveWith((states) { if (states.contains(MaterialState.pressed)) return MColors.outlineBtnBGActive; if (states.contains(MaterialState.focused)) return MColors.outlineBtnBGHover; @@ -94,6 +151,15 @@ class MyApp extends StatelessWidget { if (states.contains(MaterialState.selected)) return MColors.outlineBtnBGHover; return Colors.transparent; }))), + textButtonTheme: TextButtonThemeData( + style: ButtonStyle( + shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(3))), + minimumSize: MaterialStateProperty.all(Size(0, 30)), + padding: MaterialStateProperty.all(EdgeInsets.symmetric(horizontal: 12, vertical: 4)), + elevation: MaterialStateProperty.all(0), + visualDensity: VisualDensity.comfortable, + shadowColor: MaterialStateProperty.all(Colors.transparent), + )), scrollbarTheme: ScrollbarThemeData( thumbColor: MaterialStateProperty.all(MColors.thumbColor), trackColor: MaterialStateProperty.all(MColors.trackColor), @@ -111,15 +177,15 @@ class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { var screenWidth = MediaQuery.of(context).size.width; - var _data = - MediaQuery.of(context).copyWith(textScaleFactor: double.parse(context.watch().setting.textScale)); return Scaffold( //appBar: DraggebleAppBar("Draggable borderless"), body: MediaQuery( - data: _data, + data: MediaQuery.of(context) + .copyWith(textScaleFactor: double.parse(context.watch().setting.textScale)), child: DefaultTextStyle( //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), + softWrap: false, + style: TextStyle(color: MColors.textColor, fontFamily: "opposans", letterSpacing: 0.5), child: Container( color: MColors.pageRightBG, child: SplitView( diff --git a/alixby/lib/models/FileItem.dart b/alixby/lib/models/FileItem.dart index 878cb45..dface9b 100644 --- a/alixby/lib/models/FileItem.dart +++ b/alixby/lib/models/FileItem.dart @@ -3,13 +3,15 @@ import 'package:json_annotation/json_annotation.dart'; @JsonSerializable(explicitToJson: true) class FileItem { FileItem(); - static FileItem newFileItem(String key, String parentkey, String name) { + static FileItem newFileItem(String box, String key, String parentkey, String name) { return FileItem() + ..box = box ..key = key ..parentkey = parentkey ..name = name; } + String box = ""; String key = ""; String parentkey = ""; String name = ""; @@ -30,8 +32,9 @@ class FileItem { bool get isWeiFa => status == "illegal"; List children = []; - factory FileItem.fromJson(Map json) { + factory FileItem.fromJson(String box, Map json) { var model = FileItem(); + model.box = box; var item = json['key']; model.key = item == null ? "" : item as String; item = json['name']; @@ -57,7 +60,7 @@ class FileItem { var cdlist = json["children"]; if (cdlist != null && cdlist.length > 0) { - model.children = cdlist.map((m) => new FileItem.fromJson(m)).toList(); + model.children = cdlist.map((m) => new FileItem.fromJson(box, m)).toList(); } return model; } diff --git a/alixby/lib/models/PageRightFileItem.dart b/alixby/lib/models/PageRightFileItem.dart index efb4dbe..06a4f0f 100644 --- a/alixby/lib/models/PageRightFileItem.dart +++ b/alixby/lib/models/PageRightFileItem.dart @@ -6,29 +6,30 @@ import 'package:json_annotation/json_annotation.dart'; @JsonSerializable() class PageRightFileItem { PageRightFileItem(); - static PageRightFileItem newPageRightFileItem( - String key, Icon icon, String title, int fileSize, DateTime fileTime, bool isFavor, bool isDir, String filetype) { + static PageRightFileItem newPageRightFileItem(String box, String key, Icon icon, String title, int fileSize, + DateTime fileTime, bool isFavor, bool isDir, String filetype) { return PageRightFileItem() + ..box = box ..key = key ..icon = icon ..fileSize = fileSize ..filesizestr = filesize(fileSize) ..fileTime = fileTime.millisecondsSinceEpoch - ..filetimestr = - "${fileTime.year.toString()} ${fileTime.month.toString().padLeft(2, '0')}-${fileTime.day.toString().padLeft(2, '0')}" + ..filetimestr = "${fileTime.year.toString()}\n${fileTime.month.toString()}-${fileTime.day.toString()}" ..title = title ..filetype = filetype ..isFavor = isFavor ..isDir = isDir; } + String box = ''; String key = ''; String title = ''; Icon icon = Icon(MIcons.wenjian); int fileSize = 0; String filesizestr = "0B"; int fileTime = 0; - String filetimestr = "1991 01-01"; + String filetimestr = "1991\n1-1"; bool selected = false; bool isFavor = false; bool isDir = false; diff --git a/alixby/lib/models/PageRightMiaoChuanItem.dart b/alixby/lib/models/PageRightMiaoChuanItem.dart index f48e6db..4f13641 100644 --- a/alixby/lib/models/PageRightMiaoChuanItem.dart +++ b/alixby/lib/models/PageRightMiaoChuanItem.dart @@ -21,7 +21,7 @@ class PageRightMiaoChuanItem { m.logTime = json['LogTime'] as int; var dt2 = new DateTime.fromMillisecondsSinceEpoch(m.logTime * 1000); m.logTimeStr = - "${dt2.year.toString()}-${dt2.month.toString().padLeft(2, '0')}-${dt2.day.toString().padLeft(2, '0')} ${dt2.hour.toString().padLeft(2, '0')}:${dt2.minute.toString().padLeft(2, '0')}:${dt2.second.toString().padLeft(2, '0')}"; + "${dt2.year.toString()}-${dt2.month.toString().padLeft(2, '0')}-${dt2.day.toString().padLeft(2, '0')}\n${dt2.hour.toString().padLeft(2, '0')}:${dt2.minute.toString().padLeft(2, '0')}:${dt2.second.toString().padLeft(2, '0')}"; return m; } } diff --git a/alixby/lib/models/Setting.dart b/alixby/lib/models/Setting.dart index 92a480a..8a3b501 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.10.0"; + static String UIVER = "1.6.21.0"; factory Setting.fromJson(Map json) { return Setting() diff --git a/alixby/lib/pagedown/DownFileList.dart b/alixby/lib/pagedown/DownFileList.dart new file mode 100644 index 0000000..864ad05 --- /dev/null +++ b/alixby/lib/pagedown/DownFileList.dart @@ -0,0 +1,371 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/rendering.dart'; +import 'package:gradient_widgets/gradient_widgets.dart'; +import 'package:hovering/hovering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:flutter/material.dart'; + +class DownFileList extends StatefulWidget { + @override + _DownFileListState createState() => _DownFileListState(); +} + +class _DownFileListState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + final verticalScroll = ScrollController(); + final GlobalKey fileConKey = GlobalKey(); + @override + Widget build(BuildContext context) { + var itemCount = context.watch().pageRightDownList.length; + return Container( + key: fileConKey, + width: double.infinity, + decoration: BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), + alignment: Alignment.topLeft, + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: ListView.builder( + controller: verticalScroll, + shrinkWrap: false, + primary: false, + addSemanticIndexes: false, + addAutomaticKeepAlives: true, + addRepaintBoundaries: true, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + itemExtent: 60, + itemCount: itemCount, + itemBuilder: _buildList, + ))); + } + + //static BoxDecoration decoration = BoxDecoration(color: Color(0xfff7f8fa), border: border); + + static Padding padding4 = Padding(padding: EdgeInsets.only(left: 4)); + static Padding padding12 = Padding(padding: EdgeInsets.only(left: 12)); + static Padding padding16 = Padding(padding: EdgeInsets.only(left: 16)); + static Padding padding22 = Padding(padding: EdgeInsets.only(left: 22)); + TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"); + SizedBox downBox = SizedBox(width: 40, height: 40, child: Icon(MIcons.download, color: MColors.iconDown)); + SizedBox downBoxed = SizedBox(width: 40, height: 40, child: Icon(MIcons.download, color: MColors.iconSelected)); + 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 onTapFile(String key) { + Global.pageDownState.pageSelectFile(key); + } + + static onTapBtn(String button, String key, String downPage) async { + var result = ""; + if (downPage == "downing") { + if (button == "forder") { + result = await Downloader.goDowningForder(key); + } else { + if (button == "start") result = await Downloader.goDowningStart(key); + if (button == "stop") result = await Downloader.goDowningStop(key); + if (button == "delete") result = await Downloader.goDowningDelete(key); + Global.pageDownState.refreshDownByTimer(false); //触发刷新 + } + } + if (downPage == "downed") { + if (button == "forder") { + result = await Downloader.goDownedForder(key); + } else { + if (button == "delete") result = await Downloader.goDownedDelete(key); + Global.pageDownState.refreshDownByTimer(false); //触发刷新 + } + } else if (downPage == "uploading") { + if (button == "forder") { + result = await Uploader.goUploadingForder(key); + } else { + if (button == "start") result = await Uploader.goUploadingStart(key); + if (button == "stop") result = await Uploader.goUploadingStop(key); + if (button == "delete") result = await Uploader.goUploadingDelete(key); + Global.pageDownState.refreshDownByTimer(false); //触发刷新 + } + } else if (downPage == "upload") { + if (button == "forder") { + result = await Uploader.goUploadForder(key); + } else { + if (button == "delete") result = await Uploader.goUploadDelete(key); + Global.pageDownState.refreshDownByTimer(false); //触发刷新 + } + } + + if (result != "success") { + BotToast.showText(text: "操作失败:" + result); + } + } + + Widget _buildList(BuildContext context, int index) { + var item = Global.pageDownState.pageRightDownList[index]; + var decoration = BoxDecoration( + color: MColors.pageRightFileBG, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + var decorations = BoxDecoration( + color: MColors.pageRightFileBGSelect, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + + var hoverDecoration = BoxDecoration( + color: MColors.pageRightFileBGHover, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + var hoverDecorations = BoxDecoration( + color: MColors.pageRightFileBGSelect, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + + var ising = item.downPage.contains("ing"); + var isdown = item.downPage.startsWith("down"); + + if (ising) { + return HoverWidget( + child: Container( + decoration: item.selected ? decorations : decoration, + key: Key("prd_hc_" + item.key), + padding: EdgeInsets.only(right: 16), + height: 60, + child: InkWell( + mouseCursor: SystemMouseCursors.basic, + onTap: () => onTapFile(item.key), + child: Row( + key: Key("prd_hcr_" + item.key), + children: [ + isdown ? (item.isDowning ? downBoxed : downBox) : (item.isDowning ? uploadBoxed : uploadBox), + padding4, + Expanded( + child: Tooltip( + message: item.path, + child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), + ), + ), + Container( + key: Key("prd_hcr_s_" + item.key), + width: 88, + alignment: Alignment.centerRight, + child: Text(item.fileSize, style: textStyle, maxLines: 1)), + padding22, + Container( + height: 60, + child: Stack(alignment: Alignment.topLeft, children: [ + Container( + width: 220, + height: 60, + child: Row(key: Key("prd_hcr_hbtnr_" + item.key), children: [ + Container( + key: Key("prd_hcr_t_" + item.key), + width: 90, + alignment: Alignment.center, + child: Column(children: [ + Padding(padding: EdgeInsets.only(top: 20)), + SizedBox( + height: 3, + child: GradientProgressIndicator( + gradient: Gradients.coralCandyGradient, + value: item.downProgress / 100, + )), + Padding(padding: EdgeInsets.only(top: 4)), + Text(item.lastTime, + style: + TextStyle(fontSize: 12, color: MColors.textColor, fontFamily: "opposans"), + maxLines: 1, + softWrap: false), + ])), + padding12, + Container( + key: Key("prd_hcr_sp_" + item.key), + width: 110, + alignment: Alignment.centerRight, + child: Text(item.downSpeed, + style: TextStyle( + fontSize: 20, + color: MColors.pageRightDownSpeedColor, + fontFamily: "opposans"), + maxLines: 1, + softWrap: false, + overflow: TextOverflow.visible)) + ])), + Positioned( + left: 0, + top: 39, + child: SizedBox( + width: 210.0, + height: 20.0, + child: Container( + width: 210, + child: Text( + item.failedMessage, + overflow: TextOverflow.clip, + maxLines: 1, + softWrap: false, + style: TextStyle(color: Colors.red, fontSize: 12, fontFamily: "opposans"), + ))), + ), + ])), + padding12, + ], + ))), + hoverChild: Container( + decoration: item.selected ? hoverDecorations : hoverDecoration, + key: Key("prd_hc_" + item.key), + padding: EdgeInsets.only(right: 16), + height: 60, + child: InkWell( + mouseCursor: SystemMouseCursors.basic, + onTap: () => onTapFile(item.key), + child: Row( + key: Key("prd_hcr_" + item.key), + children: [ + isdown ? (item.isDowning ? downBoxed : downBox) : (item.isDowning ? uploadBoxed : uploadBox), + padding4, + Expanded( + child: Tooltip( + message: item.path, + child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), + ), + ), + Container( + key: Key("prd_hcr_s_" + item.key), + width: 88, + alignment: Alignment.centerRight, + child: Text(item.fileSize, style: textStyle, maxLines: 1)), + padding22, + Container( + height: 60, + child: Stack(alignment: Alignment.topLeft, children: [ + Container( + width: 220, + height: 60, + child: Row( + key: Key("prd_hcr_hbtnr2_" + item.key), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + OutlinedButton( + child: Icon(MIcons.start, size: 16), + onPressed: () => onTapBtn("start", item.key, item.downPage)), + padding16, + OutlinedButton( + child: Icon(MIcons.pause, size: 16), + onPressed: () => onTapBtn("stop", item.key, item.downPage)), + padding16, + OutlinedButton( + child: Icon(MIcons.file_folder, size: 16), + onPressed: () => onTapBtn("forder", item.key, item.downPage)), + padding16, + OutlinedButton( + child: Icon(MIcons.delete, size: 16), + onPressed: () => onTapBtn("delete", item.key, item.downPage)), + ])), + Positioned( + left: 0, + top: 39, + child: SizedBox( + width: 210.0, + height: 20.0, + child: Container( + width: 210, + child: Text( + item.failedMessage, + overflow: TextOverflow.clip, + maxLines: 1, + softWrap: false, + style: TextStyle(color: Colors.red, fontSize: 12, fontFamily: "opposans"), + ))), + ), + ])), + padding12, + ], + ))), + onHover: (e) {}, + ); + } else { + return HoverContainer( + key: Key("prdn_h_" + item.key), + cursor: SystemMouseCursors.basic, + height: 60, + decoration: item.selected ? decorations : decoration, + hoverDecoration: item.selected ? hoverDecorations : hoverDecoration, + child: Container( + key: Key("prd_hc_" + item.key), + padding: EdgeInsets.only(right: 16), + height: 60, + child: InkWell( + mouseCursor: SystemMouseCursors.basic, + onTap: () => onTapFile(item.key), + child: Row( + key: Key("prd_hcr_" + item.key), + children: [ + isdown ? (item.isDowning ? downBoxed : downBox) : (item.isDowning ? uploadBoxed : uploadBox), + padding4, + Expanded( + child: Tooltip( + message: item.path, + child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), + ), + ), + Container( + key: Key("prd_hcr_s_" + item.key), + width: 88, + alignment: Alignment.centerRight, + child: Text(item.fileSize, style: textStyle, maxLines: 1)), + padding22, + Container( + height: 60, + child: Stack(alignment: Alignment.topLeft, children: [ + Container( + width: 120, + height: 60, + child: Row( + key: Key("prd_hcr_hbtnr2_" + item.key), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + OutlinedButton( + child: Icon(MIcons.file_folder, size: 16), + onPressed: () => onTapBtn("forder", item.key, item.downPage)), + padding16, + OutlinedButton( + child: Icon(MIcons.delete, size: 16), + onPressed: () => onTapBtn("delete", item.key, item.downPage)), + ])), + Positioned( + left: 0, + top: 39, + child: SizedBox( + width: 210.0, + height: 20.0, + child: Container( + width: 210, + child: Text( + item.failedMessage, + overflow: TextOverflow.clip, + maxLines: 1, + softWrap: false, + style: TextStyle(color: Colors.red, fontSize: 12, fontFamily: "opposans"), + ))), + ), + ])), + padding12, + ], + ))), + ); + } + } +} diff --git a/alixby/lib/views/PageLeftDown.dart b/alixby/lib/pagedown/PageLeftDown.dart similarity index 91% rename from alixby/lib/views/PageLeftDown.dart rename to alixby/lib/pagedown/PageLeftDown.dart index 215eb23..1444ea4 100644 --- a/alixby/lib/views/PageLeftDown.dart +++ b/alixby/lib/pagedown/PageLeftDown.dart @@ -1,12 +1,12 @@ import 'package:alixby/states/Global.dart'; import 'package:alixby/states/pageDownState.dart'; import 'package:provider/provider.dart'; -import '../utils/MIcons.dart'; +import 'package:alixby/utils/MIcons.dart'; -import '../utils/MColors.dart'; +import 'package:alixby/utils/MColors.dart'; import 'package:hovering/hovering.dart'; -import '../models/PageLeftRowItem.dart'; +import 'package:alixby/models/PageLeftRowItem.dart'; import 'package:flutter/material.dart'; class PageLeftDown extends StatefulWidget { @@ -29,7 +29,6 @@ class _PageLeftDownState extends State with AutomaticKeepAliveClie @override void initState() { super.initState(); - print('_PageLeftDownState initState'); } @override @@ -47,7 +46,7 @@ class _PageLeftDownState extends State with AutomaticKeepAliveClie alignment: Alignment.centerLeft, child: Text( "本地下载的文件", - style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor), + style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor, fontFamily: "opposans"), )), Expanded( child: ListView.builder( @@ -84,7 +83,8 @@ class _PageLeftDownState extends State with AutomaticKeepAliveClie Text( item.title, style: TextStyle( - color: selectKey == item.key ? MColors.userNavMenuIconHover : MColors.pageLeftRowItemColor), + color: selectKey == item.key ? MColors.userNavMenuIconHover : MColors.pageLeftRowItemColor, + fontFamily: "opposans"), ) ])))), ); diff --git a/alixby/lib/views/PageRightDown.dart b/alixby/lib/pagedown/PageRightDown.dart similarity index 89% rename from alixby/lib/views/PageRightDown.dart rename to alixby/lib/pagedown/PageRightDown.dart index b902dc3..fbd5708 100644 --- a/alixby/lib/views/PageRightDown.dart +++ b/alixby/lib/pagedown/PageRightDown.dart @@ -5,7 +5,7 @@ import 'package:alixby/states/pageDownState.dart'; import 'package:alixby/utils/FileLinkifier.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; -import 'package:alixby/widgets/DownFileList.dart'; +import 'package:alixby/pagedown/DownFileList.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter_linkify/flutter_linkify.dart'; @@ -20,7 +20,6 @@ class _PageRightDownState extends State with AutomaticKeepAliveCl @override void initState() { super.initState(); - print('_PageRightDownState initState'); } @override @@ -29,7 +28,6 @@ class _PageRightDownState extends State with AutomaticKeepAliveCl } static onTapBtn(String button) async { - print('点击按钮'); String downPage = Global.pageDownState.getPageName; String key = "all"; var result = ""; @@ -76,6 +74,8 @@ class _PageRightDownState extends State with AutomaticKeepAliveCl @override // ignore: must_call_super Widget build(BuildContext context) { + var getPageName = context.watch().getPageName; + var pageRightDownDes = context.watch().pageRightDownDes; return Column( children: [ Container( @@ -88,13 +88,16 @@ class _PageRightDownState extends State with AutomaticKeepAliveCl child: Linkify( onOpen: null, text: "传输任务列表", - linkifiers: [FileLinkifier("传输任务列表", "")], - linkStyle: - TextStyle(fontSize: 13, color: MColors.linkColor, decoration: TextDecoration.none))))), + linkifiers: [FileLinkifier("传输任务列表", "", "")], + linkStyle: TextStyle( + fontSize: 13, + color: MColors.linkColor, + decoration: TextDecoration.none, + fontFamily: "opposans"))))), Container( height: 34, width: double.infinity, - child: context.watch().getPageName.contains("ing") + child: getPageName.contains("ing") ? Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ OutlinedButton.icon( icon: Icon(MIcons.start, size: 16), label: Text('全部开始'), onPressed: () => onTapBtn('start')), @@ -116,7 +119,7 @@ class _PageRightDownState extends State with AutomaticKeepAliveCl width: double.infinity, child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ Padding(padding: EdgeInsets.only(left: 44)), - Text(context.watch().pageRightDownDes), + Text(pageRightDownDes), Expanded(child: Container()), Container(child: Text("操作")), Padding(padding: EdgeInsets.only(left: 210)), diff --git a/alixby/lib/pagepan/CreatDirDialog.dart b/alixby/lib/pagepan/CreatDirDialog.dart new file mode 100644 index 0000000..5adc0bf --- /dev/null +++ b/alixby/lib/pagepan/CreatDirDialog.dart @@ -0,0 +1,129 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +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); + String box = ""; + final TextEditingController controller = TextEditingController(); + + void onSubmitted(BuildContext context) { + String dirname = controller.text; + dirname = dirname.replaceAll('"', '').trim(); + + 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: "创建失败请重试"); + } + }); + } + + @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: 200, + width: 460, + 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("新建文件夹", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 380, + padding: EdgeInsets.only(top: 20), + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 60, maxWidth: 375), + child: TextField( + controller: controller, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + 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), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + onSubmitted: (val) { + onSubmitted(context); + }, + )), + Positioned.directional( + textDirection: TextDirection.rtl, + start: 0, + child: ElevatedButton( + onPressed: () { + onSubmitted(context); + }, + child: Text(" 创建 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + )), + ], + ), + ), + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/pagepan/CreatMiaoChuanBackDialog.dart b/alixby/lib/pagepan/CreatMiaoChuanBackDialog.dart new file mode 100644 index 0000000..6e6aa81 --- /dev/null +++ b/alixby/lib/pagepan/CreatMiaoChuanBackDialog.dart @@ -0,0 +1,100 @@ +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.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 CreatMiaoChuanBackDialog extends StatelessWidget { + CreatMiaoChuanBackDialog({Key? key, required this.filename, required this.info}) : super(key: key) { + controller.text = filename; + } + String filename = ""; + String info = ""; + final TextEditingController controller = TextEditingController(); + + @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: 160, + width: 460, + 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("创建秒传文件", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 380, + child: Stack( + children: [ + TextField( + controller: controller, + maxLines: 2, + 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: 8, horizontal: 8), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + ), + Positioned.directional( + textDirection: TextDirection.rtl, + start: 0, + top: 22, + 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 new file mode 100644 index 0000000..1fe6911 --- /dev/null +++ b/alixby/lib/pagepan/CreatMiaoChuanDialog.dart @@ -0,0 +1,237 @@ +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: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 CreatMiaoChuanDialog extends StatefulWidget { + CreatMiaoChuanDialog( + {Key? key, required this.box, required this.parentid, required String parentname, required this.filelist}) + : 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"; + } + String box = ""; + String parentid = ""; + String savename = ""; + List filelist = []; + + @override + _CreatMiaoChuanDialogState createState() => _CreatMiaoChuanDialogState(); +} + +class _CreatMiaoChuanDialogState extends State { + final TextEditingController pwdcontroller = TextEditingController(); + @override + void dispose() { + pwdcontroller.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + pwdcontroller.text = widget.savename; + } + + @override + Widget build(BuildContext context) { + var stylegray = TextStyle(color: MColors.pageLeftRowHeadColor, fontSize: 13, fontFamily: "opposans"); + var stylered = TextStyle(color: Color(0xccdf5659), fontFamily: "opposans"); + 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: 400, + width: 500, + 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("创建秒传文件(txt)", + 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: [ + Padding(padding: EdgeInsets.only(top: 12)), + Container( + alignment: Alignment.topLeft, + child: Text("为选中的 " + widget.filelist.length.toString() + " 个文件/文件夹创建秒传文件"), + ), + Padding(padding: EdgeInsets.only(top: 24)), + _buildCanShu(context), + Padding(padding: EdgeInsets.only(top: 24)), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + alignment: Alignment.topLeft, + child: RichText( + textAlign: TextAlign.left, + text: TextSpan(style: stylegray, children: [ + TextSpan(text: "就是把选中的文件 (", style: stylegray), + TextSpan(text: "文件名 / sha1 / 文件夹结构", style: stylered), + TextSpan(text: ") 保存到一个txt文件里。之后你可以删除选中的文件,释放网盘空间。", style: stylegray), + ])), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + alignment: Alignment.topLeft, + child: RichText( + textAlign: TextAlign.left, + text: TextSpan(style: stylegray, children: [ + TextSpan(text: "等以后需要用到这些文件时再重新瞬间导入,恢复这些文件和文件夹", style: stylegray), + ])), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + alignment: Alignment.topLeft, + child: RichText( + textAlign: TextAlign.left, + text: TextSpan(style: stylegray, children: [ + TextSpan(text: "如果选中了很多文件夹时,会自动遍历", style: stylegray), + TextSpan(text: "全部子文件", style: stylered), + TextSpan(text: ",可能会耗时很长", style: stylegray), + ])), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + alignment: Alignment.topLeft, + child: RichText( + textAlign: TextAlign.left, + text: TextSpan(style: stylegray, children: [ + TextSpan(text: "保护用户隐私声明:\n", style: stylered), + TextSpan(text: "创建秒传文件时只会把sha1保存到", style: stylegray), + TextSpan(text: "你的网盘里", style: stylered), + TextSpan(text: "!", style: stylegray), + TextSpan(text: "不会", style: stylered), + TextSpan(text: "联网发送其他", style: stylegray), + TextSpan(text: "数据。所以不会", style: stylegray), + TextSpan(text: "泄露隐私。只有", style: stylegray), + TextSpan(text: "你自己", style: stylered), + TextSpan(text: "要把此文件", style: stylegray), + TextSpan(text: "分享", style: stylered), + TextSpan(text: "出去时,才需要注意", style: stylegray), + ])), + ), + ])), + ], + ), + )), + ))); + } + + 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 new file mode 100644 index 0000000..4dd03e5 --- /dev/null +++ b/alixby/lib/pagepan/DownSaveDialog.dart @@ -0,0 +1,159 @@ +import 'package:alixby/api/Downloader.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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class DownSaveDialog extends StatefulWidget { + DownSaveDialog( + {Key? key, required this.box, required this.parentid, required String parentPath, required this.filelist}) + : super(key: key) { + var savePath = Global.settingState.setting.savePath; + var spc = "\\"; + if (savePath.contains("/")) { + spc = "/"; //mac linux + } else { + parentPath = parentPath.replaceAll('/', '\\'); + } + while (savePath.endsWith(spc)) { + savePath = savePath.substring(0, savePath.length - 1); + } + savePath = savePath + spc; + while (parentPath.startsWith(spc)) { + parentPath = parentPath.substring(1); + } + controller.text = savePath + parentPath; + } + String box = ""; + String parentid = ""; + List filelist = []; + TextEditingController controller = TextEditingController(); + @override + _DownSaveDialogState createState() => _DownSaveDialogState(); +} + +class _DownSaveDialogState extends State { + void _getDirectoryPath() async { + final directoryPath = await FileSelectorPlatform.instance.getDirectoryPath( + initialDirectory: widget.controller.text, + confirmButtonText: "选择保存到的文件夹", + ); + if (directoryPath != null) widget.controller.text = directoryPath; + } + + @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: 240, + width: 460, + 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("选择下载文件保存位置", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 380, + padding: EdgeInsets.only(top: 20), + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 60), + child: TextField( + controller: widget.controller, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + decoration: InputDecoration( + helperText: "默认是保存位置+网盘全路径+文件名,不推荐修改", + 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.inputBorderColor, + width: 1, + ), + ), + ), + )), + Positioned.directional( + textDirection: TextDirection.rtl, + start: 0, + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: 31), + child: ElevatedButton.icon( + icon: Icon(MIcons.file_folder, size: 16), + label: Text('选择'), + onPressed: () => _getDirectoryPath()))), + ], + ), + ), + Container( + width: 380, + padding: EdgeInsets.only(top: 38, bottom: 8), + child: OutlinedButton.icon( + icon: Icon(MIcons.download, size: 16), + label: Text('立即下载'), + onPressed: () { + String savepath = widget.controller.text; + savepath = savepath.replaceAll('"', '').trim(); + var fcHide = Loading.showLoading(); + Downloader.goDownFile(widget.box, widget.parentid, savepath, widget.filelist).then((value) { + fcHide(); + if (value > 0) { + BotToast.showText(text: "成功创建" + value.toString() + "个文件的下载任务"); + Navigator.of(context).pop('ok'); + } else { + BotToast.showText(text: "创建下载任务失败请重试"); + } + }); + }, + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + )), + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/pagepan/DropUploadDialog.dart b/alixby/lib/pagepan/DropUploadDialog.dart new file mode 100644 index 0000000..d107588 --- /dev/null +++ b/alixby/lib/pagepan/DropUploadDialog.dart @@ -0,0 +1,268 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:hovering/hovering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class DropUploadDialog extends StatefulWidget { + DropUploadDialog( + {Key? key, + required this.ukey, + required this.box, + required this.parentid, + required this.parentname, + required String files}) + : super(key: key) { + //boxname + if (box == 'box') + boxname = "网盘"; + else if (box == 'sbox') + boxname = "保险箱"; + else if (box == 'xiangce') boxname = "相册"; + +//filelist + filelist = []; + var list = files.split('\n'); + final Icon iconFile = Icon(MIcons.wenjian, key: Key("file"), size: 22, color: MColors.iconFile); + final Icon iconFolder = Icon(MIcons.folder, key: Key("folder"), size: 22, color: MColors.iconFolder); + int fileCount = 0; + int dirCount = 0; + for (var i = 0; i < list.length; i++) { + var file = list[i]; + var fi = FileStat.statSync(file); + if (fi.type == FileSystemEntityType.notFound) { + continue; + } + + var isdir = (fi.type == FileSystemEntityType.directory); + if (isdir) { + dirCount++; + var item = PageRightFileItem.newPageRightFileItem( + box, file, iconFolder, file, 0, DateTime.now(), false, isdir, "forder"); + filelist.add(item); + fileuplist.add(file); + } else { + fileCount++; + var item = PageRightFileItem.newPageRightFileItem( + box, file, iconFile, file, fi.size, fi.modified, false, isdir, "file"); + filelist.add(item); + fileuplist.add(file); + } + } + desc = fileCount.toString() + "文件 " + dirCount.toString() + "文件夹"; + } + UniqueKey ukey; + String box = ""; + String boxname = ""; + String parentid = ""; + String parentname = ""; + List filelist = []; + List fileuplist = []; + String desc = ""; + + @override + _DropUploadDialogState createState() => _DropUploadDialogState(); +} + +class _DropUploadDialogState extends State { + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + final ScrollController verticalScroll = ScrollController(); + @override + void initState() { + super.initState(); + } + + @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: 520, + width: 500, + 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: () => BotToast.remove(widget.ukey, "upload"), + ))), + Container( + child: Text("拖放文件+文件夹上传", + 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: 24)), + _buildCanShu(context), + Padding(padding: EdgeInsets.only(top: 12)), + ])), + ], + ), + )), + ))); + } + + Widget _buildLink(BuildContext context) { + return Container( + height: 300, + alignment: Alignment.topLeft, + decoration: + BoxDecoration(border: Border.all(width: 1, color: Colors.grey), borderRadius: BorderRadius.circular(3.0)), + padding: EdgeInsets.all(2), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: ListView.builder( + controller: verticalScroll, + shrinkWrap: false, + primary: false, + addSemanticIndexes: false, + addAutomaticKeepAlives: false, + addRepaintBoundaries: false, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + itemExtent: 42, + itemCount: widget.filelist.length, + itemBuilder: _buildList, + ))); + } + + var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); + var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); + var padding = EdgeInsets.only(left: 3, right: 3); + var padding2 = Padding(padding: EdgeInsets.only(left: 4)); + var icondir = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); + var iconfile = Icon(MIcons.file_file, size: 20, color: MColors.iconFile); + var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor, fontFamily: "opposans"); + TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"); + Widget _buildList(BuildContext context, int index) { + var item = widget.filelist[index]; + + return HoverContainer( + //key: Key("prd_h_" + item.key), + cursor: SystemMouseCursors.basic, + height: 42, + margin: EdgeInsets.only(top: 4), + padding: EdgeInsets.only(right: 16), + decoration: decoration, + hoverDecoration: hoverDecoration, + child: Container( + height: 42, + child: Row( + children: [ + item.isDir ? icondir : iconfile, + padding2, + Expanded( + child: Text( + item.title, + style: textStyle, + softWrap: false, + overflow: TextOverflow.ellipsis, + maxLines: 2, + )), + Container( + key: Key("prf_hcr_s_" + item.key), + width: 88, + alignment: Alignment.centerRight, + child: Text(item.filesizestr, style: textStyle, maxLines: 1, softWrap: false)), + ], + ))); + } + + Widget _buildCanShu(BuildContext context) { + return Container( + alignment: Alignment.topLeft, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: + Text(widget.desc, style: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"))), + OutlinedButton( + onPressed: () => BotToast.remove(widget.ukey, "upload"), + child: Text(" 取消 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + Padding(padding: EdgeInsets.only(left: 24)), + ElevatedButton( + onPressed: () { + var fcHide = Loading.showLoading(); + Uploader.goUploadFileAndDir(widget.box, widget.parentid, widget.fileuplist).then((value) { + fcHide(); + if (value > 0) { + BotToast.showText(text: "成功创建" + value.toString() + "个上传任务"); + BotToast.remove(widget.ukey, "upload"); + Future.delayed(Duration(milliseconds: 500), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + } else { + BotToast.showText(text: "创建文件上传任务失败请重试"); + } + }); + }, + child: Text(" 上传 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ], + ), + ); + } +} diff --git a/alixby/lib/pagepan/ImageDialog.dart b/alixby/lib/pagepan/ImageDialog.dart new file mode 100644 index 0000000..5d71c71 --- /dev/null +++ b/alixby/lib/pagepan/ImageDialog.dart @@ -0,0 +1,102 @@ +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:extended_image/extended_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class ImageDialog extends StatelessWidget { + ImageDialog({Key? key, required this.imageUrl}) : super(key: key); + String imageUrl = ""; + final verticalScroll = ScrollController(); + + @override + Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; + var imagew = size.width * 0.8 - 40; + var imageh = size.height * 0.9 - 80; + 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: size.height * 0.9, + width: size.width * 0.8, + 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("图片预览", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: imagew, + height: imageh, + alignment: Alignment.topLeft, + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: SingleChildScrollView( + controller: verticalScroll, + scrollDirection: Axis.vertical, + physics: BouncingScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: imagew, minHeight: imageh), + child: Container( + width: imagew, + alignment: Alignment.topCenter, + decoration: BoxDecoration( + border: Border.all(width: 1, color: Colors.grey), + borderRadius: BorderRadius.circular(3.0)), + padding: EdgeInsets.all(4), + margin: EdgeInsets.only(right: 16), + child: ExtendedImage.network(imageUrl, + headers: {"Referer": "https://www.aliyundrive.com/"}, + fit: BoxFit.none, + filterQuality: FilterQuality.high, + cache: true, + //enableLoadState: false, + mode: ExtendedImageMode.none, loadStateChanged: (ExtendedImageState state) { + switch (state.extendedImageLoadState) { + case LoadState.loading: + return null; + case LoadState.completed: + verticalScroll.animateTo(0, + duration: Duration(milliseconds: 100), + curve: Curves.ease); //奇怪这里必须刷新一下才显示 + return ExtendedRawImage(image: state.extendedImageInfo?.image); + case LoadState.failed: + return null; + } + })))))), + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/pagepan/ImagesDialog.dart b/alixby/lib/pagepan/ImagesDialog.dart new file mode 100644 index 0000000..ba8cf54 --- /dev/null +++ b/alixby/lib/pagepan/ImagesDialog.dart @@ -0,0 +1,272 @@ +import 'package:alixby/api/Downloader.dart'; +import 'package:alixby/models/PageRightFileItem.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:extended_image/extended_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:hovering/hovering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class ImagesDialog extends StatefulWidget { + ImagesDialog({Key? key, required this.box, required this.imageselected, required this.imagelist}) : super(key: key); + String box = ""; + String imageselected = ""; + List imagelist = []; + + @override + _ImagesDialogState createState() => _ImagesDialogState(); +} + +class _ImagesDialogState extends State { + final verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + String imageSelected = ""; + String imageName = ""; + String imageUrl = ""; + double imageScale = 1.0; + int imageRotate = 0; + @override + void initState() { + super.initState(); + imageSelected = widget.imageselected; + loadImage(); + } + + void loadImageNext() { + var count = widget.imagelist.length; + for (var i = 0; i < count; i++) { + if (widget.imagelist[i].key == imageSelected) { + if ((count - 1) > i) { + imageSelected = widget.imagelist[i + 1].key; + loadImage(); + return; + } else { + BotToast.showText(text: "这是最后一张图片了"); + } + } + } + } + + void loadImagePrev() { + var count = widget.imagelist.length; + for (var i = 0; i < count; i++) { + if (widget.imagelist[i].key == imageSelected) { + if (i > 0) { + imageSelected = widget.imagelist[i - 1].key; + loadImage(); + return; + } else { + BotToast.showText(text: "这是第一张图片"); + } + } + } + } + + void loadImage() { + imageScale = 1.0; + imageRotate = 0; + var count = widget.imagelist.length; + for (var i = 0; i < count; i++) { + if (widget.imagelist[i].key == imageSelected) { + imageName = "[" + (i + 1).toString() + "/" + count.toString() + "] " + widget.imagelist[i].title; + setState(() {}); + } + } + Downloader.goImage(widget.box, imageSelected).then((value) { + if (value == "error" || value == "") { + BotToast.showText(text: "预览图片失败,请重试"); + } else { + if (mounted) { + setState(() { + imageUrl = value; + }); + } + } + }); + } + + void zoomImage(double add) { + imageScale = imageScale - add; + if (imageScale <= 0) imageScale = 0.1; + if (mounted) { + setState(() {}); + } + } + + void rotateImage() { + imageRotate = imageRotate + 1; + if (imageRotate >= 4) imageRotate = 0; + setState(() {}); + } + + final GlobalKey imageKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; + var imagew = size.width * 0.8 - 24; + var imageh = size.height * 0.9 - 90; + + 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: size.height * 0.9, + width: size.width * 0.8, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: MColors.dialogBgColor, + ), + padding: EdgeInsets.only(left: 20, right: 4), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + alignment: Alignment.bottomRight, + padding: EdgeInsets.only(top: 8, right: 4), + 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: Row(children: [ + OutlinedButton.icon( + icon: Icon(MIcons.sync, size: 16), label: Text('刷新'), onPressed: () => loadImage()), + Padding(padding: EdgeInsets.only(left: 16)), + OutlinedButton(child: Text('前1张'), onPressed: () => loadImagePrev()), + Padding(padding: EdgeInsets.only(left: 16)), + OutlinedButton(child: Text('后1张'), onPressed: () => loadImageNext()), + Padding(padding: EdgeInsets.only(left: 16)), + _buildBtn(MIcons.xuanzhuan, "顺时针", () => rotateImage()), + Padding(padding: EdgeInsets.only(left: 16)), + Expanded( + child: Container( + alignment: Alignment.topLeft, + child: Text(imageName, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + style: TextStyle( + fontSize: 15, color: MColors.textColor, height: 1, fontFamily: "opposans")))), + Padding(padding: EdgeInsets.only(left: 20)), + ])), + Container(padding: EdgeInsets.only(top: 10)), + Expanded( + child: Container( + width: imagew, + height: imageh, + padding: EdgeInsets.only(bottom: 20), + alignment: Alignment.topLeft, + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: SingleChildScrollView( + controller: verticalScroll, + scrollDirection: Axis.vertical, + physics: BouncingScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints(minWidth: imagew, minHeight: imageh), + child: Container( + width: imagew, + alignment: Alignment.center, + decoration: BoxDecoration( + border: Border.all(width: 1, color: Colors.grey), + borderRadius: BorderRadius.circular(3.0)), + padding: EdgeInsets.all(4), + margin: EdgeInsets.only(top: 4, bottom: 4, right: 16), + child: imageUrl == "" + ? Container() + : ExtendedImage.network(imageUrl, + headers: {"Referer": "https://www.aliyundrive.com/"}, + fit: BoxFit.contain, + width: imagew, + enableLoadState: true, + filterQuality: FilterQuality.high, + mode: ExtendedImageMode.none, + cacheRawData: true, loadStateChanged: (ExtendedImageState state) { + switch (state.extendedImageLoadState) { + case LoadState.loading: + return null; + case LoadState.completed: + verticalScroll.animateTo(0, + duration: Duration(milliseconds: 100), + curve: Curves.ease); //奇怪这里必须刷新一下才显示 + var img = state.extendedImageInfo!.image; + if (imageRotate % 2 == 0) { + //0 2 + return RotatedBox( + quarterTurns: imageRotate, + child: ExtendedRawImage( + image: img, + width: imagew, + scale: img.width / imagew, + )); + } else { + //1 3 + return RotatedBox( + quarterTurns: imageRotate, + child: ExtendedRawImage( + image: img, + height: imagew, + scale: img.height / imagew, + )); + } + + case LoadState.failed: + BotToast.showText(text: "下载图片失败请手动刷新"); + return null; + } + }), + )))))), + ], + ), + )), + ))); + } + + Widget _buildBtn(IconData icondata, String tip, Function() onPressed) { + return UnconstrainedBox( + child: Container( + width: 30, + height: 36, + padding: EdgeInsets.only(top: 6, bottom: 6), + child: HoverContainer( + decoration: BoxDecoration( + border: Border.all(color: MColors.outlineBtnBorderColor, width: 1.0, style: BorderStyle.solid), + borderRadius: BorderRadius.circular(3.0), + color: Colors.transparent), + hoverDecoration: BoxDecoration( + border: Border.all(color: MColors.outlineBtnBorderColor, width: 1.0, style: BorderStyle.solid), + borderRadius: BorderRadius.circular(3.0), + color: MColors.userNavMenuBGHover), + child: IconButton( + iconSize: 20, + padding: EdgeInsets.all(0), + color: MColors.userNavMenuIconHover, + icon: Icon(icondata), + onPressed: onPressed, + tooltip: tip, + )))); + } +} diff --git a/alixby/lib/pagepan/MoveDialog.dart b/alixby/lib/pagepan/MoveDialog.dart new file mode 100644 index 0000000..a3b2823 --- /dev/null +++ b/alixby/lib/pagepan/MoveDialog.dart @@ -0,0 +1,411 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_treeview/flutter_treeview.dart'; +import 'package:hovering/hovering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class MoveDialog extends StatefulWidget { + // ignore: non_constant_identifier_names + MoveDialog({Key? key, required this.iscopy, required this.box, required this.parentid, required this.filelist}) + : super(key: key) { + if (iscopy) pagetitle = "复制"; + } + // ignore: non_constant_identifier_names + bool iscopy = false; + String pagetitle = "移动"; + String box = ""; + String parentid = ""; + // ignore: non_constant_identifier_names + List filelist = []; + + @override + _MoveDialogState createState() => _MoveDialogState(); +} + +class _MoveDialogState extends State { + @override + void initState() { + super.initState(); + movetobox = widget.box; + pageExpandedNode("root", true); + } + + String movetobox = ""; + + static Node _makeNode(String parentkey, String key, String label, int leve, List children) { + var dir = DirNode2(parentkey, key, label, leve); + return Node(label: dir.label, key: dir.key, parent: true, data: dir, children: children); + } + + final ScrollController verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + TreeViewController treeController = TreeViewController(children: [_makeNode("", "root", "网盘根目录", 0, [])]); + String selectKey = ""; + Map loading = {}; + @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: 500, + width: 500, + 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(widget.pagetitle + "文件/文件夹", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 440, + height: 370, + alignment: Alignment.topLeft, + decoration: BoxDecoration( + border: Border.all(width: 1, color: Colors.grey), borderRadius: BorderRadius.circular(3.0)), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + hoverThickness: 9, + thickness: 9, + showTrackOnHover: true, + child: SingleChildScrollView( + controller: verticalScroll, + scrollDirection: Axis.vertical, + physics: BouncingScrollPhysics(), + child: Container( + alignment: Alignment.topLeft, + padding: EdgeInsets.only(bottom: 12), + child: TreeView( + shrinkWrap: true, + primary: true, + controller: treeController, + physics: BouncingScrollPhysics(), + allowParentSelect: true, + supportParentDoubleTap: true, + onExpansionChanged: _expandNodeHandler, + onNodeTap: _onNodeTap, + nodeBuilder: _builderTreeNode, + theme: TreeViewTheme( + expanderTheme: ExpanderThemeData( + type: ExpanderType.caret, + modifier: ExpanderModifier.none, + position: ExpanderPosition.start, + color: MColors.userNavColor, + size: 20, + ), + labelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), + parentLabelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), + iconTheme: IconThemeData(size: 18, color: MColors.pageLeftRowItemIconColor), + colorScheme: ColorScheme.light().copyWith(primary: Colors.transparent), + expandSpeed: Duration(milliseconds: 100), + ), + )), + ))), + Container( + width: 440, + padding: EdgeInsets.only(top: 12), + child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + UnconstrainedBox( + child: Container( + height: 32, + padding: EdgeInsets.only(left: 7, right: 5), + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(3.0), //3像素圆角 + border: Border.all( + color: MColors.inputBorderColor, + width: 1.0, + ), + ), + child: DropdownButton( + isDense: true, + itemHeight: 32, //需要修改kMinInteractiveDimension =32 + elevation: 0, + value: movetobox, + underline: Container(height: 0), + dropdownColor: MColors.userNavMenuBG, + onChanged: (String? newValue) { + if (newValue != null) { + movetobox = newValue; + setState(() { + movetobox = newValue; + }); + pageExpandedNode("root", true); + } + }, + items: [ + DropdownMenuItem( + value: "box", + child: Text(widget.pagetitle + '到 网盘', + style: TextStyle( + fontSize: 14, color: MColors.textColor, fontFamily: "opposans"))), + DropdownMenuItem( + value: "xiangce", + child: Text(widget.pagetitle + '到 相册', + style: TextStyle( + fontSize: 14, color: MColors.textColor, fontFamily: "opposans"))), + ]))), + Expanded(child: Container()), + OutlinedButton( + onPressed: () => Navigator.of(context).pop('ok'), + child: Text("取消"), + 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(); + + 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"); //触发联网加载 + }); + + 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() + "个文件"); + }); + } + } + }, + child: Text(widget.pagetitle + "到选中的文件夹内"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ]), + ), + ], + ), + )), + ))); + } + + _updateTree(TreeViewController tree) { + treeController = tree; + if (mounted) { + setState(() {}); + } + } + + //页面调用,点击文件树的一个文件夹时触发 + pageExpandedNode(String key, bool expanded) { + Node? node = treeController.getNode(key); + if (node != null) { + selectKey = key; + //选中并展开 + Node node2 = node.copyWith(expanded: expanded); + if (key == "root") { + if (movetobox == "box") { + //node2 = node.copyWith(label: "网盘目录树", expanded: expanded); + node2 = _makeNode("", "root", "网盘根目录", 0, node.children).copyWith(expanded: expanded); + } else if (movetobox == "xiangce") { + //node2 = node.copyWith(label: "相册目录树", expanded: expanded); + node2 = _makeNode("", "root", "相册根目录", 0, node.children).copyWith(expanded: expanded); + } + } + + List updated = treeController.updateNode(key, node2); + _updateTree(treeController.copyWith(children: updated, selectedKey: key)); + + if (expanded == true) { + if (!loading.containsKey(key) || loading[key] == false) { + loading[key] = true; + //是文件夹&&children子文件数==0&&要展开显示了 + //注意node.parent,当联网后发现是空文件夹,node.parent会变成false + + AliFile.apiDirList(movetobox, key, node2.label).then((loadData) { + if (loadData.key == "error") return; + var leve = node2.data.leve + 1; + //动态新增 + List children = []; + var total = loadData.list.length; + for (int i = 0; i < total; i++) { + var m = loadData.list[i]; + if (m.isDir) children.add(_makeNode(m.parentkey, m.key, m.name, leve, [])); + } + node2 = node2.copyWith(expanded: true, parent: true, children: children); //注意这里更新了parent + //更新并展开 + List updated = treeController.updateNode(key, node2); + _updateTree(treeController.copyWith(children: updated, selectedKey: selectKey)); + loading[key] = false; + }); + } + } + } + } + + pageSelectNode(String key) { + Node? node = treeController.getNode(key); + if (node != null) { + pageExpandedNode(node.key, !node.expanded); + } + } + + _expandNodeHandler(String key, bool expanded) { + pageExpandedNode(key, expanded); + } + + _onNodeTap(String key) { + pageSelectNode(key); + } + + Widget _builderTreeNode(BuildContext context, Node node) { + DirNode2? dir = node.data; + if (dir != null) { + return selectKey == node.key ? dir.widgetSelect : dir.widget; + } else { + return Container(); + } + } +} + +class DirNode2 { + DirNode2(this.parentkey, this.key, this.label, this.leve) { + widget = Container( + key: Key("pdt_move_rc_" + key), + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(top: 2, bottom: 2), + child: UnconstrainedBox( + alignment: Alignment.centerLeft, + child: HoverContainer( + key: Key("pdt_move_rch_" + key), + cursor: SystemMouseCursors.click, + height: 24, + decoration: decoration, + hoverDecoration: hoverDecoration, + child: Container( + key: Key("pdt_move_rchc_" + key), + width: 400 - leve * 20, + height: 24, + padding: padding, + child: Row(key: Key("pdt_move_rchcr_" + key), children: [ + icon, + padding2, + Expanded( + child: Text( + label, + key: Key("pdt_move_rchcrt_" + key), + style: style, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + )) + ]))))); + + widgetSelect = Container( + key: Key("pdt_move_rc_" + key), + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(top: 2, bottom: 2), + child: UnconstrainedBox( + alignment: Alignment.centerLeft, + child: HoverContainer( + key: Key("pdt_move_rch_" + key), + cursor: SystemMouseCursors.click, + height: 24, + decoration: decorations, + hoverDecoration: hoverDecorations, + child: Container( + key: Key("pdt_move_rchc_" + key), + width: 400 - leve * 20, + height: 24, + padding: padding, + child: Row(key: Key("pdt_move_rchcr_" + key), children: [ + icons, + padding2, + Expanded( + child: Text( + label, + key: Key("pdt_move_rchcrt_" + key), + style: styles, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + )) + ]))))); + } + + String label = ""; + String key = ""; + //父文件夹key + String parentkey = ""; + //文件夹层级 + int leve = 0; + + Widget widget = Container(); + Widget widgetSelect = Container(); + + var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); + var decorations = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); + + var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); + var hoverDecorations = + BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); + + var padding = EdgeInsets.only(left: 3, right: 3); + var padding2 = Padding(padding: EdgeInsets.only(left: 8)); + var icon = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); + var icons = Icon(MIcons.folder, size: 20, color: MColors.userNavMenuIconHover); + var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor, fontFamily: "opposans"); + var styles = TextStyle(fontSize: 14, color: MColors.userNavMenuIconHover, fontFamily: "opposans"); +} diff --git a/alixby/lib/views/PageLeftPan.dart b/alixby/lib/pagepan/PageLeftPan.dart similarity index 68% rename from alixby/lib/views/PageLeftPan.dart rename to alixby/lib/pagepan/PageLeftPan.dart index 0954b84..c90e9c2 100644 --- a/alixby/lib/views/PageLeftPan.dart +++ b/alixby/lib/pagepan/PageLeftPan.dart @@ -1,46 +1,73 @@ +import 'package:alixby/states/TreeState.dart'; import 'package:alixby/states/UserState.dart'; import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter_treeview/flutter_treeview.dart'; -import '../states/Global.dart'; -import '../states/PanTreeState.dart'; +import 'package:alixby/states/Global.dart'; import 'package:provider/provider.dart'; -import '../utils/MIcons.dart'; +import 'package:alixby/utils/MIcons.dart'; -import '../utils/MColors.dart'; +import 'package:alixby/utils/MColors.dart'; import 'package:hovering/hovering.dart'; -import '../models/PageLeftRowItem.dart'; +import 'package:alixby/models/PageLeftRowItem.dart'; import 'package:flutter/material.dart'; +// ignore: must_be_immutable class PageLeftPan extends StatefulWidget { + PageLeftPan(this.box) : super(); + String box = ""; @override _PageLeftPanState createState() => _PageLeftPanState(); } class _PageLeftPanState extends State with AutomaticKeepAliveClientMixin { - final data = [ - PageLeftRowItem.newPageLeftRowItem("trash", "rest", "回收站"), - PageLeftRowItem.newPageLeftRowItem("favorite", "crown", "收藏夹"), - PageLeftRowItem.newPageLeftRowItem("safebox", "rpasswoed", "保险箱"), + var data = [ + PageLeftRowItem.newPageLeftRowItem("trash", "rest", "网盘回收站"), + PageLeftRowItem.newPageLeftRowItem("favorite", "crown", "网盘收藏夹"), ]; void onPageLeftRowItemChanged(String key) { - if (key == "safebox") { + if (key == 'safebox') { BotToast.showText(text: "此功能还在开发中"); return; } - Global.panTreeState.pageMenuSelectKey(key); + Global.getTreeState(widget.box).pageMenuSelectKey(key); } @override void initState() { super.initState(); + if (widget.box == "box") { + data = [ + PageLeftRowItem.newPageLeftRowItem("trash", "rest", "网盘回收站"), + PageLeftRowItem.newPageLeftRowItem("favorite", "crown", "网盘收藏夹"), + ]; + } else if (widget.box == "xiangce") { + data = [ + PageLeftRowItem.newPageLeftRowItem("trash", "rest", "相册回收站"), + PageLeftRowItem.newPageLeftRowItem("favorite", "crown", "相册收藏夹"), + ]; + } } @override // ignore: must_call_super Widget build(BuildContext context) { + var selectKey = ""; + if (widget.box == "box") { + selectKey = context.watch().selectKey; + } else if (widget.box == "xiangce") { + selectKey = context.watch().selectKey; + } + var userPanUsed = context.watch().userPanUsed; + + List menulist = []; + for (var i = 0; i < data.length; i++) { + menulist.add(_buildItem(context, i, selectKey)); + } + return Container( alignment: Alignment.topLeft, child: Column( @@ -49,15 +76,15 @@ class _PageLeftPanState extends State with AutomaticKeepAliveClient padding: EdgeInsets.only(left: 26, right: 18, top: 9, bottom: 5), alignment: Alignment.centerLeft, child: Text( - context.watch().userPanUsed, - style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor), + userPanUsed, + style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor, fontFamily: "opposans"), )), Container( alignment: Alignment.centerLeft, height: 32, padding: EdgeInsets.only(left: 12, right: 8), child: Row( - children: [_buildItem(context, 0), _buildItem(context, 1), _buildItem(context, 2)], + children: menulist, ), ), Container(height: 3), @@ -67,8 +94,7 @@ class _PageLeftPanState extends State with AutomaticKeepAliveClient } //136 - Widget _buildItem(BuildContext context, int index) { - var selectKey = context.watch().selectKey; + Widget _buildItem(BuildContext context, int index, String selectKey) { var item = data[index]; return Container( alignment: Alignment.centerLeft, @@ -97,9 +123,9 @@ class _PageLeftPanState extends State with AutomaticKeepAliveClient Text( item.title, style: TextStyle( - color: selectKey == item.key - ? MColors.userNavMenuIconHover - : MColors.pageLeftRowItemColor), + color: + selectKey == item.key ? MColors.userNavMenuIconHover : MColors.pageLeftRowItemColor, + fontFamily: "opposans"), ) ])))))); } @@ -119,17 +145,30 @@ class _PageLeftPanState extends State with AutomaticKeepAliveClient */ _expandNodeHandler(String key, bool expanded) { - Global.panTreeState.pageExpandedNode(key, expanded); + Global.getTreeState(widget.box).pageExpandedNode(key, expanded); } _onNodeTap(String key) { - Global.panTreeState.pageSelectNode(key, true); + Global.getTreeState(widget.box).pageSelectNode(widget.box, key, true); + } + + @override + void dispose() { + verticalScroll.dispose(); + hengScroll.dispose(); + super.dispose(); } final verticalScroll = ScrollController(); - final horizontalScroll = ScrollController(); + final hengScroll = ScrollController(); final GlobalKey treeConKey = GlobalKey(); Widget _buildTree(BuildContext context) { + var treewidth = 0.0; + if (widget.box == "box") { + treewidth = context.watch().width; + } else if (widget.box == "xiangce") { + treewidth = context.watch().width; + } return Container( key: treeConKey, alignment: Alignment.topLeft, @@ -152,18 +191,19 @@ class _PageLeftPanState extends State with AutomaticKeepAliveClient child: Container( alignment: Alignment.topLeft, child: SingleChildScrollView( - controller: horizontalScroll, scrollDirection: Axis.horizontal, + controller: hengScroll, physics: BouncingScrollPhysics(), + dragStartBehavior: DragStartBehavior.down, child: Container( //color: Colors.red, alignment: Alignment.topLeft, - width: context.watch().width, + width: treewidth, padding: EdgeInsets.only(bottom: 12), child: TreeView( shrinkWrap: true, primary: true, - controller: context.watch().treeController, + controller: Global.getTreeState(widget.box).treeController, physics: BouncingScrollPhysics(), allowParentSelect: true, supportParentDoubleTap: true, @@ -178,13 +218,15 @@ class _PageLeftPanState extends State with AutomaticKeepAliveClient color: MColors.userNavColor, size: 20, ), - labelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.normal), - parentLabelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.normal), + labelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), + parentLabelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), iconTheme: IconThemeData(size: 18, color: MColors.pageLeftRowItemIconColor), colorScheme: ColorScheme.light().copyWith(primary: Colors.transparent), expandSpeed: Duration(milliseconds: 100), )))))), - Container(width: 16, height: 300), + Container(width: 16, height: 1), ]))), )); } @@ -192,7 +234,7 @@ class _PageLeftPanState extends State with AutomaticKeepAliveClient Widget _builderTreeNode(BuildContext context, Node node) { DirNode? dir = node.data; if (dir != null) { - return Global.panTreeState.selectKey == node.key ? dir.widgetSelect : dir.widget; + return Global.getTreeState(widget.box).selectKey == node.key ? dir.widgetSelect : dir.widget; } else { return Container(); } diff --git a/alixby/lib/views/PageRightPan.dart b/alixby/lib/pagepan/PageRightPan.dart similarity index 78% rename from alixby/lib/views/PageRightPan.dart rename to alixby/lib/pagepan/PageRightPan.dart index 60a73c6..682810f 100644 --- a/alixby/lib/views/PageRightPan.dart +++ b/alixby/lib/pagepan/PageRightPan.dart @@ -1,15 +1,18 @@ +import 'package:alixby/states/FileState.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/states/PanFileState.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; -import 'package:alixby/widgets/PanFileList.dart'; -import 'package:alixby/widgets/PanRightTopButton.dart'; +import 'package:alixby/pagepan/PanFileList.dart'; +import 'package:alixby/pagepan/PanRightTopButton.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:hovering/hovering.dart'; import 'package:provider/provider.dart'; +// ignore: must_be_immutable class PageRightPan extends StatefulWidget { + PageRightPan(this.box) : super(); + String box = ""; @override _PageRightPanState createState() => _PageRightPanState(); } @@ -18,12 +21,17 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie @override void initState() { super.initState(); - print('_PageRightPanState initState'); } @override // ignore: must_call_super Widget build(BuildContext context) { + FileState? filestate; + if (widget.box == "box") { + filestate = context.watch(); + } else if (widget.box == "xiangce") { + filestate = context.watch(); + } return Column( children: [ Container( @@ -32,7 +40,7 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie alignment: Alignment.centerLeft, child: RichText( textAlign: TextAlign.left, - text: context.watch().pageRightDirPath, + text: filestate!.pageRightDirPath, textDirection: TextDirection.ltr, )), Container( @@ -48,8 +56,7 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie child: child, ); }, - child: PanRightTopButton(context.watch().pageRightFileSelectedCount, - context.watch().getPageName))), + child: PanRightTopButton(widget.box, filestate.pageRightFileSelectedCount, filestate.getPageName))), Container(height: 1, width: double.infinity, color: MColors.pageRightBorderColor), Container( height: 40, @@ -58,13 +65,13 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ _buildSelectAll(), Padding(padding: EdgeInsets.only(left: 8)), - Text(context.watch().pageRightFileSelectedDes), + Text(filestate.pageRightFileSelectedDes), Expanded(child: Container()), Container(child: Icon(MIcons.sort, color: Color(0xff637dff), size: 28)), - Container(child: _buildSortMenu()), + Container(child: _buildSortMenu(filestate)), Padding(padding: EdgeInsets.only(left: 12)), ])), - Expanded(child: PanFileList()), + Expanded(child: PanFileList(widget.box)), ], ); } @@ -83,16 +90,16 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie color: Color(0xff637dff), icon: Icon(MIcons.rsuccess), onPressed: () { - Global.panFileState.pageSelectFile("all"); + Global.getFileState(widget.box).pageSelectFile("all"); }, tooltip: '全选', )))); } - Widget _buildSortMenu() { + Widget _buildSortMenu(FileState filestate) { return PopupMenuButton( onSelected: (value) { - Global.panFileState.pageChangeOrderBy(value); + Global.getFileState(widget.box).pageChangeOrderBy(value); }, color: MColors.userNavBtnBG, offset: Offset(0, 26), @@ -100,42 +107,42 @@ class _PageRightPanState extends State with AutomaticKeepAliveClie side: BorderSide(color: MColors.userNavBtnBorder), borderRadius: BorderRadius.circular(4)), tooltip: '选择排序方式', padding: EdgeInsets.all(0), - child: Text("按 " + context.watch().pageRightFileOrderBy + " 排序", - style: TextStyle(fontSize: 14, color: Color(0xff637dff))), + child: Text("按 " + filestate.pageRightFileOrderBy + " 排序", + style: TextStyle(fontSize: 14, color: Color(0xff637dff), fontFamily: "opposans")), itemBuilder: (context) { return >[ PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), height: 32, value: '文件名 从小到大', child: Text('文件名 从小到大'), ), PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), height: 32, value: '文件名 从大到小', child: Text('文件名 从大到小'), ), PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), height: 32, value: '文件体积 从小到大', child: Text('文件体积 从小到大'), ), PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), height: 32, value: '文件体积 从大到小', child: Text('文件体积 从大到小'), ), PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), height: 32, value: '上传时间 从小到大', child: Text('上传时间 从小到大'), ), PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 14, fontFamily: "opposans"), height: 32, value: '上传时间 从大到小', child: Text('上传时间 从大到小'), diff --git a/alixby/lib/widgets/PanFileList.dart b/alixby/lib/pagepan/PanFileList.dart similarity index 65% rename from alixby/lib/widgets/PanFileList.dart rename to alixby/lib/pagepan/PanFileList.dart index e8cce2d..99a444c 100644 --- a/alixby/lib/widgets/PanFileList.dart +++ b/alixby/lib/pagepan/PanFileList.dart @@ -1,9 +1,10 @@ import 'package:alixby/api/Downloader.dart'; +import 'package:alixby/pagepan/ImagesDialog.dart'; import 'package:alixby/states/Global.dart'; -import 'package:alixby/states/PanFileState.dart'; import 'package:alixby/utils/Loading.dart'; -import 'package:alixby/widgets/ImageDialog.dart'; -import 'package:alixby/widgets/TextDialog.dart'; +import 'package:alixby/pagepan/ImageDialog.dart'; +import 'package:alixby/pagepan/TextDialog.dart'; +import 'package:alixby/pagepan/UnRarDialog.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/rendering.dart'; import 'package:hovering/hovering.dart'; @@ -12,7 +13,10 @@ import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; import 'package:flutter/material.dart'; +// ignore: must_be_immutable class PanFileList extends StatefulWidget { + PanFileList(this.box) : super(); + String box = ""; @override _PanFileListState createState() => _PanFileListState(); } @@ -21,7 +25,6 @@ class _PanFileListState extends State { @override void initState() { super.initState(); - print('_PanFileListState initState'); } @override @@ -36,37 +39,38 @@ class _PanFileListState extends State { final GlobalKey fileListKey = GlobalKey(); @override Widget build(BuildContext context) { + var itemCount = 0; + if (widget.box == 'box') { + itemCount = context.watch().pageRightFileList.length; + } else if (widget.box == "xiangce") { + itemCount = context.watch().pageRightFileList.length; + } return Container( - key: fileConKey, - width: double.infinity, - decoration: BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), - alignment: Alignment.topLeft, - child: Scrollbar( - key: fileSBKey, + key: fileConKey, + width: double.infinity, + decoration: BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), + alignment: Alignment.topLeft, + child: Scrollbar( + key: fileSBKey, + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: ListView.builder( + key: fileListKey, controller: verticalScroll, - isAlwaysShown: true, - showTrackOnHover: true, - thickness: 9, - hoverThickness: 9, - child: Row( - children: [ - Expanded( - child: ListView.builder( - key: fileListKey, - controller: verticalScroll, - shrinkWrap: false, - primary: false, - addSemanticIndexes: false, - addAutomaticKeepAlives: false, - scrollDirection: Axis.vertical, - physics: ClampingScrollPhysics(), - itemExtent: 50, - itemCount: context.watch().pageRightFileList.length, - itemBuilder: _buildList, - )), - Container(width: 16), - ], - ))); + shrinkWrap: false, + primary: false, + addSemanticIndexes: false, + addAutomaticKeepAlives: false, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + itemExtent: 50, + itemCount: itemCount, + itemBuilder: _buildList, + )), + ); } static Icon iconSelected = Icon(MIcons.rsuccess, color: MColors.iconSelected); @@ -75,29 +79,40 @@ class _PanFileListState extends State { static Padding padding6 = Padding(padding: EdgeInsets.only(left: 6)); static Padding padding4 = Padding(padding: EdgeInsets.only(left: 4)); static Padding padding12 = Padding(padding: EdgeInsets.only(left: 12)); - static TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor); + static TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"); static SizedBox sizeBox = SizedBox(width: 40, height: 40, child: iconSelect); static SizedBox sizeBoxFavor = SizedBox(width: 40, height: 40, child: iconSelectFavor); static SizedBox sizeBoxed = SizedBox(width: 40, height: 40, child: iconSelected); - static onTapFileName(String key, String filetype, BuildContext context) { - print('点击文件名'); - onTapFile(key); + static onTapFileName(String box, String key, String filetype, BuildContext context) { + onTapFile(box, key); //var page = Global.panFileState.getPageName; //if (page == "trash") return;//回收站内文件同样可以预览 //todo::收藏夹,向上遍历父文件夹路径 if (filetype == "folder") { - Global.panTreeState.pageSelectNode(key, true); + Global.getTreeState(box).pageSelectNode(box, key, true); return; } else if (filetype == "file") { //不支持预览的文件格式,忽略 return; } else if (filetype == "video" || filetype == "audio") { - Downloader.goPlay(key); + BotToast.showLoading(duration: Duration(seconds: 3)); + Downloader.goPlay(box, key); + return; + } else if (filetype == "image") { + var imagelist = Global.getFileState(box).getImageFiles(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: ImagesDialog(box: box, imageselected: key, imagelist: imagelist)); + }); return; } else if (filetype == "image") { var fcHide = Loading.showLoading(); - Downloader.goImage(key).then((value) { + Downloader.goImage(box, key).then((value) { fcHide(); if (value == "error" || value == "") { BotToast.showText(text: "预览图片失败,请重试"); @@ -115,7 +130,7 @@ class _PanFileListState extends State { return; } else if (filetype == "txt") { var fcHide = Loading.showLoading(); - Downloader.goText(key).then((value) { + Downloader.goText(box, key).then((value) { fcHide(); if (value == "error") { BotToast.showText(text: "预览文本失败,请重试"); @@ -126,21 +141,30 @@ class _PanFileListState extends State { builder: (context) { return WillPopScope( onWillPop: () async => false, //关键代码 - child: TextDialog(text: value)); + child: TextDialog(box: box, text: value)); }); } }); return; + } else if (filetype == "zip") { + //AliFile.apiUncompress(key, target_file_id, password) + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: UnrarDialog(box: box, fileid: key)); + }); } } - static onTapFile(String key) { - Global.panFileState.pageSelectFile(key); - print('选中文件'); + static onTapFile(String box, String key) { + Global.getFileState(box).pageSelectFile(key); } Widget _buildList(BuildContext context, int index) { - var item = Global.panFileState.pageRightFileList[index]; + var item = Global.getFileState(widget.box).pageRightFileList[index]; var decoration = BoxDecoration( color: MColors.pageRightFileBG, border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); @@ -154,11 +178,11 @@ class _PanFileListState extends State { var hoverDecorations = BoxDecoration( color: MColors.pageRightFileBGSelect, border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); - //print("buildfile " + item.key); - //if (item.icon[0] == '.') item.icon = FileIcons.getFileIcon(item.icon, ""); + var title = item.title.padRight(10); return HoverContainer( key: Key("prf_h_" + item.key), cursor: SystemMouseCursors.basic, + padding: EdgeInsets.only(right: 16), height: 50, decoration: item.selected ? decorations : decoration, hoverDecoration: item.selected ? hoverDecorations : hoverDecoration, @@ -167,7 +191,7 @@ class _PanFileListState extends State { height: 50, child: InkWell( mouseCursor: SystemMouseCursors.basic, - onTap: () => onTapFile(item.key), + onTap: () => onTapFile(item.box, item.key), child: Row( key: Key("prf_hcr_" + item.key), children: [ @@ -185,9 +209,8 @@ class _PanFileListState extends State { child: InkWell( mouseCursor: item.filetype != "file" ? SystemMouseCursors.click : SystemMouseCursors.basic, - onTap: () => onTapFileName(item.key, item.filetype, context), - child: - Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2)))) + onTap: () => onTapFileName(item.box, item.key, item.filetype, context), + child: Text(title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2)))) ])), Container( key: Key("prf_hcr_s_" + item.key), @@ -199,7 +222,7 @@ class _PanFileListState extends State { key: Key("prf_hcr_t_" + item.key), width: 44, alignment: Alignment.centerRight, - child: Text(item.filetimestr, style: textStyle, textAlign: TextAlign.center, maxLines: 2), + child: Text(item.filetimestr, style: textStyle, textAlign: TextAlign.right, maxLines: 2), ), padding12, ], diff --git a/alixby/lib/widgets/PanRightTopButton.dart b/alixby/lib/pagepan/PanRightTopButton.dart similarity index 60% rename from alixby/lib/widgets/PanRightTopButton.dart rename to alixby/lib/pagepan/PanRightTopButton.dart index 9c55775..833094d 100644 --- a/alixby/lib/widgets/PanRightTopButton.dart +++ b/alixby/lib/pagepan/PanRightTopButton.dart @@ -1,27 +1,31 @@ import 'package:alixby/api/AliFile.dart'; 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/states/Global.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/widgets/CreatMiaoChuanDialog.dart'; -import 'package:alixby/widgets/SaveMiaoChuanDialog.dart'; +import 'package:alixby/pagepan/CreatMiaoChuanDialog.dart'; +import 'package:alixby/pagepan/RenameMutlDialog.dart'; +import 'package:alixby/pagepan/SaveMiaoChuanTxtDialog.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; -import 'CreatDirDialog.dart'; -import 'DownSaveDialog.dart'; -import 'MoveDialog.dart'; -import 'RenameDialog.dart'; +import 'package:alixby/pagepan/CreatDirDialog.dart'; +import 'package:alixby/pagepan/DownSaveDialog.dart'; +import 'package:alixby/pagepan/MoveDialog.dart'; +import 'package:alixby/pagepan/RenameDialog.dart'; // ignore: must_be_immutable class PanRightTopButton extends StatefulWidget { - PanRightTopButton(this.selectCount, this.selectKey) + PanRightTopButton(this.box, this.selectCount, this.selectKey) : super(key: Key('prbk_' + selectKey + "_" + (selectCount > 0 ? "selected" : "no"))); int selectCount = 0; String selectKey = ""; + String box = ""; @override _PanRightTopButtonState createState() => _PanRightTopButtonState(); } @@ -30,7 +34,6 @@ class _PanRightTopButtonState extends State { @override void initState() { super.initState(); - print('_PanRightTopButtonState initState'); } @override @@ -38,12 +41,13 @@ class _PanRightTopButtonState extends State { Widget build(BuildContext context) { var selectCount = widget.selectCount; var selectKey = widget.selectKey; - if (selectKey == "trash") return (selectCount == 0) ? _buildButtons_refresh() : _buildButtons_trashselect(); - if (selectKey == "favorite") return (selectCount == 0) ? _buildButtons_refresh() : _buildButtons_favoriteselect(); + if (selectKey == "trash") return (selectCount == 0) ? _buildButtons_refresh() : _buildButtons_trashSelect(); + if (selectKey == "favorite") return (selectCount == 0) ? _buildButtons_refresh() : _buildButtons_favoriteSelect(); if (selectKey == "safebox") return _buildButtons_safebox(); - if (selectKey == "calendar") return (selectCount == 0) ? _buildButtons_refresh() : _buildButtons_calendarselect(); + if (selectKey == "xiangce") return (selectCount == 0) ? _buildButtons_refresh() : _buildButtons_xiangceSelect(); + //默认显示文件列表 - return (selectCount == 0) ? _buildButtons_dir() : _buildButtons_dirselect(); + return (selectCount == 0) ? _buildButtons_dir() : _buildButtons_dirSelect(); } // ignore: non_constant_identifier_names @@ -56,14 +60,16 @@ class _PanRightTopButtonState extends State { _buildCreatDir(), Padding(padding: EdgeInsets.only(left: 12)), _buildUpload(), - Padding(padding: EdgeInsets.only(left: 42)), + Padding(padding: EdgeInsets.only(left: 12)), _buildSaveMiaoChuan(), + Padding(padding: EdgeInsets.only(left: 12)), + _buildSaveShare(), ], ); } // ignore: non_constant_identifier_names - Widget _buildButtons_dirselect() { + Widget _buildButtons_dirSelect() { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -73,11 +79,15 @@ class _PanRightTopButtonState extends State { Padding(padding: EdgeInsets.only(left: 12)), _buildMove(), Padding(padding: EdgeInsets.only(left: 12)), + _buildCopy(), + Padding(padding: EdgeInsets.only(left: 12)), _buildRename(), Padding(padding: EdgeInsets.only(left: 12)), _buildFavor(true), Padding(padding: EdgeInsets.only(left: 12)), _buildTrash(), + Padding(padding: EdgeInsets.only(left: 12)), + _buildCreatMiaoChuan(), ], ); } @@ -94,7 +104,7 @@ class _PanRightTopButtonState extends State { } // ignore: non_constant_identifier_names - Widget _buildButtons_favoriteselect() { + Widget _buildButtons_favoriteSelect() { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -104,6 +114,8 @@ class _PanRightTopButtonState extends State { Padding(padding: EdgeInsets.only(left: 12)), _buildMove(), Padding(padding: EdgeInsets.only(left: 12)), + _buildCopy(), + Padding(padding: EdgeInsets.only(left: 12)), _buildRename(), Padding(padding: EdgeInsets.only(left: 12)), _buildFavor(false), @@ -115,7 +127,7 @@ class _PanRightTopButtonState extends State { } // ignore: non_constant_identifier_names - Widget _buildButtons_trashselect() { + Widget _buildButtons_trashSelect() { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -141,7 +153,7 @@ class _PanRightTopButtonState extends State { } // ignore: non_constant_identifier_names - Widget _buildButtons_calendarselect() { + Widget _buildButtons_xiangceSelect() { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -155,7 +167,9 @@ class _PanRightTopButtonState extends State { Widget _buildRefresh() { return OutlinedButton.icon( - icon: Icon(MIcons.sync, size: 16), label: Text('刷新'), onPressed: () => Global.panTreeState.pageRefreshNode()); + icon: Icon(MIcons.sync, size: 16), + label: Text('刷新'), + onPressed: () => Global.getTreeState(widget.box).pageRefreshNode()); } Widget _buildCreatDir() { @@ -169,7 +183,7 @@ class _PanRightTopButtonState extends State { builder: (context) { return WillPopScope( onWillPop: () async => false, //关键代码 - child: CreatDirDialog()); + child: CreatDirDialog(box: widget.box)); }); }); } @@ -178,7 +192,7 @@ class _PanRightTopButtonState extends State { return SizedBox( child: PopupMenuButton( onSelected: (value) { - var parentid = Global.panFileState.pageRightDirKey; + var parentid = Global.getFileState(widget.box).pageRightDirKey; if (value == "uploadfiles") { FileSelectorPlatform.instance.openFiles(confirmButtonText: "上传选中的文件").then((values) { if (values.length > 0) { @@ -187,7 +201,7 @@ class _PanRightTopButtonState extends State { filelist.add(values[i].path); } var fcHide = Loading.showLoading(); - Uploader.goUploadFile(parentid, filelist).then((value) { + Uploader.goUploadFile(widget.box, parentid, filelist).then((value) { fcHide(); if (value > 0) { BotToast.showText(text: "成功创建" + value.toString() + "个文件的上传任务"); @@ -201,7 +215,7 @@ class _PanRightTopButtonState extends State { FileSelectorPlatform.instance.getDirectoryPath(confirmButtonText: "上传整个选中的文件夹").then((dirpath) { if (dirpath != null) { var fcHide = Loading.showLoading(); - Uploader.goUploadDir(parentid, dirpath).then((value) { + Uploader.goUploadDir(widget.box, parentid, dirpath).then((value) { fcHide(); if (value > 0) { BotToast.showText(text: "成功创建" + value.toString() + "个文件夹的上传任务"); @@ -228,13 +242,13 @@ class _PanRightTopButtonState extends State { itemBuilder: (context) { return >[ PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15, fontFamily: "opposans"), height: 32, value: 'uploadfiles', child: Text('上传文件'), ), PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15), + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15, fontFamily: "opposans"), height: 32, value: 'uploaddir', child: Text('上传文件夹'), @@ -246,7 +260,6 @@ class _PanRightTopButtonState extends State { Widget _buildDown() { var txt = "下载"; - if (widget.selectCount > 1) txt = "批量" + txt; return OutlinedButton.icon( icon: Icon(MIcons.download, size: 16), @@ -254,18 +267,17 @@ class _PanRightTopButtonState extends State { onPressed: () { if (Global.settingState.setting.savePath == "") { BotToast.showText(text: "需要先设置一下下载保存位置"); - Global.userState.updatePageIndex(3); + Global.userState.updatePageIndex(4); return; } - var parentID = Global.panFileState.pageRightDirKey; - var filelist = Global.panFileState.getSelectedFileKeys(); + 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(); - var parentid = Global.panFileState.pageRightDirKey; - Downloader.goDownFile(parentid, savepath, filelist).then((value) { + Downloader.goDownFile(widget.box, parentid, savepath, filelist).then((value) { fcHide(); if (value > 0) { BotToast.showText(text: "成功创建" + value.toString() + "个文件的下载任务"); @@ -276,14 +288,15 @@ class _PanRightTopButtonState extends State { return; } else { //显示弹窗 - var parentPath = Global.panFileState.getSelectedFileParentPath(); + var parentPath = Global.getFileState(widget.box).getSelectedFileParentPath(); showDialog( barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 context: context, builder: (context) { return WillPopScope( onWillPop: () async => false, //关键代码 - child: DownSaveDialog(parentID: parentID, parentPath: parentPath, filelist: filelist)); + child: DownSaveDialog( + box: widget.box, parentid: parentid, parentPath: parentPath, filelist: filelist)); }); } }); @@ -294,81 +307,168 @@ class _PanRightTopButtonState extends State { icon: Icon(MIcons.scissor, size: 16), label: Text("移动"), onPressed: () { - var parentid = Global.panFileState.pageRightDirKey; - var filelist = Global.panFileState.getSelectedFileKeys(); + 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(parentid: parentid, filelist: filelist)); + child: MoveDialog(iscopy: false, box: widget.box, parentid: parentid, filelist: filelist)); }); }); } - // ignore: unused_element - Widget _buildCreatMiaoChuan() { + Widget _buildCopy() { return OutlinedButton.icon( - icon: Icon(MIcons.link2, size: 16), - label: Text("新建秒传链"), + icon: Icon(MIcons.copy, size: 16), + label: Text("复制"), onPressed: () { - var parentid = Global.panFileState.pageRightDirKey; - var filelist = Global.panFileState.getSelectedFileKeys(); + 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: CreatMiaoChuanDialog(parentid: parentid, filelist: filelist)); + child: MoveDialog(iscopy: true, box: widget.box, parentid: parentid, filelist: filelist)); }); }); } - Widget _buildSaveMiaoChuan() { - return OutlinedButton.icon( + // ignore: unused_element + Widget _buildCreatMiaoChuan() { + return ElevatedButton.icon( icon: Icon(MIcons.link2, size: 16), - label: Text("导入秒传链"), + label: Text("创建秒传"), onPressed: () { - var parentid = Global.panFileState.pageRightDirKey; - var parentname = Global.panFileState.getSelectedFileParentPath(); + 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) { + parentname = files[0].title; + } + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); showDialog( barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 context: context, builder: (context) { return WillPopScope( onWillPop: () async => false, //关键代码 - child: SaveMiaoChuanDialog(parentid: parentid, parentname: parentname)); + child: CreatMiaoChuanDialog( + box: widget.box, parentid: parentid, parentname: parentname, filelist: filelist)); }); }); } + Widget _buildSaveMiaoChuan() { + return SizedBox( + child: PopupMenuButton( + onSelected: (value) { + var parentid = Global.getFileState(widget.box).pageRightDirKey; + var parentname = Global.getFileState(widget.box).getSelectedFileParentPath(); + Widget dialog = Container(); + if (value == "txt") { + dialog = SaveMiaoChuanTxtDialog(box: widget.box, parentid: parentid, parentname: parentname); + } else if (value == "aliyunpan" || value == "115") { + dialog = SaveMiaoChuan115Dialog(box: widget.box, parentid: parentid, parentname: parentname); + } else if (value == "xby") { + dialog = SaveMiaoChuanXbyDialog(box: widget.box, parentid: parentid, parentname: parentname); + } + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: dialog); + }); + }, + offset: Offset(0, 28), + shape: RoundedRectangleBorder( + side: BorderSide(color: MColors.userNavBtnBorder), borderRadius: BorderRadius.circular(4)), + tooltip: "各种秒传链接保存到网盘", + padding: EdgeInsets.all(0), + color: MColors.userNavBtnBG, + child: ElevatedButton.icon( + icon: Icon(MIcons.link2, size: 16), + label: Text('导入秒传'), + onPressed: null, + style: ButtonStyle(mouseCursor: MaterialStateMouseCursor.clickable), + ), + itemBuilder: (context) { + return >[ + PopupMenuItem( + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15, fontFamily: "opposans"), + height: 32, + value: 'txt', + child: Text('秒传文件(txt)'), + ), + PopupMenuItem( + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15, fontFamily: "opposans"), + height: 32, + value: 'aliyunpan', + child: Text('aliyunpan://秒传'), + ), + PopupMenuItem( + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15, fontFamily: "opposans"), + height: 32, + value: '115', + child: Text('115://秒传链接'), + ), + PopupMenuItem( + textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15, fontFamily: "opposans"), + height: 32, + value: 'xby', + child: Text('xby.writeas.com'), + ), + ]; + }, + )); + } + + 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: "此功能还在开发中"); + }); + } + Widget _buildRename() { if (widget.selectCount <= 1) { return OutlinedButton.icon( icon: Icon(MIcons.edit_square, size: 16), label: Text('改名'), onPressed: () { - var filelist = Global.panFileState.getSelectedFiles(); - + var filelist = Global.getFileState(widget.box).getSelectedFiles(); showDialog( barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 context: context, builder: (context) { return WillPopScope( onWillPop: () async => false, //关键代码 - child: RenameDialog(file_id: filelist[0].key, file_name: filelist[0].title)); + 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('批量改名', style: TextStyle(decoration: TextDecoration.lineThrough)), + label: Text('批量改名'), onPressed: () { - //todo::批量重命名 - print('批量重命名'); - BotToast.showText(text: "此功能还在开发中"); + 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)); + }); }); } } @@ -378,13 +478,15 @@ class _PanRightTopButtonState extends State { icon: Icon(MIcons.rest, size: 16), label: Text("回收站"), onPressed: () { - var filelist = Global.panFileState.getSelectedFileKeys(); + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); if (filelist.length > 0) { var fcHide = Loading.showLoading(); - AliFile.apiTrashBatch(filelist).then((value) { + AliFile.apiTrashBatch(widget.box, filelist).then((value) { fcHide(); - Global.panTreeState.pageRefreshNode(); + Future.delayed(Duration(milliseconds: 200), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); PanData.clearTrash(); BotToast.showText(text: "成功移到回收站" + value.toString() + "个文件"); }); @@ -399,12 +501,14 @@ class _PanRightTopButtonState extends State { icon: Icon(MIcons.delete, size: 16), label: Text(txt), onPressed: () { - var filelist = Global.panFileState.getSelectedFileKeys(); + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); if (filelist.length > 0) { var fcHide = Loading.showLoading(); - AliFile.apiTrashDeleteBatch(filelist).then((value) { + AliFile.apiTrashDeleteBatch(widget.box, filelist).then((value) { fcHide(); - Global.panTreeState.pageRefreshNode(); + Future.delayed(Duration(milliseconds: 200), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); }); } @@ -418,13 +522,15 @@ class _PanRightTopButtonState extends State { icon: Icon(MIcons.recover, size: 16), label: Text(txt), onPressed: () { - var filelist = Global.panFileState.getSelectedFileKeys(); + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); if (filelist.length > 0) { var fcHide = Loading.showLoading(); - AliFile.apiTrashRestoreBatch(filelist).then((value) { + AliFile.apiTrashRestoreBatch(widget.box, filelist).then((value) { fcHide(); - Global.panTreeState.pageRefreshNode(); + Future.delayed(Duration(milliseconds: 200), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); }); } @@ -454,13 +560,15 @@ class _PanRightTopButtonState extends State { icon: Icon(MIcons.crown, size: 16), label: Text(txt), onPressed: () { - var filelist = Global.panFileState.getSelectedFileKeys(); + var filelist = Global.getFileState(widget.box).getSelectedFileKeys(); if (filelist.length > 0) { var fcHide = Loading.showLoading(); - AliFile.apiFavorBatch(isfavor, filelist).then((value) { + AliFile.apiFavorBatch(widget.box, isfavor, filelist).then((value) { fcHide(); - Global.panTreeState.pageRefreshNode(); + Future.delayed(Duration(milliseconds: 200), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); if (isfavor) PanData.clearFavor(); BotToast.showText(text: "成功" + txt + value.toString() + "个文件"); }); diff --git a/alixby/lib/pagepan/RenameDialog.dart b/alixby/lib/pagepan/RenameDialog.dart new file mode 100644 index 0000000..eedf24b --- /dev/null +++ b/alixby/lib/pagepan/RenameDialog.dart @@ -0,0 +1,135 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:provider/provider.dart'; +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) { + controller.text = filename; + } + + String box = ""; + String fileid = ""; + + 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( + 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: 200, + width: 460, + 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("重命名", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 380, + padding: EdgeInsets.only(top: 20), + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 60, maxWidth: 375), + child: TextField( + controller: controller, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + style: TextStyle( + fontSize: 14, color: MColors.textColor, fontFamily: "opposans", height: 1), + cursorColor: MColors.inputBorderHover, + autofocus: true, + decoration: InputDecoration( + helperText: "文件名不要有特殊字符:<>!:*?\\/.'\"", + 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.inputBorderColor, + width: 1, + ), + ), + ), + onSubmitted: (value) { + onSubmitted(context); + }, + )), + Positioned.directional( + textDirection: TextDirection.rtl, + start: 0, + child: ElevatedButton( + onPressed: () { + onSubmitted(context); + }, + child: Text(" 重命名 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + )), + ], + ), + ), + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/pagepan/RenameMutlDialog.dart b/alixby/lib/pagepan/RenameMutlDialog.dart new file mode 100644 index 0000000..8abcb92 --- /dev/null +++ b/alixby/lib/pagepan/RenameMutlDialog.dart @@ -0,0 +1,341 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:hovering/hovering.dart'; +import 'package:styled_text/styled_text.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class RenameMutlDialog extends StatefulWidget { + // ignore: non_constant_identifier_names + RenameMutlDialog({Key? key, required this.box, required this.filelist}) : super(key: key); + + String box = ""; + List filelist = []; + + @override + _RenameMutlDialogState createState() => _RenameMutlDialogState(); +} + +class _RenameMutlDialogState extends State { + @override + void initState() { + super.initState(); + oldcontroller.addListener(() { + ///获取输入的内容 + oldval = oldcontroller.text; + updatematch(); + setState(() {}); + }); + newcontroller.addListener(() { + ///获取输入的内容 + newval = newcontroller.text; + updatematch(); + setState(() {}); + }); + } + + void updatematch() { + if (oldval.endsWith("\\") && oldval.endsWith("\\\\") == false) oldval = "\\\\"; + + matchCount = 0; + for (var i = 0; i < widget.filelist.length; i++) { + var item = widget.filelist[i]; + var showname = item.title; + if (oldval == "" && newval != "") { + //头部插入 + showname = "" + newval + "" + showname; + } + if (oldval != "" && newval == "") { + //删除 + showname = showname.replaceFirstMapped(RegExp(r'' + oldval), (Match m) => '' + m[0]! + '', 0); + } + if (oldval != "" && newval != "") { + //替换 + showname = showname.replaceFirstMapped( + RegExp(r'' + oldval), (Match m) => '' + m[0]! + '' + newval + "", 0); + } + + if (showname != item.title) matchCount++; + } + } + + final ScrollController verticalScroll = ScrollController(); + final TextEditingController oldcontroller = TextEditingController(); + final TextEditingController newcontroller = TextEditingController(); + String oldval = ""; + String newval = ""; + int matchCount = 0; + @override + void dispose() { + verticalScroll.dispose(); + oldcontroller.dispose(); + newcontroller.dispose(); + super.dispose(); + } + + @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: 540, + width: 500, + 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("批量重命名文件/文件夹", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 440, + height: 370, + alignment: Alignment.topLeft, + decoration: BoxDecoration( + border: Border.all(width: 1, color: Colors.grey), borderRadius: BorderRadius.circular(3.0)), + padding: EdgeInsets.all(2), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: ListView.builder( + controller: verticalScroll, + shrinkWrap: false, + primary: false, + addSemanticIndexes: false, + addAutomaticKeepAlives: false, + addRepaintBoundaries: false, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + itemExtent: 42, + itemCount: widget.filelist.length, + itemBuilder: _buildList, + ))), + Container( + width: 440, + padding: EdgeInsets.only(top: 8), + child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + Expanded( + child: TextField( + controller: oldcontroller, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: false, + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 4, 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)), + Text("替换成"), + Padding(padding: EdgeInsets.only(left: 24)), + Expanded( + child: TextField( + controller: newcontroller, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: false, + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + )), + ]), + ), + Container( + width: 440, + padding: EdgeInsets.only(top: 8), + child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + Expanded( + child: Text("左边支持正则表达式替换\n左边不填则右边的变为前缀", + style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), + ), + Padding(padding: EdgeInsets.only(left: 24)), + Text("命中 " + matchCount.toString() + " 个", + style: TextStyle(fontSize: 12, color: Colors.redAccent, fontFamily: "opposans")), + Padding(padding: EdgeInsets.only(left: 24)), + OutlinedButton( + onPressed: () => Navigator.of(context).pop('ok'), + child: Text("取消"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + Padding(padding: EdgeInsets.only(left: 24)), + ElevatedButton( + onPressed: () { + List keyList = []; + List nameList = []; + for (var i = 0; i < widget.filelist.length; i++) { + var item = widget.filelist[i]; + var showname = item.title; + if (oldval == "" && newval != "") { + //头部插入 + showname = newval + showname; + } + if (oldval != "" && newval == "") { + //删除 + showname = showname.replaceFirstMapped(RegExp(r'' + oldval), (Match m) => '', 0); + } + if (oldval != "" && newval != "") { + //替换 + showname = showname.replaceFirstMapped(RegExp(r'' + oldval), (Match m) => newval, 0); + } + + if (showname != item.title) { + keyList.add(item.key); + nameList.add(showname); + } + } + + if (keyList.length == 0) { + BotToast.showText(text: "没有需要重命名的文件"); + return; + } + var fcHide = Loading.showLoading(); + + AliFile.apiRenameBatch(widget.box, keyList, nameList).then((value) { + fcHide(); + if (value > 0) { + Navigator.of(context).pop('ok'); + Future.delayed(Duration(milliseconds: 200), () { + Global.getTreeState(widget.box).pageRefreshNode(); + }); + BotToast.showText(text: "成功重命名 " + value.toString() + " 个文件"); + } else { + BotToast.showText(text: "批量重命名失败,请重试"); + } + }); + }, + child: Text("重命名"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ]), + ), + ], + ), + )), + ))); + } + + var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); + var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); + var padding = EdgeInsets.only(left: 3, right: 3); + var padding2 = Padding(padding: EdgeInsets.only(left: 4)); + var icondir = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); + var iconfile = Icon(MIcons.file_file, size: 20, color: MColors.iconFile); + var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor, fontFamily: "opposans"); + + Widget _buildList(BuildContext context, int index) { + var item = widget.filelist[index]; + var showname = item.title; + if (oldval == "" && newval != "") { + //头部插入 + showname = "" + newval + "" + showname; + } + if (oldval != "" && newval == "") { + //删除 + showname = showname.replaceFirstMapped(RegExp(r'' + oldval), (Match m) => '' + m[0]! + '', 0); + } + if (oldval != "" && newval != "") { + //替换 + showname = showname.replaceFirstMapped( + RegExp(r'' + oldval), (Match m) => '' + m[0]! + '' + newval + "", 0); + } + return HoverContainer( + //key: Key("prd_h_" + item.key), + cursor: SystemMouseCursors.basic, + height: 42, + margin: EdgeInsets.only(top: 4), + padding: EdgeInsets.only(right: 16), + decoration: decoration, + hoverDecoration: hoverDecoration, + child: Container( + height: 42, + child: Row( + children: [ + item.isDir ? icondir : iconfile, + padding2, + Expanded( + child: Tooltip( + message: item.title, + child: StyledText( + softWrap: false, + overflow: TextOverflow.ellipsis, + maxLines: 2, + text: showname, + tags: { + 'd': StyledTextTag( + style: TextStyle( + backgroundColor: Color(0xeeffebee), + color: Colors.red, + decorationStyle: TextDecorationStyle.solid, + decoration: TextDecoration.lineThrough, + fontFamily: "opposans")), + 'a': StyledTextTag( + style: TextStyle( + color: Colors.green, backgroundColor: Color(0xeee8f5e9), fontFamily: "opposans")), + }, + ))), + ], + ))); + } +} diff --git a/alixby/lib/pagepan/SaveMiaoChuan115Dialog.dart b/alixby/lib/pagepan/SaveMiaoChuan115Dialog.dart new file mode 100644 index 0000000..872bde0 --- /dev/null +++ b/alixby/lib/pagepan/SaveMiaoChuan115Dialog.dart @@ -0,0 +1,257 @@ +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: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 SaveMiaoChuan115Dialog extends StatefulWidget { + SaveMiaoChuan115Dialog({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 + _SaveMiaoChuan115DialogState createState() => _SaveMiaoChuan115DialogState(); +} + +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(); + } + + bool isPublic = false; + @override + void initState() { + super.initState(); + Clipboard.getData("text/plain").then((value) { + if (value != null) { + var text = value.text; + if (text != null) { + if (text.indexOf("aliyunpan://") > 0 || text.indexOf("115://") >= 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: 500, + width: 500, + 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("导入秒传链接", + 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: "多条115://秒传链接 ", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "115://文件名.mp4|大小|sha1|hash|", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + TextSpan( + text: "\n多条aliyunpan://秒传链接 ", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "aliyunpan://文件名.mp4|sha1|大小|", + 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: 156, minWidth: double.infinity), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: TextField( + controller: linkcontroller, + scrollController: verticalScroll, + maxLines: 10, + 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.center, + children: [ + Container( + width: 200 * double.parse(context.watch().setting.textScale), + padding: EdgeInsets.only(right: 8), + alignment: Alignment.topLeft, + child: CheckboxListTile( + tristate: true, + dense: true, + tileColor: Colors.transparent, + contentPadding: EdgeInsets.all(0), + selectedTileColor: Colors.transparent, + checkColor: Colors.white, + activeColor: MColors.inputBorderHover, + title: Text( + '发布到聚合搜索?(默认否)', + style: TextStyle( + fontSize: 13, + color: isPublic ? MColors.inputBorderHover : MColors.textColor, + fontFamily: "opposans"), + ), + value: (isPublic ? true : null), + selected: isPublic, + onChanged: (bool? value) { + isPublic = !isPublic; + setState(() {}); + }, + )), + Expanded(child: Container()), + ElevatedButton( + onPressed: () { + String link = linkcontroller.text; + String pwd = pwdcontroller.text; + var fcHide = Loading.showLoading(); + + Linker.goLinkParse(link, pwd, isPublic).then((value) { + fcHide(); + 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); + } + }); + }, + child: Text(" 解析链接 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ], + ), + ); + } +} diff --git a/alixby/lib/pagepan/SaveMiaoChuanBackDialog.dart b/alixby/lib/pagepan/SaveMiaoChuanBackDialog.dart new file mode 100644 index 0000000..1d5d71c --- /dev/null +++ b/alixby/lib/pagepan/SaveMiaoChuanBackDialog.dart @@ -0,0 +1,207 @@ +import 'package:alixby/api/Linker.dart'; +import 'package:alixby/utils/Loading.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.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:hovering/hovering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class SaveMiaoChuanBackDialog extends StatefulWidget { + // ignore: non_constant_identifier_names + SaveMiaoChuanBackDialog( + {Key? key, required this.box, required this.boxname, required this.parentid, required this.link}) + : super(key: key); + + String box = ""; + String boxname = ""; + String parentid = ""; + + LinkFileModel link = LinkFileModel(); + + @override + _SaveMiaoChuanBackDialogState createState() => _SaveMiaoChuanBackDialogState(); +} + +class _SaveMiaoChuanBackDialogState extends State { + List list = []; + @override + void initState() { + super.initState(); + //创建树 + list.addAll(_addNodes(widget.link.children, 0)); + } + + List _addNodes(List list, int leve) { + List clist = []; + + for (int i = 0; i < list.length; i++) { + if (list[i].isdir) { + list[i].leve = leve; + clist.add(list[i]); + clist.addAll(_addNodes(list[i].children, leve + 1)); + } + } + for (int i = 0; i < list.length; i++) { + if (list[i].isdir == false) { + list[i].leve = leve; + clist.add(list[i]); + } + } + return clist; + } + + final ScrollController verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + @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: 540, + width: 500, + 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("导入秒传短链接---" + widget.boxname, + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 440, + height: 370, + alignment: Alignment.topLeft, + decoration: BoxDecoration( + border: Border.all(width: 1, color: Colors.grey), borderRadius: BorderRadius.circular(3.0)), + padding: EdgeInsets.all(2), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: ListView.builder( + controller: verticalScroll, + shrinkWrap: false, + primary: false, + addSemanticIndexes: false, + addAutomaticKeepAlives: false, + addRepaintBoundaries: false, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + itemExtent: 28, + itemCount: list.length, + itemBuilder: _buildList, + ))), + Container( + width: 440, + height: 54, + padding: EdgeInsets.only(top: 8), + child: Text("备注信息:" + widget.link.name)), + Container( + width: 440, + padding: EdgeInsets.only(top: 8), + child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + OutlinedButton( + onPressed: () => Navigator.of(context).pop('ok'), + child: Text("取消"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + Padding(padding: EdgeInsets.only(left: 24)), + ElevatedButton( + onPressed: () { + 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: "导入秒传任务失败,请重试"); + } + }); + } + }, + child: Text("导入这些文件"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ]), + ), + ], + ), + )), + ))); + } + + var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); + var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); + var padding = EdgeInsets.only(left: 3, right: 3); + var padding2 = Padding(padding: EdgeInsets.only(left: 4)); + var icondir = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); + var iconfile = Icon(MIcons.file_file, size: 20, color: MColors.iconFile); + var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor, fontFamily: "opposans"); + + static TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"); + Widget _buildList(BuildContext context, int index) { + var item = list[index]; + return HoverContainer( + //key: Key("prd_h_" + item.key), + cursor: SystemMouseCursors.basic, + height: 24, + margin: EdgeInsets.only(top: 4), + padding: EdgeInsets.only(right: 16), + decoration: decoration, + hoverDecoration: hoverDecoration, + child: Container( + height: 24, + child: Row( + children: [ + Container(width: (22 * item.leve).toDouble()), + item.isdir ? icondir : iconfile, + padding2, + Expanded( + child: Tooltip( + message: item.name, + child: Text(item.name, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 1)), + ), + Container( + width: 88, + alignment: Alignment.centerRight, + child: Text(item.isdir ? "" : filesize(item.size), style: textStyle, maxLines: 1)), + ], + ))); + } +} diff --git a/alixby/lib/pagepan/SaveMiaoChuanTxtDialog.dart b/alixby/lib/pagepan/SaveMiaoChuanTxtDialog.dart new file mode 100644 index 0000000..9360940 --- /dev/null +++ b/alixby/lib/pagepan/SaveMiaoChuanTxtDialog.dart @@ -0,0 +1,250 @@ +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: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 SaveMiaoChuanTxtDialog extends StatefulWidget { + SaveMiaoChuanTxtDialog({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 + _SaveMiaoChuanTxtDialogState createState() => _SaveMiaoChuanTxtDialogState(); +} + +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(); + } + + bool isPublic = false; + @override + void initState() { + super.initState(); + Clipboard.getData("text/plain").then((value) { + if (value != null) { + var text = value.text; + if (text != null) { + if (text.indexOf("\"DirList\"") > 0 && text.indexOf("FileList") > 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: 480, + width: 500, + 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("导入秒传文件(txt)", + 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: "请一定要把txt内的全部文字都复制完整,再粘贴到这里\n", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "举例:{\"DirList\":[],\"FileList\":[],\"Name\":\"\",\"Size\":0}", + style: TextStyle( + fontSize: 12, color: MColors.textColorRed, fontFamily: "opposans")), + ]))), + Padding(padding: EdgeInsets.only(top: 12)), + _buildCanShu(context), + ])), + ], + ), + )), + ))); + } + + Widget _buildLink(BuildContext context) { + return Container( + alignment: Alignment.topLeft, + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: 156, minWidth: double.infinity), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: TextField( + controller: linkcontroller, + scrollController: verticalScroll, + maxLines: 10, + 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.center, + children: [ + Container( + width: 200 * double.parse(context.watch().setting.textScale), + padding: EdgeInsets.only(right: 8), + alignment: Alignment.topLeft, + child: CheckboxListTile( + tristate: true, + dense: true, + tileColor: Colors.transparent, + contentPadding: EdgeInsets.all(0), + selectedTileColor: Colors.transparent, + checkColor: Colors.white, + activeColor: MColors.inputBorderHover, + title: Text( + '发布到聚合搜索?(默认否)', + style: TextStyle( + fontSize: 13, + color: isPublic ? MColors.inputBorderHover : MColors.textColor, + fontFamily: "opposans"), + ), + value: (isPublic ? true : null), + selected: isPublic, + onChanged: (bool? value) { + isPublic = !isPublic; + setState(() {}); + }, + )), + Expanded(child: Container()), + ElevatedButton( + onPressed: () { + String link = linkcontroller.text; + String pwd = pwdcontroller.text; + var fcHide = Loading.showLoading(); + + Linker.goLinkParse(link, pwd, isPublic).then((value) { + fcHide(); + 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); + } + }); + }, + child: Text(" 解析链接 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ], + ), + ); + } +} diff --git a/alixby/lib/pagepan/SaveMiaoChuanXbyDialog.dart b/alixby/lib/pagepan/SaveMiaoChuanXbyDialog.dart new file mode 100644 index 0000000..5c411cc --- /dev/null +++ b/alixby/lib/pagepan/SaveMiaoChuanXbyDialog.dart @@ -0,0 +1,269 @@ +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: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 SaveMiaoChuanXbyDialog extends StatefulWidget { + SaveMiaoChuanXbyDialog({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 + _SaveMiaoChuanXbyDialogState createState() => _SaveMiaoChuanXbyDialogState(); +} + +class _SaveMiaoChuanXbyDialogState 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(); + Clipboard.getData("text/plain").then((value) { + if (value != null) { + var text = value.text; + if (text != null) { + if (text.indexOf("密码:") > 0 && text.indexOf("xby") > 0) { + var pwd = text.substring(text.indexOf("密码:") + "密码:".length).trim(); + if (pwd.length == 4) { + pwdcontroller.text = pwd; + text = text.substring(0, text.indexOf("密码:")).trim(); + } + } + if (text.indexOf("xby") > 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: 500, + 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("导入xby秒传链接", + 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: "一条 xby秒传链接 ", + style: TextStyle(color: MColors.textColor, fontFamily: "opposans")), + TextSpan( + text: "https://xby.writeas.com/?t=XXXXXXXX", + 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: 4, 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)), + ElevatedButton( + onPressed: () { + String link = linkcontroller.text; + String pwd = pwdcontroller.text; + var fcHide = Loading.showLoading(); + + Linker.goLinkParse(link, pwd, isPublic).then((value) { + fcHide(); + 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); + } + }); + }, + child: Text(" 解析链接 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ], + ), + ); + } +} diff --git a/alixby/lib/pagepan/TextDialog.dart b/alixby/lib/pagepan/TextDialog.dart new file mode 100644 index 0000000..ac8a951 --- /dev/null +++ b/alixby/lib/pagepan/TextDialog.dart @@ -0,0 +1,109 @@ +import 'package:alixby/states/Global.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.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 TextDialog extends StatelessWidget { + TextDialog({Key? key, required this.box, required this.text}) : super(key: key) { + controller.text = text; + } + String box = ""; + String text = ""; + final verticalScroll = ScrollController(); + final TextEditingController controller = TextEditingController(); + + @override + Widget build(BuildContext context) { + var size = MediaQuery.of(context).size; + var imagew = size.width * 0.8 - 40; + var imageh = size.height * 0.9 - 120; + 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: size.height * 0.9, + width: size.width * 0.8, + 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("小文本预览(最多显示前100kb)", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: imagew, + height: imageh, + alignment: Alignment.topLeft, + child: TextField( + controller: controller, + scrollController: verticalScroll, + maxLines: 48, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: false, + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 8, horizontal: 2), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + )), + Container( + width: imagew, + margin: EdgeInsets.only(top: 16), + alignment: Alignment.topRight, + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: 31), + child: ElevatedButton( + child: Text(" 复制全部文字 "), + onPressed: () { + Clipboard.setData(ClipboardData(text: controller.text)); + Global.getFileState(box).pageSelectFile(""); + BotToast.showText(text: "复制成功"); + }, + )), + ) + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/pagepan/UnrarBackDialog.dart b/alixby/lib/pagepan/UnrarBackDialog.dart new file mode 100644 index 0000000..7b5693e --- /dev/null +++ b/alixby/lib/pagepan/UnrarBackDialog.dart @@ -0,0 +1,70 @@ +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class UnrarBackDialog extends StatelessWidget { + UnrarBackDialog({Key? key, required this.state}) : super(key: key); + String state = ""; + @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: 280, + width: 460, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.white, + ), + 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("成功调用解压缩命令", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 420, + padding: EdgeInsets.only(top: 20), + child: Text("操作成功并且而收到了正确的返回值[" + + state + + "]\n\n解压缩可能会耗时较久,请稍后到选择的文件夹里查看解压结果!\n\n对于有密码的压缩包如果输入的密码错误会解压失败!当前失败后无任何提示,后面的版本会增加解压进度刷新"), + ), + Container( + width: 420, + margin: EdgeInsets.only(top: 24), + alignment: Alignment.centerRight, + child: OutlinedButton( + onPressed: () => Navigator.of(context).pop('ok'), + child: Text(" 关闭 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ) + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/pagepan/UnrarDialog.dart b/alixby/lib/pagepan/UnrarDialog.dart new file mode 100644 index 0000000..9993c99 --- /dev/null +++ b/alixby/lib/pagepan/UnrarDialog.dart @@ -0,0 +1,372 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_treeview/flutter_treeview.dart'; +import 'package:hovering/hovering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class UnrarDialog extends StatefulWidget { + // ignore: non_constant_identifier_names + UnrarDialog({Key? key, required this.box, required this.fileid}) : super(key: key) { + if (box == 'box') + boxname = "网盘"; + else if (box == 'sbox') + boxname = "保险箱"; + else if (box == 'xiangce') boxname = "相册"; + } + // ignore: non_constant_identifier_names + String box = ""; + String boxname = ""; + String fileid = ""; + + @override + _UnrarDialogState createState() => _UnrarDialogState(); +} + +class _UnrarDialogState extends State { + @override + void initState() { + super.initState(); + treeController = TreeViewController(children: [_makeNode("", "root", widget.boxname + "根目录", 0, [])]); + pageExpandedNode("root", true); + } + + static Node _makeNode(String parentkey, String key, String label, int leve, List children) { + var dir = DirNode2(parentkey, key, label, leve); + return Node(label: dir.label, key: dir.key, parent: true, data: dir, children: children); + } + + final ScrollController verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + TreeViewController treeController = TreeViewController(); + String selectKey = ""; + Map loading = {}; + + final TextEditingController controller = TextEditingController(); + + void onSubmitted(BuildContext context) {} + @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: 500, + width: 500, + 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("在线解压缩", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 440, + height: 370, + alignment: Alignment.topLeft, + decoration: BoxDecoration( + border: Border.all(width: 1, color: Colors.grey), borderRadius: BorderRadius.circular(3.0)), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + hoverThickness: 9, + thickness: 9, + showTrackOnHover: true, + child: SingleChildScrollView( + controller: verticalScroll, + scrollDirection: Axis.vertical, + physics: BouncingScrollPhysics(), + child: Container( + alignment: Alignment.topLeft, + padding: EdgeInsets.only(bottom: 12), + child: TreeView( + shrinkWrap: true, + primary: true, + controller: treeController, + physics: BouncingScrollPhysics(), + allowParentSelect: true, + supportParentDoubleTap: true, + onExpansionChanged: _expandNodeHandler, + onNodeTap: _onNodeTap, + nodeBuilder: _builderTreeNode, + theme: TreeViewTheme( + expanderTheme: ExpanderThemeData( + type: ExpanderType.caret, + modifier: ExpanderModifier.none, + position: ExpanderPosition.start, + color: MColors.userNavColor, + size: 20, + ), + labelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), + parentLabelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), + iconTheme: IconThemeData(size: 18, color: MColors.pageLeftRowItemIconColor), + colorScheme: ColorScheme.light().copyWith(primary: Colors.transparent), + expandSpeed: Duration(milliseconds: 100), + ), + )), + ))), + Container( + width: 440, + padding: EdgeInsets.only(top: 12), + child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + Expanded( + child: TextField( + controller: controller, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: false, + decoration: InputDecoration( + hintText: "解压密码。没有不填", + hintStyle: TextStyle(fontSize: 13, color: MColors.textColorGray, fontFamily: "opposans"), + contentPadding: EdgeInsets.symmetric(vertical: 4, 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)), + OutlinedButton( + onPressed: () => Navigator.of(context).pop('ok'), + child: Text("取消"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + Padding(padding: EdgeInsets.only(left: 24)), + ElevatedButton( + onPressed: () { + var password = controller.text; + var fcHide = Loading.showLoading(); + AliFile.apiUncompress(widget.box, widget.fileid, selectKey, password).then((value) { + fcHide(); + if (value.length == 1) { + BotToast.showText(text: "失败:" + value[0]); + return; + } + pageExpandedNode("root", true); + Navigator.of(context).pop('ok'); + + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: UnrarBackDialog(state: value[0])); + }); + }); + }, + child: Text("解压缩到选中的文件夹内"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ]), + ), + ], + ), + )), + ))); + } + + _updateTree(TreeViewController tree) { + treeController = tree; + if (mounted) { + setState(() {}); + } + } + + //页面调用,点击文件树的一个文件夹时触发 + pageExpandedNode(String key, bool expanded) { + Node? node = treeController.getNode(key); + if (node != null) { + selectKey = key; + //选中并展开 + Node node2 = node.copyWith(expanded: expanded); + List updated = treeController.updateNode(key, node2); + _updateTree(treeController.copyWith(children: updated, selectedKey: key)); + + if (expanded == true) { + if (!loading.containsKey(key) || loading[key] == false) { + loading[key] = true; + //是文件夹&&children子文件数==0&&要展开显示了 + //注意node.parent,当联网后发现是空文件夹,node.parent会变成false + + AliFile.apiDirList(widget.box, key, node.label).then((loadData) { + if (loadData.key == "error") return; + var leve = node.data.leve + 1; + //动态新增 + List children = []; + var total = loadData.list.length; + for (int i = 0; i < total; i++) { + var m = loadData.list[i]; + if (m.isDir) children.add(_makeNode(m.parentkey, m.key, m.name, leve, [])); + } + Node node2 = node.copyWith(expanded: true, parent: true, children: children); //注意这里更新了parent + //更新并展开 + List updated = treeController.updateNode(key, node2); + _updateTree(treeController.copyWith(children: updated, selectedKey: selectKey)); + loading[key] = false; + }); + } + } + } + } + + pageSelectNode(String key) { + Node? node = treeController.getNode(key); + if (node != null) { + pageExpandedNode(node.key, !node.expanded); + } + } + + _expandNodeHandler(String key, bool expanded) { + pageExpandedNode(key, expanded); + } + + _onNodeTap(String key) { + pageSelectNode(key); + } + + Widget _builderTreeNode(BuildContext context, Node node) { + DirNode2? dir = node.data; + if (dir != null) { + return selectKey == node.key ? dir.widgetSelect : dir.widget; + } else { + return Container(); + } + } +} + +class DirNode2 { + DirNode2(this.parentkey, this.key, this.label, this.leve) { + widget = Container( + key: Key("pdt_unrar_rc_" + key), + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(top: 2, bottom: 2), + child: UnconstrainedBox( + alignment: Alignment.centerLeft, + child: HoverContainer( + key: Key("pdt_unrar_rch_" + key), + cursor: SystemMouseCursors.click, + height: 24, + decoration: decoration, + hoverDecoration: hoverDecoration, + child: Container( + key: Key("pdt_unrar_rchc_" + key), + width: 400 - leve * 20, + height: 24, + padding: padding, + child: Row(key: Key("pdt_unrar_rchcr_" + key), children: [ + icon, + padding2, + Expanded( + child: Text( + label, + key: Key("pdt_unrar_rchcrt_" + key), + style: style, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + )) + ]))))); + + widgetSelect = Container( + key: Key("pdt_unrar_rc_" + key), + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(top: 2, bottom: 2), + child: UnconstrainedBox( + alignment: Alignment.centerLeft, + child: HoverContainer( + key: Key("pdt_unrar_rch_" + key), + cursor: SystemMouseCursors.click, + height: 24, + decoration: decorations, + hoverDecoration: hoverDecorations, + child: Container( + key: Key("pdt_unrar_rchc_" + key), + width: 400 - leve * 20, + height: 24, + padding: padding, + child: Row(key: Key("pdt_unrar_rchcr_" + key), children: [ + icons, + padding2, + Expanded( + child: Text( + label, + key: Key("pdt_unrar_rchcrt_" + key), + style: styles, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + )) + ]))))); + } + + String label = ""; + String key = ""; + //父文件夹key + String parentkey = ""; + //文件夹层级 + int leve = 0; + + Widget widget = Container(); + Widget widgetSelect = Container(); + + var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); + var decorations = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); + + var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); + var hoverDecorations = + BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); + + var padding = EdgeInsets.only(left: 3, right: 3); + var padding2 = Padding(padding: EdgeInsets.only(left: 8)); + var icon = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); + var icons = Icon(MIcons.folder, size: 20, color: MColors.userNavMenuIconHover); + var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor, fontFamily: "opposans"); + var styles = TextStyle(fontSize: 14, color: MColors.userNavMenuIconHover, fontFamily: "opposans"); +} diff --git a/alixby/lib/views/PageLeftRss.dart b/alixby/lib/pagerss/PageLeftRss.dart similarity index 92% rename from alixby/lib/views/PageLeftRss.dart rename to alixby/lib/pagerss/PageLeftRss.dart index d378a81..56cf1be 100644 --- a/alixby/lib/views/PageLeftRss.dart +++ b/alixby/lib/pagerss/PageLeftRss.dart @@ -1,11 +1,11 @@ import 'package:alixby/states/Global.dart'; -import '../utils/MIcons.dart'; +import 'package:alixby/utils/MIcons.dart'; -import '../utils/MColors.dart'; +import 'package:alixby/utils/MColors.dart'; import 'package:hovering/hovering.dart'; -import '../models/PageLeftRowItem.dart'; +import 'package:alixby/models/PageLeftRowItem.dart'; import 'package:flutter/material.dart'; class PageLeftRss extends StatefulWidget { @@ -38,7 +38,6 @@ class _PageLeftRssState extends State with AutomaticKeepAliveClient @override void initState() { super.initState(); - print('_PageLeftRssState initState'); } @override @@ -56,7 +55,7 @@ class _PageLeftRssState extends State with AutomaticKeepAliveClient alignment: Alignment.centerLeft, child: Text( "Rss订阅资源", - style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor), + style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor, fontFamily: "opposans"), )), Expanded( child: ListView.builder( @@ -94,7 +93,8 @@ class _PageLeftRssState extends State with AutomaticKeepAliveClient item.title, style: TextStyle( color: - selectedKey == item.key ? MColors.userNavMenuIconHover : MColors.pageLeftRowItemColor), + selectedKey == item.key ? MColors.userNavMenuIconHover : MColors.pageLeftRowItemColor, + fontFamily: "opposans"), ) ])))), ); diff --git a/alixby/lib/views/PageRightRss.dart b/alixby/lib/pagerss/PageRightRss.dart similarity index 87% rename from alixby/lib/views/PageRightRss.dart rename to alixby/lib/pagerss/PageRightRss.dart index 8a34c46..4ff02f9 100644 --- a/alixby/lib/views/PageRightRss.dart +++ b/alixby/lib/pagerss/PageRightRss.dart @@ -1,8 +1,8 @@ import 'package:alixby/states/UserState.dart'; import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/views/PageRightRssLiXian.dart'; -import 'package:alixby/views/PageRightRssMiaoChuan.dart'; -import 'package:alixby/views/PageRightRssSearch.dart'; +import 'package:alixby/pagerss/PageRightRssLiXian.dart'; +import 'package:alixby/pagerss/PageRightRssMiaoChuan.dart'; +import 'package:alixby/pagerss/PageRightRssSearch.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -17,7 +17,6 @@ class _PageRightRssState extends State with AutomaticKeepAliveClie @override void initState() { super.initState(); - print('_PageRightRssState initState'); } final PageController _pageController = PageController(initialPage: 0, keepPage: true); diff --git a/alixby/lib/pagerss/PageRightRssHelp.dart b/alixby/lib/pagerss/PageRightRssHelp.dart new file mode 100644 index 0000000..cee97e9 --- /dev/null +++ b/alixby/lib/pagerss/PageRightRssHelp.dart @@ -0,0 +1,248 @@ +import 'package:alixby/utils/FileLinkifier.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_linkify/flutter_linkify.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class PageRightRssHelp extends StatefulWidget { + @override + _PageRightRssHelpState createState() => _PageRightRssHelpState(); +} + +class _PageRightRssHelpState extends State { + @override + void initState() { + super.initState(); + } + + final verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + @override + // 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); + return Column(children: [ + Container( + height: 52, + width: double.infinity, + alignment: Alignment.centerLeft, + child: RichText( + textAlign: TextAlign.left, + text: WidgetSpan( + child: Linkify( + onOpen: null, + text: "操作帮助", + linkifiers: [FileLinkifier("操作帮助", "", "")], + linkStyle: TextStyle( + fontSize: 13, + color: MColors.linkColor, + decoration: TextDecoration.none, + fontFamily: "opposans"))))), + Container(height: 1, width: double.infinity, color: MColors.pageRightBorderColor), + Expanded( + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: SingleChildScrollView( + controller: verticalScroll, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + child: Container( + alignment: Alignment.topLeft, + padding: EdgeInsets.only(left: 8, right: 100), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷使用中遇到XX问题,发现XXBUG,希望有XX功能", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Linkify( + onOpen: (link) { + launch(Uri.encodeFull(link.url)); + }, + text: "github", + linkifiers: [ + FileLinkifier("https://github.com/liupan1890/aliyunpan", + "https://github.com/liupan1890/aliyunpan/issues", "") + ], + linkStyle: TextStyle( + fontSize: 14, + color: MColors.linkColor, + decoration: TextDecoration.none, + fontFamily: "opposans"))), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷关闭后还能继续下载吗?怎么彻底退出?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:当你点击X号关闭,只是关闭了窗口,程序在后台继续运行(继续下载/上传)。此时鼠标右键点击桌面右下角任务栏里的托盘小图标,会显示 [显示主界面] 和 [彻底退出] 按钮,点击彻底退出按钮,才是真的关闭程序", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷不能选择多个文件后批量操作吗?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:当然可以,支持配合Ctrl键、Shift键,实现自由选中多个文件,\n跟win10文件管理器里选择多个文件的操作是一样的\n按住Ctrl键,再点击1个文件就是多选,还可以取消选中这个文件\n先点击一个文件,按住Shift键,再点击1个文件,会自动选中之间的全部文件", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷可以一次下载整个文件夹吗?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:当然可以,选择一个文件夹,点击下载按钮即可!还可以一次选择多个文件夹+文件,点击下载按钮批量下载!没有文件数量的限制!下载文件时也支持断点续传,可以随时暂停恢复继续下载", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷可以指定把文件下载到哪里吗?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:当然可以,在设置里勾选 [ 每次下载都让我选择下载位置 ] 后,就可以选择把文件下载到哪里了,默认是按照阿里云盘的完整路径保存的,勾选后就会去掉阿里云盘的完整路径直接保存到你选择的文件夹里", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷可以一次上传整个文件夹吗?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:当然可以,点击上传,选择上传文件夹,选择一个你电脑上的文件夹就可以了,会自动上传这个文件夹下面的所有文件和所有子文件夹!没有上传数量的限制!但阿里云盘限制单个文件最大30GB!上传文件时支持秒传,支持断点续传,可以随时暂停恢复继续上传!\nWindow系统用户还支持直接拖拽一堆文件扔到窗口上自动上传", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷不能导入115分享链接?百度分享链接?磁力链接?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:当然都 不可以,但是可以导入115秒传链接(115://........)和阿里云盘秒传链接(aliyunpan://........)", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷聚合搜索是什么?搜不到想要的文件?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:所有用户导入115秒传链接时,可以主动勾选分享,分享的链接可以在聚合搜索中给其他人搜索到,方便其他人!因为搜索刚刚上线所以搜索结果很少,等以后自然就多了", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷支持在线预览哪些文件?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:支持预览所有的音视频格式(支持音轨、字幕、倍速快放、倍速慢放、音量/对比度/亮度调整等等,具体操作请百度 “ mpv播放器 ” ),还支持在线预览图片和txt", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷运行后提示更新,怎么升级版本呢?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:去github下载最新版本的压缩包,直接解压缩替换旧版本文件即可。所有用户数据都存放在 旧版\\data\\user.db 这个文件里,只要最终保留user.db这个文件就好了!甚至还可以直接复制这个文件到新版解压位置后删除旧版文件夹", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷可以更换自己喜欢的字体吗?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:当然可以!将[data\\flutter_assets\\assets\\fonts\\OPPOSans-R.ttf]这个文件替换成你自己的ttf字体文件就可以了。就是这么简单", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷相册和网盘有什么区别?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:功能上并没有区别,相册内文件同样占用网盘的总空间。但相册在官网只能显示图片和视频,所以虽然可以把网盘里的任意文件 复制/移动 到相册,但并不推荐这样做,请遵守官方的规则只往相册里存放图片和视频。", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷不想用了怎么卸载?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:小白羊是绿色软件,直接删除小白羊所在的文件夹就可以了,没有任何安装残留!", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + Container( + child: Text("Q∷会泄露我的隐私吗?", style: styleQ), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + child: Text( + "答:小白羊是开源软件,除了提交秒传链接和聚合搜索,小白羊并没有其他上传数据的操作!你的所有数据也都只存放在阿里云盘里,我们很注意保护你的隐私!", + style: stylegray, + softWrap: true, + ), + ), + Padding(padding: EdgeInsets.only(top: 32)), + ]))))) + ]); + } +} diff --git a/alixby/lib/views/PageRightRssLiXian.dart b/alixby/lib/pagerss/PageRightRssLiXian.dart similarity index 86% rename from alixby/lib/views/PageRightRssLiXian.dart rename to alixby/lib/pagerss/PageRightRssLiXian.dart index 109ddc7..102772e 100644 --- a/alixby/lib/views/PageRightRssLiXian.dart +++ b/alixby/lib/pagerss/PageRightRssLiXian.dart @@ -13,7 +13,6 @@ class _PageRightRssLiXianState extends State { @override void initState() { super.initState(); - print('_PageRightRssLiXianState initState'); } @override @@ -36,9 +35,10 @@ class _PageRightRssLiXianState extends State { text: "aliyundrive.com", linkifiers: [ FileLinkifier( - "https://github.com/liupan1890/aliyunpan", "https://github.com/liupan1890/aliyunpan/issues") + "https://github.com/liupan1890/aliyunpan", "https://github.com/liupan1890/aliyunpan/issues", "") ], - linkStyle: TextStyle(fontSize: 14, color: MColors.linkColor, decoration: TextDecoration.none)) + linkStyle: TextStyle( + fontSize: 14, color: MColors.linkColor, decoration: TextDecoration.none, fontFamily: "opposans")) ])); } } diff --git a/alixby/lib/views/PageRightRssMiaoChuan.dart b/alixby/lib/pagerss/PageRightRssMiaoChuan.dart similarity index 77% rename from alixby/lib/views/PageRightRssMiaoChuan.dart rename to alixby/lib/pagerss/PageRightRssMiaoChuan.dart index dcc434f..522c33e 100644 --- a/alixby/lib/views/PageRightRssMiaoChuan.dart +++ b/alixby/lib/pagerss/PageRightRssMiaoChuan.dart @@ -21,7 +21,6 @@ class _PageRightRssMiaoChuanState extends State { @override void initState() { super.initState(); - print('_PageRightRssMiaoChuanState initState'); } @override @@ -35,6 +34,7 @@ class _PageRightRssMiaoChuanState extends State { @override // ignore: must_call_super Widget build(BuildContext context) { + var itemCount = context.watch().pageRightMiaoChuanList.length; return Column( key: mcKey, children: [ @@ -48,9 +48,12 @@ class _PageRightRssMiaoChuanState extends State { child: Linkify( onOpen: null, text: "秒传记录", - linkifiers: [FileLinkifier("秒传记录", "")], - linkStyle: - TextStyle(fontSize: 13, color: MColors.linkColor, decoration: TextDecoration.none))))), + linkifiers: [FileLinkifier("秒传记录", "", "")], + linkStyle: TextStyle( + fontSize: 13, + color: MColors.linkColor, + decoration: TextDecoration.none, + fontFamily: "opposans"))))), Container( height: 34, width: double.infinity, @@ -76,35 +79,29 @@ class _PageRightRssMiaoChuanState extends State { ])), Expanded( child: Container( - width: double.infinity, - decoration: - BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), - alignment: Alignment.topLeft, - child: Scrollbar( - controller: verticalScroll, - isAlwaysShown: true, - showTrackOnHover: true, - thickness: 9, - hoverThickness: 9, - child: Row( - children: [ - Expanded( - child: ListView.builder( - controller: verticalScroll, - shrinkWrap: false, - primary: false, - addSemanticIndexes: false, - addAutomaticKeepAlives: false, - addRepaintBoundaries: false, - scrollDirection: Axis.vertical, - physics: ClampingScrollPhysics(), - itemExtent: 60, - itemCount: context.watch().pageRightMiaoChuanList.length, - itemBuilder: _buildList, - )), - Container(width: 16), - ], - )))), + width: double.infinity, + decoration: BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), + alignment: Alignment.topLeft, + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: ListView.builder( + controller: verticalScroll, + shrinkWrap: false, + primary: false, + addSemanticIndexes: false, + addAutomaticKeepAlives: false, + addRepaintBoundaries: false, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + itemExtent: 60, + itemCount: itemCount, + itemBuilder: _buildList, + )), + )), ], ); } @@ -134,7 +131,7 @@ class _PageRightRssMiaoChuanState extends State { Widget _buildList(BuildContext context, int index) { var item = Global.pageRssMiaoChuanState.pageRightMiaoChuanList[index]; - TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor); + TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"); SizedBox linkBox = SizedBox(width: 40, height: 40, child: Icon(MIcons.link2, color: MColors.iconDown)); SizedBox linkBoxed = SizedBox(width: 40, height: 40, child: Icon(MIcons.link2, color: MColors.iconSelected)); @@ -151,11 +148,10 @@ class _PageRightRssMiaoChuanState extends State { var hoverDecorations = BoxDecoration( color: MColors.pageRightFileBGSelect, border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); - //print("buildfile " + item.key); - //if (item.icon[0] == '.') item.icon = FileIcons.getFileIcon(item.icon, ""); return HoverContainer( //key: Key("prd_h_" + item.key), cursor: SystemMouseCursors.basic, + padding: EdgeInsets.only(right: 16), height: 60, decoration: item.selected ? decorations : decoration, hoverDecoration: item.selected ? hoverDecorations : hoverDecoration, @@ -175,9 +171,9 @@ class _PageRightRssMiaoChuanState extends State { ), ), Container( - width: 80, + width: 90, alignment: Alignment.centerRight, - child: Text(item.logTimeStr, style: textStyle, maxLines: 2)), + child: Text(item.logTimeStr, textAlign: TextAlign.right, style: textStyle, maxLines: 2)), padding22, Container( height: 60, diff --git a/alixby/lib/pagerss/PageRightRssSearch.dart b/alixby/lib/pagerss/PageRightRssSearch.dart new file mode 100644 index 0000000..332cf2f --- /dev/null +++ b/alixby/lib/pagerss/PageRightRssSearch.dart @@ -0,0 +1,250 @@ +import 'package:alixby/states/Global.dart'; +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:flutter/material.dart'; +import 'package:hovering/hovering.dart'; +import 'package:provider/provider.dart'; + +class PageRightRssSearch extends StatefulWidget { + @override + _PageRightRssSearchState createState() => _PageRightRssSearchState(); +} + +class _PageRightRssSearchState extends State { + @override + void initState() { + super.initState(); + Global.pageRssSearchState.searchcontroller.addListener(() { + print(Global.pageRssSearchState.searchcontroller.text); + }); + } + + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + final verticalScroll = ScrollController(); + @override + // ignore: must_call_super + Widget build(BuildContext context) { + var pageRightFileSelectedDes = context.watch().pageRightFileSelectedDes; + var itemCount = context.watch().pageRightSearchList.length; + return Column( + children: [ + Container( + height: 52, + width: double.infinity, + alignment: Alignment.center, + child: Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 60, maxWidth: 275), + child: TextField( + controller: Global.pageRssSearchState.searchcontroller, + onSubmitted: (val) { + Global.pageRssSearchState.pageSearch(1); + }, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + autofocus: false, + decoration: InputDecoration( + hintText: "搜索文件转存", + hintStyle: TextStyle(fontSize: 13, color: MColors.textColorGray, fontFamily: "opposans"), + contentPadding: EdgeInsets.symmetric(vertical: 2, horizontal: 8), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderHover, + width: 1, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: MColors.inputBorderColor, + width: 1, + ), + ), + ), + )), + Positioned.directional( + textDirection: TextDirection.rtl, + start: 0, + child: ElevatedButton( + onPressed: () { + Global.pageRssSearchState.pageSearch(1); + }, + child: Text(" 搜索 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + )), + ], + ), + ), + Container( + height: 34, + width: double.infinity, + child: Row( + children: [ + Container( + width: 166, + child: Row(children: [ + OutlinedButton.icon( + icon: Icon(MIcons.chuanshu, size: 16), + label: Text('转存选中项'), + onPressed: () { + var filelist = Global.pageRssSearchState.getSelectedFiles(); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: ZhuanCunDialog(filelist: filelist)); + }); + }), + Expanded(child: Container()), + ])), + Expanded(child: context.watch().navBtns), + ], + )), + Container(height: 1, width: double.infinity, color: MColors.pageRightBorderColor), + Container( + height: 40, + alignment: Alignment.topLeft, + width: double.infinity, + child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ + UnconstrainedBox( + child: Container( + width: 40, + height: 40, + child: HoverContainer( + decoration: + BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG), + hoverDecoration: + BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.userNavMenuBG), + child: IconButton( + iconSize: 24, + padding: EdgeInsets.all(0), + color: Color(0xff637dff), + icon: Icon(MIcons.rsuccess), + onPressed: () { + Global.pageRssSearchState.pageSelectFile("all"); + }, + tooltip: '全选', + )))), + Padding(padding: EdgeInsets.only(left: 8)), + Text("115秒传文件"), + Padding(padding: EdgeInsets.only(left: 8)), + Text(pageRightFileSelectedDes), + Expanded(child: Container()), + Container(child: Text("操作")), + Padding(padding: EdgeInsets.only(left: 100)), + ])), + Expanded( + child: Container( + width: double.infinity, + decoration: BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), + alignment: Alignment.topLeft, + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + showTrackOnHover: true, + thickness: 9, + hoverThickness: 9, + child: ListView.builder( + controller: verticalScroll, + shrinkWrap: false, + primary: false, + addSemanticIndexes: false, + addAutomaticKeepAlives: false, + addRepaintBoundaries: false, + scrollDirection: Axis.vertical, + physics: ClampingScrollPhysics(), + itemExtent: 50, + itemCount: itemCount, + itemBuilder: _buildList, + )), + )), + ], + ); + } + + static onTapFile(String key) { + Global.pageRssSearchState.pageSelectFile(key); + } + + static Icon iconSelected = Icon(MIcons.rsuccess, color: MColors.iconSelected); + static Icon iconSelect = Icon(MIcons.rpic, color: MColors.iconSelect); + static Padding padding6 = Padding(padding: EdgeInsets.only(left: 6)); + static Padding padding4 = Padding(padding: EdgeInsets.only(left: 4)); + static Padding padding12 = Padding(padding: EdgeInsets.only(left: 12)); + static TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"); + static SizedBox sizeBox = SizedBox(width: 40, height: 40, child: iconSelect); + static SizedBox sizeBoxed = SizedBox(width: 40, height: 40, child: iconSelected); + + Widget _buildList(BuildContext context, int index) { + var item = Global.pageRssSearchState.pageRightSearchList[index]; + var decoration = BoxDecoration( + color: MColors.pageRightFileBG, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + var decorations = BoxDecoration( + color: MColors.pageRightFileBGSelect, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + + var hoverDecoration = BoxDecoration( + color: MColors.pageRightFileBGHover, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + var hoverDecorations = BoxDecoration( + color: MColors.pageRightFileBGSelect, + border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); + return HoverContainer( + key: Key("prs_h_" + item.key), + cursor: SystemMouseCursors.basic, + padding: EdgeInsets.only(right: 16), + height: 50, + decoration: item.selected ? decorations : decoration, + hoverDecoration: item.selected ? hoverDecorations : hoverDecoration, + child: Container( + key: Key("prs_hc_" + item.key), + height: 50, + child: InkWell( + mouseCursor: SystemMouseCursors.basic, + onTap: () => onTapFile(item.key), + child: Row( + key: Key("prs_hcr_" + item.key), + children: [ + item.selected ? sizeBoxed : sizeBox, + padding6, + item.icon, + padding4, + Expanded( + child: Row(children: [ + Flexible( + flex: 1, + fit: FlexFit.loose, + child: Container( + key: Key("prs_hcr_n_" + item.key), + child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2))) + ])), + Container( + key: Key("prs_hcr_s_" + item.key), + width: 88, + alignment: Alignment.centerRight, + child: Text(item.filesizestr, style: textStyle, maxLines: 1, softWrap: false)), + padding12, + Container( + key: Key("prs_hcr_t_" + item.key), + width: 44, + alignment: Alignment.centerRight, + child: Text(item.filetimestr, style: textStyle, textAlign: TextAlign.center, maxLines: 2), + ), + padding12, + ], + )))); + } +} diff --git a/alixby/lib/pagerss/ZhuanCunDialog.dart b/alixby/lib/pagerss/ZhuanCunDialog.dart new file mode 100644 index 0000000..3479e50 --- /dev/null +++ b/alixby/lib/pagerss/ZhuanCunDialog.dart @@ -0,0 +1,396 @@ +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:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_treeview/flutter_treeview.dart'; +import 'package:hovering/hovering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +// ignore: must_be_immutable +class ZhuanCunDialog extends StatefulWidget { + // ignore: non_constant_identifier_names + ZhuanCunDialog({Key? key, required this.filelist}) : super(key: key); + String pagetitle = "转存"; + // ignore: non_constant_identifier_names + List filelist = []; + + @override + _ZhuanCunDialogState createState() => _ZhuanCunDialogState(); +} + +class _ZhuanCunDialogState extends State { + @override + void initState() { + super.initState(); + pageExpandedNode("root", true); + } + + String movetobox = "box"; + static Node _makeNode(String parentkey, String key, String label, int leve, List children) { + var dir = DirNode2(parentkey, key, label, leve); + return Node(label: dir.label, key: dir.key, parent: true, data: dir, children: children); + } + + final ScrollController verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } + + TreeViewController treeController = TreeViewController(children: [_makeNode("", "root", "网盘目录树", 0, [])]); + String selectKey = ""; + Map loading = {}; + @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: 500, + width: 500, + 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("转存文件", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 440, + height: 370, + alignment: Alignment.topLeft, + decoration: BoxDecoration( + border: Border.all(width: 1, color: Colors.grey), borderRadius: BorderRadius.circular(3.0)), + child: Scrollbar( + controller: verticalScroll, + isAlwaysShown: true, + hoverThickness: 9, + thickness: 9, + showTrackOnHover: true, + child: SingleChildScrollView( + controller: verticalScroll, + scrollDirection: Axis.vertical, + physics: BouncingScrollPhysics(), + child: Container( + alignment: Alignment.topLeft, + padding: EdgeInsets.only(bottom: 12, right: 16), + child: TreeView( + shrinkWrap: true, + primary: true, + controller: treeController, + physics: BouncingScrollPhysics(), + allowParentSelect: true, + supportParentDoubleTap: true, + onExpansionChanged: _expandNodeHandler, + onNodeTap: _onNodeTap, + nodeBuilder: _builderTreeNode, + theme: TreeViewTheme( + expanderTheme: ExpanderThemeData( + type: ExpanderType.caret, + modifier: ExpanderModifier.none, + position: ExpanderPosition.start, + color: MColors.userNavColor, + size: 20, + ), + labelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), + parentLabelStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.normal, fontFamily: "opposans"), + iconTheme: IconThemeData(size: 18, color: MColors.pageLeftRowItemIconColor), + colorScheme: ColorScheme.light().copyWith(primary: Colors.transparent), + expandSpeed: Duration(milliseconds: 100), + ), + )), + ))), + Container( + width: 440, + padding: EdgeInsets.only(top: 12), + child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + UnconstrainedBox( + child: Container( + height: 32, + padding: EdgeInsets.only(left: 7, right: 5), + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(3.0), //3像素圆角 + border: Border.all( + color: MColors.inputBorderColor, + width: 1.0, + ), + ), + child: DropdownButton( + isDense: true, + itemHeight: 32, //需要修改kMinInteractiveDimension =32 + elevation: 0, + value: movetobox, + underline: Container(height: 0), + dropdownColor: MColors.userNavMenuBG, + onChanged: (String? newValue) { + if (newValue != null) { + movetobox = newValue; + setState(() { + movetobox = newValue; + }); + pageExpandedNode("root", true); + } + }, + items: [ + DropdownMenuItem( + value: "box", + child: Text(widget.pagetitle + '到 网盘', + style: TextStyle( + fontSize: 14, color: MColors.textColor, fontFamily: "opposans"))), + DropdownMenuItem( + value: "xiangce", + child: Text(widget.pagetitle + '到 相册', + style: TextStyle( + fontSize: 14, color: MColors.textColor, fontFamily: "opposans"))), + ]))), + Expanded(child: Container()), + OutlinedButton( + onPressed: () => Navigator.of(context).pop('ok'), + child: Text("取消"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + Padding(padding: EdgeInsets.only(left: 24)), + ElevatedButton( + onPressed: () { + var linkstr = '{"DirList":[],"FileList":['; + int totalsize = 0; + bool isadd = false; + for (var i = 0; i < widget.filelist.length; i++) { + var item = widget.filelist[i]; + if (isadd == false) + isadd = true; + else + linkstr += ","; + + linkstr += '"' + + item.title.replaceAll("\"", "").replaceAll("|", "") + + '|' + + item.fileSize.toString() + + '|' + + item.filetype + + '"'; + totalsize += item.fileSize; + } + linkstr += '],"Name":"无","Size":' + totalsize.toString() + ',"Message":""}'; + var fcHide = Loading.showLoading(); + Linker.goLinkUpload(movetobox, selectKey, linkstr).then((value) { + fcHide(); + Future.delayed(Duration(milliseconds: 500), () { + PanData.loadFileList(movetobox, selectKey, "zhuancun"); //触发联网加载 + }); + + pageExpandedNode("root", true); + Navigator.of(context).pop('ok'); + BotToast.showText(text: "成功转存" + value.toString() + "个文件"); + }); + }, + child: Text("转存到选中的文件夹内"), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + ), + ]), + ), + ], + ), + )), + ))); + } + + _updateTree(TreeViewController tree) { + treeController = tree; + if (mounted) { + setState(() {}); + } + } + + //页面调用,点击文件树的一个文件夹时触发 + pageExpandedNode(String key, bool expanded) { + Node? node = treeController.getNode(key); + if (node != null) { + selectKey = key; + //选中并展开 + Node node2 = node.copyWith(expanded: expanded); + if (key == "root") { + if (movetobox == "box") { + //node2 = node.copyWith(label: "网盘目录树", expanded: expanded); + node2 = _makeNode("", "root", "网盘根目录", 0, node.children).copyWith(expanded: expanded); + } else if (movetobox == "xiangce") { + //node2 = node.copyWith(label: "相册目录树", expanded: expanded); + node2 = _makeNode("", "root", "相册根目录", 0, node.children).copyWith(expanded: expanded); + } + } + List updated = treeController.updateNode(key, node2); + _updateTree(treeController.copyWith(children: updated, selectedKey: key)); + + if (expanded == true) { + if (!loading.containsKey(key) || loading[key] == false) { + loading[key] = true; + //是文件夹&&children子文件数==0&&要展开显示了 + //注意node.parent,当联网后发现是空文件夹,node.parent会变成false + + AliFile.apiDirList(movetobox, key, node2.label).then((loadData) { + if (loadData.key == "error") return; + var leve = node2.data.leve + 1; + //动态新增 + List children = []; + var total = loadData.list.length; + for (int i = 0; i < total; i++) { + var m = loadData.list[i]; + if (m.isDir) children.add(_makeNode(m.parentkey, m.key, m.name, leve, [])); + } + node2 = node2.copyWith(expanded: true, parent: true, children: children); //注意这里更新了parent + //更新并展开 + List updated = treeController.updateNode(key, node2); + _updateTree(treeController.copyWith(children: updated, selectedKey: selectKey)); + loading[key] = false; + }); + } + } + } + } + + pageSelectNode(String key) { + Node? node = treeController.getNode(key); + if (node != null) { + pageExpandedNode(node.key, !node.expanded); + } + } + + _expandNodeHandler(String key, bool expanded) { + pageExpandedNode(key, expanded); + } + + _onNodeTap(String key) { + pageSelectNode(key); + } + + Widget _builderTreeNode(BuildContext context, Node node) { + DirNode2? dir = node.data; + if (dir != null) { + return selectKey == node.key ? dir.widgetSelect : dir.widget; + } else { + return Container(); + } + } +} + +class DirNode2 { + DirNode2(this.parentkey, this.key, this.label, this.leve) { + widget = Container( + key: Key("pdt_zhuan_rc_" + key), + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(top: 2, bottom: 2), + child: UnconstrainedBox( + alignment: Alignment.centerLeft, + child: HoverContainer( + key: Key("pdt_zhuan_rch_" + key), + cursor: SystemMouseCursors.click, + height: 24, + decoration: decoration, + hoverDecoration: hoverDecoration, + child: Container( + key: Key("pdt_zhuan_rchc_" + key), + width: 400 - leve * 20, + height: 24, + padding: padding, + child: Row(key: Key("pdt_zhuan_rchcr_" + key), children: [ + icon, + padding2, + Expanded( + child: Text( + label, + key: Key("pdt_zhuan_rchcrt_" + key), + style: style, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + )) + ]))))); + + widgetSelect = Container( + key: Key("pdt_zhuan_rc_" + key), + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(top: 2, bottom: 2), + child: UnconstrainedBox( + alignment: Alignment.centerLeft, + child: HoverContainer( + key: Key("pdt_zhuan_rch_" + key), + cursor: SystemMouseCursors.click, + height: 24, + decoration: decorations, + hoverDecoration: hoverDecorations, + child: Container( + key: Key("pdt_zhuan_rchc_" + key), + width: 400 - leve * 20, + height: 24, + padding: padding, + child: Row(key: Key("pdt_zhuan_rchcr_" + key), children: [ + icons, + padding2, + Expanded( + child: Text( + label, + key: Key("pdt_zhuan_rchcrt_" + key), + style: styles, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + )) + ]))))); + } + + String label = ""; + String key = ""; + //父文件夹key + String parentkey = ""; + //文件夹层级 + int leve = 0; + + Widget widget = Container(); + Widget widgetSelect = Container(); + + var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); + var decorations = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); + + var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); + var hoverDecorations = + BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); + + var padding = EdgeInsets.only(left: 3, right: 3); + var padding2 = Padding(padding: EdgeInsets.only(left: 8)); + var icon = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); + var icons = Icon(MIcons.folder, size: 20, color: MColors.userNavMenuIconHover); + var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor, fontFamily: "opposans"); + var styles = TextStyle(fontSize: 14, color: MColors.userNavMenuIconHover, fontFamily: "opposans"); +} diff --git a/alixby/lib/states/PanFileState.dart b/alixby/lib/states/FileState.dart similarity index 74% rename from alixby/lib/states/PanFileState.dart rename to alixby/lib/states/FileState.dart index 66e0971..1da3aa0 100644 --- a/alixby/lib/states/PanFileState.dart +++ b/alixby/lib/states/FileState.dart @@ -10,11 +10,11 @@ import 'package:flutter_linkify/flutter_linkify.dart'; import 'PanData.dart'; -class PanFileState extends ChangeNotifier { - PanFileState(); +class FileState extends ChangeNotifier { + FileState(); //右侧顶部的 文件夹路径导航 - InlineSpan pageRightDirPath = TextSpan(style: TextStyle(fontSize: 13), children: []); + InlineSpan pageRightDirPath = TextSpan(style: TextStyle(fontSize: 13, fontFamily: "opposans"), children: []); //右侧真正绑定显示的文件列表 List pageRightFileList = []; //基准的文件列表,用来生成排序后的文件列表 @@ -23,17 +23,26 @@ class PanFileState extends ChangeNotifier { String pageRightFileOrderBy = "文件名 从小到大"; //绑定显示的 选中文件数 String get pageRightFileSelectedDes => - "共 " + pageRightFileSelectedCount.toString() + " / " + pageRightFileList0.length.toString() + " 个"; + "选中 " + pageRightFileSelectedCount.toString() + " / " + pageRightFileList0.length.toString() + " 个"; //当前选中的文件数 int pageRightFileSelectedCount = 0; //当前正在显示的文件列表是属于哪一个文件夹 + String pageRightDirBox = ""; String pageRightDirKey = ""; + String pageRightDirName = ""; + + pageSetDir(String box, String fileid, String name) { + pageRightDirBox = box; + pageRightDirKey = fileid; + pageRightDirName = name; + } + //最后一次点击的文件key,shift多选时用到 String pageRightLastClickKey = ""; - //当前正在显示的文件列表是属于哪一个页面(file/trash/favorite/safebox/calendar)顶部菜单关联显示用到 + //当前正在显示的文件列表是属于哪一个页面(file/trash/favorite/safebox/xiangce)顶部菜单关联显示用到 String get getPageName { var key = pageRightDirKey; - if (key == "trash" || key == "favorite" || key == "safebox" || key == "calendar") + if (key == "trash" || key == "favorite" || key == "safebox" || key == "xiangce") return key; else return "file"; @@ -41,7 +50,7 @@ class PanFileState extends ChangeNotifier { //页面调用,更改排序方式 pageChangeOrderBy(String order) { - FileItem? file = PanData.getFileItem(pageRightDirKey); + FileItem? file = PanData.getFileItem(pageRightDirBox, pageRightDirKey); if (file != null) { pageRightFileOrderBy = order; _updateFileOrder(); @@ -50,9 +59,9 @@ class PanFileState extends ChangeNotifier { } //网络回调更新子文件列表 - notifyFileListChanged(String loadKey) { - if (pageRightDirKey == loadKey) { - FileItem? file = PanData.getFileItem(loadKey); + notifyFileListChanged(String box, String loadKey) { + if (pageRightDirBox == box && pageRightDirKey == loadKey) { + FileItem? file = PanData.getFileItem(pageRightDirBox, pageRightDirKey); if (file != null) { _updateFileList(file, true); notifyListeners(); @@ -61,13 +70,14 @@ class PanFileState extends ChangeNotifier { } //页面调用,文件树操作选择文件夹时触发 - pageSelectNode(String key) { - FileItem? file = PanData.getFileItem(key); + pageSelectNode(String box, String key) { + FileItem? file = PanData.getFileItem(box, key); if (file != null) { - bool isUpdate = pageRightDirKey == key; - pageRightDirKey = key; - if (isUpdate == false) _updateFilePath(file); - _updateFileList(file, isUpdate); + bool isSame = pageRightDirKey == key; + pageSetDir(file.box, file.key, file.name); + + if (isSame == false) _updateFilePath(file); + _updateFileList(file, isSame); pageSelectFile(''); //清空选中项 } } @@ -177,9 +187,11 @@ class PanFileState extends ChangeNotifier { pageRightFileList = []; pageRightFileList0 = []; pageRightFileSelectedCount = 0; + pageRightDirBox = ""; pageRightDirKey = ""; + pageRightDirName = ""; pageRightLastClickKey = ""; - pageRightDirPath = TextSpan(style: TextStyle(fontSize: 13), children: []); + pageRightDirPath = TextSpan(style: TextStyle(fontSize: 13, fontFamily: "opposans"), children: []); notifyListeners(); } @@ -197,10 +209,10 @@ class PanFileState extends ChangeNotifier { Future refreshPanByTimer(bool isTimer) async { try { if (isTimer) { - if (Global.userState.userNavPageIndex != 1) return false; + if (Global.userState.userNavPageIndex != Global.getTreeState(pageRightDirBox).boxindex) return false; if (!Global.userState.isLogin) return false; double subtime = DateTime.now().millisecondsSinceEpoch / 1000 - pageRefreshTime; //相差几秒 - if (pageRightFileList0.length >= 1500) { + if (pageRightFileList0.length >= 100) { return false; //文件太多不自动刷新 } if (getPageName == 'file' && subtime < 60) { @@ -209,13 +221,13 @@ class PanFileState extends ChangeNotifier { return false; //回收站60秒刷新一次 } else if (getPageName == 'favorite' && subtime < 60) { return false; //收藏,60秒刷新一次 - } else if (getPageName == "safebox" || getPageName == "calendar") { - return false; //不刷新 + } else if (getPageName == 'xiangce' && subtime < 60) { + return false; //相册,60秒刷新一次 + } else if (getPageName == "safebox" && subtime < 60) { + return false; //保险箱,60秒刷新一次 } } - var dt1 = DateTime.now().millisecondsSinceEpoch; - print('refreshPanByTimer ' + dt1.toString()); - Global.panTreeState.pageRefreshNode(); + Global.getTreeState(pageRightDirBox).pageRefreshNode(); pageRefreshTime = DateTime.now().millisecondsSinceEpoch / 1000; return true; } catch (e) { @@ -241,14 +253,29 @@ class PanFileState extends ChangeNotifier { return selectKeys; } -//返回选中文件的父文件夹的完整路径(下载用) + //返回所有的图片文件的filelist + List getImageFiles() { + List filelist = []; + for (int f = 0; f < pageRightFileList0.length; f++) { + if (pageRightFileList0[f].filetype == "image") filelist.add(pageRightFileList0[f]); + } + filelist.sort((a, b) => StringUtils.sortNumber1(a.title, b.title)); + + List selectKeys = []; + for (int i = 0; i < filelist.length; i++) { + selectKeys.add(filelist[i]); + } + return selectKeys; + } + + //返回选中文件的父文件夹的完整路径(下载用) String getSelectedFileParentPath() { List names = []; var pid = pageRightDirKey; while (true) { if (pid == "root") break; //成功到顶 - var find = PanData.getFileItem(pid); + var find = PanData.getFileItem(pageRightDirBox, pid); if (find == null) break; //没有找到 names.add(find.name); pid = find.parentkey; @@ -260,19 +287,27 @@ class PanFileState extends ChangeNotifier { return path; // "" /xx/xx } - static _onOpen(LinkableElement link) { - Global.panTreeState.pageSelectNode(link.url, false); + static _onOpen(String box, String key) { + Global.getTreeState(box).pageSelectNode(box, key, false); } //刷新顶部文件路径导航 bool _updateFilePath(FileItem file) { List names = []; List ids = []; + List boxs = []; + var topbox = file.box; var topkey = file.key; var topname = file.name; - if (topkey != "trash" && topkey != "favorite" && topkey != "safebox" && topkey != "calendar") { + if (topbox == "sbox") { + topkey = "root"; + topname = "保险箱"; + } else if (topbox == "xiangce") { + topkey = "root"; + topname = "相册"; + } else if (topbox == "box" && topkey != "trash" && topkey != "favorite") { topkey = "root"; topname = "根目录"; } @@ -282,33 +317,47 @@ class PanFileState extends ChangeNotifier { //root时 pid=="" names.add(file.name); ids.add(file.key); + boxs.add(file.box); while (true) { if (pid == "root") break; //成功到顶 - var find = PanData.getFileItem(pid); + var find = PanData.getFileItem(file.box, pid); if (find == null) return false; //没有找到 names.add(find.name); ids.add(find.key); + boxs.add(file.box); pid = find.parentkey; } } List childs = []; - var linkStyle = TextStyle(fontSize: 13, color: MColors.linkColor, decoration: TextDecoration.none); + var linkStyle = + TextStyle(fontSize: 13, color: MColors.linkColor, decoration: TextDecoration.none, fontFamily: "opposans"); childs.add(WidgetSpan( child: Linkify( - onOpen: _onOpen, text: topname, linkifiers: [FileLinkifier(topname, topkey)], linkStyle: linkStyle))); - childs.add(TextSpan(text: " > ", style: TextStyle(color: MColors.pageRightPathColor))); + onOpen: (v) => _onOpen(topbox, topkey), + text: topname, + linkifiers: [FileLinkifier(topname, topkey, topbox)], + linkStyle: linkStyle))); + childs.add(TextSpan(text: " > ", style: TextStyle(color: MColors.pageRightPathColor, fontFamily: "opposans"))); for (int i = names.length - 1; i >= 0; i--) { var name = names[i]; + var box = boxs[i]; + var fileid = ids[i]; + if (name.length > 11) name = name.substring(0, 4) + "..." + name.substring(name.length - 4); var link = WidgetSpan( - child: Linkify(onOpen: _onOpen, text: name, linkifiers: [FileLinkifier(name, ids[i])], linkStyle: linkStyle)); + child: Linkify( + onOpen: (v) => _onOpen(box, fileid), + text: name, + linkifiers: [FileLinkifier(name, fileid, box)], + linkStyle: linkStyle)); childs.add(link); - if (i > 0) childs.add(TextSpan(text: " > ", style: TextStyle(color: MColors.pageRightPathColor))); + if (i > 0) + childs.add(TextSpan(text: " > ", style: TextStyle(color: MColors.pageRightPathColor, fontFamily: "opposans"))); } - pageRightDirPath = TextSpan(style: TextStyle(fontSize: 13), children: childs); + pageRightDirPath = TextSpan(style: TextStyle(fontSize: 13, fontFamily: "opposans"), children: childs); return true; } @@ -317,12 +366,13 @@ class PanFileState extends ChangeNotifier { final Icon iconImage = Icon(MIcons.file_img, key: Key("image"), size: 22, color: MColors.iconImage); final Icon iconVideo = Icon(MIcons.file_video, key: Key("video"), size: 22, color: MColors.iconVideo); final Icon iconAudio = Icon(MIcons.file_audio, key: Key("audio"), size: 22, color: MColors.iconAudio); + final Icon iconZip = Icon(MIcons.file_zip, key: Key("zip"), size: 22, color: MColors.iconZip); final Icon iconTxt = Icon(MIcons.file_txt2, key: Key("txt"), size: 22, color: MColors.iconTxt); final Icon iconWeiFa = Icon(MIcons.weifa, key: Key("weifa"), size: 22, color: MColors.iconWeiFa); //刷新文件列表 - void _updateFileList(FileItem file, bool isUpdate) { + void _updateFileList(FileItem file, bool isSame) { List selectKeys = []; - if (isUpdate) { + if (isSame) { for (int f = 0; f < pageRightFileList0.length; f++) { if (pageRightFileList0[f].selected) { selectKeys.add(pageRightFileList0[f].key); @@ -334,6 +384,7 @@ class PanFileState extends ChangeNotifier { for (int i = 0; i < file.children.length; i++) { var item = file.children[i]; var model = PageRightFileItem.newPageRightFileItem( + item.box, item.key, (item.isWeiFa ? iconWeiFa @@ -347,14 +398,16 @@ class PanFileState extends ChangeNotifier { ? iconImage : item.icon == "txt" ? iconTxt - : iconFile), + : item.icon == "zip" + ? iconZip + : iconFile), item.name, item.size, item.time, item.starred, item.isDir, item.icon); - if (isUpdate) model.selected = selectKeys.contains(model.key); + if (isSame) model.selected = selectKeys.contains(model.key); list.add(model); } pageRightFileList0 = list; diff --git a/alixby/lib/states/Global.dart b/alixby/lib/states/Global.dart index a5f3d81..dc9be35 100644 --- a/alixby/lib/states/Global.dart +++ b/alixby/lib/states/Global.dart @@ -1,22 +1,43 @@ +import 'package:alixby/states/FileState.dart'; +import 'package:alixby/states/TreeState.dart'; import 'package:alixby/states/pageDownState.dart'; import 'package:alixby/states/pageRssMiaoChuanState.dart'; -import '../states/UserState.dart'; -import '../states/SettingState.dart'; -import 'PanTreeState.dart'; -import 'PanFileState.dart'; +import 'package:alixby/states/pageRssSearchState.dart'; +import 'package:alixby/states/UserState.dart'; +import 'package:alixby/states/SettingState.dart'; + +class PanFileState extends FileState { + PanFileState(); +} + +class XiangCeFileState extends FileState { + XiangCeFileState(); +} + +class PanTreeState extends TreeState { + PanTreeState() : super('box', "网盘目录树", 1); +} + +class XiangCeTreeState extends TreeState { + XiangCeTreeState() : super('xiangce', '相册目录树', 2); +} class Global { // 是否为release版 static bool get isRelease => bool.fromEnvironment("dart.vm.product"); - static String get appTitle => "阿里云盘小白羊版 v1.6.10"; - static String get appVer => "v1.6.10"; + static String get appTitle => "阿里云盘小白羊版 v1.6.21"; + static String get appVer => "v1.6.21"; - static UserState userState = UserState(); - static SettingState settingState = SettingState(); static PanTreeState panTreeState = PanTreeState(); + static XiangCeTreeState xiangceTreeState = XiangCeTreeState(); static PanFileState panFileState = PanFileState(); + static XiangCeFileState xiangceFileState = XiangCeFileState(); + + static UserState userState = UserState(); + static SettingState settingState = SettingState(); static PageDownState pageDownState = PageDownState(); static PageRssMiaoChuanState pageRssMiaoChuanState = PageRssMiaoChuanState(); + static PageRssSearchState pageRssSearchState = PageRssSearchState(); static int ctrlTime = 0; static int shiftTime = 0; @@ -32,6 +53,33 @@ class Global { shiftTime = DateTime.now().millisecondsSinceEpoch; } + static FileState getFileState(String box) { + if (box == "xiangce") return xiangceFileState; + return panFileState; + } + + static TreeState getTreeState(String box) { + if (box == "xiangce") return xiangceTreeState; + return panTreeState; + } + + static void pageInitByTheme() { + panTreeState.pageInitByTheme(); + xiangceTreeState.pageInitByTheme(); + } + + static void pageExpandedNodeByRoot() { + panTreeState.pageExpandedNode('root', true); + xiangceTreeState.pageExpandedNode('root', true); + } + + static void pageClearNodeByLogoff() { + panTreeState.userLogoff(); + panFileState.userLogoff(); + xiangceTreeState.userLogoff(); + xiangceFileState.userLogoff(); + } + //初始化全局信息,会在APP启动时执行 static Future init() async {} } diff --git a/alixby/lib/states/PanData.dart b/alixby/lib/states/PanData.dart index 930ad1e..0c32919 100644 --- a/alixby/lib/states/PanData.dart +++ b/alixby/lib/states/PanData.dart @@ -3,28 +3,32 @@ import 'package:alixby/models/FileItem.dart'; import 'package:alixby/states/Global.dart'; class PanData { - static FileItem root = FileItem.newFileItem("root", "", "根目录"); - static FileItem trash = FileItem.newFileItem("trash", "", "回收站"); - static FileItem favorite = FileItem.newFileItem("favorite", "", "收藏夹"); - static FileItem safebox = FileItem.newFileItem("safebox", "", "保险箱"); - static FileItem calendar = FileItem.newFileItem("calendar", "", "最近访问"); + static FileItem root = FileItem.newFileItem("box", "root", "", "根目录"); + static FileItem trash = FileItem.newFileItem("box", "trash", "", "回收站"); + static FileItem favorite = FileItem.newFileItem("box", "favorite", "", "收藏夹"); + + static FileItem xiangce = FileItem.newFileItem("xiangce", "root", "", "相册"); + static FileItem trash2 = FileItem.newFileItem("xiangce", "trash", "", "回收站"); + static FileItem favorite2 = FileItem.newFileItem("xiangce", "favorite", "", "收藏夹"); + + static FileItem safebox = FileItem.newFileItem("sbox", "safebox", "", "保险箱"); // ignore: non_constant_identifier_names - static FileItem? getFileItem(String key, {FileItem? parent}) { + static FileItem? getFileItem(String box, String key, {FileItem? parent}) { FileItem? _found; - switch (key) { - case "trash": - return trash; - case "favorite": - return favorite; - case "safebox": - return safebox; - case "calendar": - return calendar; - } + if (box == "box" && key == "trash") return trash; + if (box == "box" && key == "favorite") return favorite; + if (box == "xiangce" && key == "trash") return trash2; + if (box == "xiangce" && key == "favorite") return favorite2; List _children = parent == null ? [root] : parent.children; + if (box == "xiangce") { + _children = parent == null ? [xiangce] : parent.children; + } else if (box == "safebox") { + _children = parent == null ? [safebox] : parent.children; + } + Iterator iter = _children.iterator; while (iter.moveNext()) { FileItem child = iter.current; @@ -33,7 +37,7 @@ class PanData { break; } else { if (child.isFile == false) { - _found = getFileItem(key, parent: child); + _found = getFileItem(box, key, parent: child); if (_found != null) { break; } @@ -49,14 +53,18 @@ class PanData { static Map loadDataTime = {}; //用来抛弃无效的续增 //网络回调附加子文件列表 static apiFileListCallBack(FileListModel loadData) { + var loadkey = loadData.box + loadData.key; if (loadData.next_marker == "error") { - loading[loadData.key] = false; + loading[loadkey] = false; return; } - if (loadData.isMarker && loadDataTime[loadData.key] != loadData.time) return; //无效的续增 + if (loadData.isMarker && loadDataTime[loadkey] != loadData.time) return; //无效的续增 - FileItem? file = getFileItem(loadData.key); - if (file == null) return; //无效的数据,不可能发生 + FileItem? file = getFileItem(loadData.box, loadData.key); + if (file == null) { + loading[loadkey] = false; + return; //无效的数据,不可能发生 + } //保存数据 if (loadData.isMarker == true) { @@ -65,32 +73,32 @@ class PanData { file.children = loadData.list; } //更新显示 - Global.panTreeState.notifyFileListChanged(loadData.key); - Global.panFileState.notifyFileListChanged(loadData.key); + + Global.getTreeState(loadData.box).notifyFileListChanged(loadData.key); + Global.getFileState(loadData.box).notifyFileListChanged(loadData.box, loadData.key); //如果还有next_marker,继续加载 if (loadData.next_marker != "") { if (loadData.isMarker == false) { - loadDataTime[loadData.key] = loadData.time; //第一次拉取时标记一下 + loadDataTime[loadkey] = loadData.time; //第一次拉取时标记一下 } - AliFile.apiFileList(loadData.time, loadData.key, loadData.name, marker: loadData.next_marker).then((data) { - print('load next_marker for network ok ' + loadData.key); + AliFile.apiFileList(loadData.time, loadData.box, loadData.key, loadData.name, marker: loadData.next_marker) + .then((data) { apiFileListCallBack(data); }); } else { - loading[loadData.key] = false; + loading[loadkey] = false; } } //点击文件树时会触发这里加载文件列表 //点击--PanTreeState.expandedNode--PanData.loadFileList--PanData.apiFileListCallBack--panFileState.notifyFileListChanged+PanTreeState.notifyFileListChanged - static loadFileList(String parentkey, String name) { - if (!loading.containsKey(parentkey) || loading[parentkey] == false) { - loading[parentkey] = true; - print('load for network ' + name + " " + parentkey); - AliFile.apiFileList(DateTime.now().millisecondsSinceEpoch, parentkey, name).then((data) { - print('load for network ok ' + name + " " + parentkey); + static loadFileList(String box, String parentkey, String name) { + var loadkey = box + parentkey; + if (!loading.containsKey(loadkey) || loading[loadkey] == false) { + loading[loadkey] = true; + AliFile.apiFileList(DateTime.now().millisecondsSinceEpoch, box, parentkey, name).then((data) { apiFileListCallBack(data); }); } @@ -112,6 +120,6 @@ class PanData { trash.children = []; favorite.children = []; safebox.children = []; - calendar.children = []; + xiangce.children = []; } } diff --git a/alixby/lib/states/SettingState.dart b/alixby/lib/states/SettingState.dart index 43e0c6c..274174d 100644 --- a/alixby/lib/states/SettingState.dart +++ b/alixby/lib/states/SettingState.dart @@ -3,7 +3,7 @@ import 'package:alixby/states/Global.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:bot_toast/bot_toast.dart'; -import '../models/Setting.dart'; +import 'package:alixby/models/Setting.dart'; import 'package:flutter/material.dart'; class SettingState extends ChangeNotifier { @@ -67,13 +67,13 @@ class SettingState extends ChangeNotifier { Future loadSetting() async { setting = await GoServer.goSetting("load", ""); MColors.setTheme(setting.theme); - Global.panTreeState.pageInitByTheme(); + Global.pageInitByTheme(); savePathController.text = setting.savePath; downSpeedController.text = setting.downSpeed; if (Setting.UIVER != setting.serverVer) { //提示版本升级 - BotToast.showText(text: "检测到新版本 (" + setting.serverVer + ") 请升级!", align: Alignment(0, 0), duration: null); + BotToast.showText(text: "检测到新版本 (" + setting.serverVer + ") 请升级!", duration: null); } notifyListeners(); diff --git a/alixby/lib/states/PanTreeState.dart b/alixby/lib/states/TreeState.dart similarity index 79% rename from alixby/lib/states/PanTreeState.dart rename to alixby/lib/states/TreeState.dart index 77d269b..8ae1d46 100644 --- a/alixby/lib/states/PanTreeState.dart +++ b/alixby/lib/states/TreeState.dart @@ -10,28 +10,34 @@ import 'package:flutter/material.dart'; import 'PanData.dart'; -class PanTreeState extends ChangeNotifier { - PanTreeState() { - treeController = TreeViewController(children: [_makeNode("", "root", "网盘目录树", 0, [])]); +class TreeState extends ChangeNotifier { + TreeState(String box, String boxname, int boxindex) { + this.box = box; + this.boxname = boxname; + this.boxindex = boxindex; + treeController = TreeViewController(children: [_makeNode("", "root", boxname, 0, [])]); width = _updateWidth(treeController.children) * double.parse(Global.settingState.setting.textScale); height = _updateHeight(treeController.children); } TreeViewController treeController = TreeViewController(); //文件树的最小宽度 - double width = 300; + double width = 280; //文件数的最小高度 double height = 300; //当前选中的文件夹 String selectKey = "root"; + String box = "box"; + String boxname = "网盘目录树"; + int boxindex = 1; pageInitByTheme() { - Node node = _makeNode("", "root", "网盘目录树", 0, []); + Node node = _makeNode("", "root", boxname, 0, []); DirNode dir = node.data; var leve = dir.leve + 1; //动态新增 List children = []; - FileItem? file = PanData.getFileItem("root"); + FileItem? file = PanData.getFileItem(box, "root"); if (file != null) { var total = file.children.length; for (int i = 0; i < total; i++) { @@ -45,18 +51,23 @@ class PanTreeState extends ChangeNotifier { } } - //页面调用,点击回收站、收藏夹、最近访问、保险箱时触发 + //页面调用,点击回收站、收藏夹、保险箱、相册时触发 pageMenuSelectKey(String key) { - Global.userState.updatePageIndex(1); + Global.userState.updatePageIndex(boxindex); selectKey = key; _updateTree(treeController.copyWith(selectedKey: key)); //实际上是为了清空文件树的选中节点,因为现在要选中回收站 - if (key == "trash" || key == "favorite" || key == "safebox" || key == "calendar") { - var file = PanData.getFileItem(key); - if (file != null) { - Global.panFileState.pageSelectNode(key); //显示右侧文件列表 - if (file.children.length == 0) { - PanData.loadFileList(key, key); //触发联网加载 - } + FileItem? file; + if (key == "trash" || key == "favorite") { + file = PanData.getFileItem(box, key); + } else if (key == "xiangce") { + file = PanData.getFileItem("xiangce", "root"); + } else if (key == "safebox") { + file = PanData.getFileItem("sbox", "root"); + } + if (file != null) { + Global.getFileState(box).pageSelectNode(file.box, file.key); //显示右侧文件列表 + if (file.children.length == 0) { + PanData.loadFileList(file.box, file.key, file.name); //触发联网加载 } } } @@ -65,24 +76,28 @@ class PanTreeState extends ChangeNotifier { _updateTree(TreeViewController tree) { treeController = tree; width = _updateWidth(tree.children) * double.parse(Global.settingState.setting.textScale); - if (width < 290) width = 290; + if (width < 280) width = 280; height = _updateHeight(treeController.children) + 12; notifyListeners(); } //页面调用,点击文件树的一个文件夹时触发 - pageSelectNode(String key, bool expanded) { - Global.userState.updatePageIndex(1); + pageSelectNode(String box, String key, bool expanded) { + Global.userState.updatePageIndex(boxindex); Node? node = treeController.getNode(key); if (node != null) { if (node.isParent && expanded && node.expanded == false) { pageExpandedNode(node.key, true); //选中的文件夹必须展开下级,列出所有子文件夹 } else { - print('selectNode ' + key); selectKey = key; _updateTree(treeController.copyWith(selectedKey: key)); - Global.panFileState.pageSelectNode(key); //显示右侧文件列表 + Global.getFileState(box).pageSelectNode(box, key); //显示右侧文件列表 } + } else { + selectKey = key; + _updateTree(treeController.copyWith(selectedKey: key)); + Global.getFileState(box).pageSelectNode(box, key); //显示右侧文件列表 + PanData.loadFileList(box, key, key); //触发联网加载 } } @@ -92,29 +107,30 @@ class PanTreeState extends ChangeNotifier { if (node != null) { selectKey = key; //选中并展开 - print((expanded ? 'expanded ' : 'close ') + key); Node node2 = node.copyWith(expanded: expanded); List updated = treeController.updateNode(key, node2); _updateTree(treeController.copyWith(children: updated, selectedKey: key)); - Global.panFileState.pageSelectNode(key); //显示右侧文件列表 + Global.getFileState(box).pageSelectNode(box, key); //显示右侧文件列表 if (node.parent && node.children.length == 0 && expanded == true) { //是文件夹&&children子文件数==0&&要展开显示了 //注意node.parent,当联网后发现是空文件夹,node.parent会变成false - PanData.loadFileList(key, node.label); //触发联网加载 + PanData.loadFileList(box, key, node.label); //触发联网加载 } } } //页面调用,刷新子文件列表 pageRefreshNode() { - Global.userState.updatePageIndex(1); + Global.userState.updatePageIndex(boxindex); var key = selectKey; - Node? node = treeController.getNode(key); - if (node != null) { - PanData.loadFileList(key, node.label); //触发联网加载 - } else if (key == "trash" || key == "favorite" || key == "safebox" || key == "calendar") { - PanData.loadFileList(key, key); //触发联网加载 + if (key == "trash") { + PanData.loadFileList(box, "trash", '回收站'); //触发联网加载 + } else if (key == "favorite") { + PanData.loadFileList(box, "favorite", "收藏"); //触发联网加载 + } else { + var filestate = Global.getFileState(box); + PanData.loadFileList(filestate.pageRightDirBox, filestate.pageRightDirKey, filestate.pageRightDirName); //触发联网加载 } } @@ -136,7 +152,7 @@ class PanTreeState extends ChangeNotifier { //动态新增 List children = []; - FileItem? file = PanData.getFileItem(loadKey); + FileItem? file = PanData.getFileItem(box, loadKey); if (file != null) { var total = file.children.length; for (int i = 0; i < total; i++) { @@ -264,8 +280,8 @@ class DirNode { var padding2 = Padding(padding: EdgeInsets.only(left: 8)); var icon = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); var icons = Icon(MIcons.folder, size: 20, color: MColors.userNavMenuIconHover); - var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor); - var styles = TextStyle(fontSize: 14, color: MColors.userNavMenuIconHover); + var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor, fontFamily: "opposans"); + var styles = TextStyle(fontSize: 14, color: MColors.userNavMenuIconHover, fontFamily: "opposans"); static double textWidth(String text) { if (text.isEmpty) return 0; @@ -273,7 +289,7 @@ class DirNode { final TextPainter textPainter = TextPainter( textDirection: TextDirection.ltr, locale: Locale("zh", "zh-Hans"), - text: TextSpan(text: text, style: TextStyle(fontSize: 15)), + text: TextSpan(text: text, style: TextStyle(fontSize: 15, fontFamily: "opposans")), maxLines: 1) ..layout(maxWidth: double.infinity); return textPainter.size.width; diff --git a/alixby/lib/states/UserState.dart b/alixby/lib/states/UserState.dart index 0f7c9bf..1af6140 100644 --- a/alixby/lib/states/UserState.dart +++ b/alixby/lib/states/UserState.dart @@ -9,12 +9,18 @@ class UserState extends ChangeNotifier { // APP是否登录(如果有用户信息,则证明登录过) bool get isLogin => user.userID != ""; //登录后显示用户名,未登录时显示 点击登录 + String get userFace => user.userID == "" ? "" : user.userFace; String get userName => user.userID == "" ? "点击登录" : user.userName; String get userPanUsed => "网盘空间 " + user.panUsed + " / " + user.panTotal; - //登录后显示退出按钮,未登录时不显示 - double get userBtnWidth => user.userID == "" ? 0 : 26; - //当前所在页面 0=Rss 1=Pan 2=Down 3=Setting + + //当前所在页面 0=Rss 1=Pan 2=XiangCe 3=Down 4=Setting int userNavPageIndex = 1; + + String get box => userNavPageIndex == 1 + ? "box" + : userNavPageIndex == 2 + ? "xiangce" + : ""; //当前所在页面 0=秒传 1=搜索 2=离线 3=帮助 int userNavPageRssIndex = 0; final pageController = PageController(initialPage: 1); @@ -31,10 +37,10 @@ class UserState extends ChangeNotifier { notifyListeners(); } - Future loadUser() async { + Future loadUser(bool isLogin) async { user = await AliLogin.apiUserInfo(); - if (user.userID != "") { - Global.panTreeState.pageExpandedNode('root', true); + if (isLogin && user.userID != "") { + Global.pageExpandedNodeByRoot(); } notifyListeners(); return user.userID != ""; @@ -43,8 +49,7 @@ class UserState extends ChangeNotifier { Future logoffUser() async { await AliLogin.apiUserLogoff(); user = AliUserInfo(); - Global.panTreeState.userLogoff(); - Global.panFileState.userLogoff(); + Global.pageClearNodeByLogoff(); notifyListeners(); } } diff --git a/alixby/lib/states/pageDownState.dart b/alixby/lib/states/pageDownState.dart index 1a81927..ac5dd83 100644 --- a/alixby/lib/states/pageDownState.dart +++ b/alixby/lib/states/pageDownState.dart @@ -51,7 +51,7 @@ class PageDownState extends ChangeNotifier { Future refreshDownByTimer(bool isTimer) async { try { if (isTimer) { - if (Global.userState.userNavPageIndex != 2) return false; + if (Global.userState.userNavPageIndex != 3) return false; if (!Global.userState.isLogin) return false; double subtime = DateTime.now().millisecondsSinceEpoch / 1000 - pageRefreshTime; //相差几秒 if (getPageName == 'downing') { @@ -64,8 +64,6 @@ class PageDownState extends ChangeNotifier { return false; //已上传2秒刷新一次 } } - var dt1 = DateTime.now().millisecondsSinceEpoch; - print('refreshDownByTimer ' + dt1.toString()); var downdata = PageRightDownModel(); //联网加载 if (getPageName == 'downing') { diff --git a/alixby/lib/states/pageRssSearchState.dart b/alixby/lib/states/pageRssSearchState.dart new file mode 100644 index 0000000..da9b78d --- /dev/null +++ b/alixby/lib/states/pageRssSearchState.dart @@ -0,0 +1,200 @@ +import 'package:alixby/api/Linker.dart'; +import 'package:alixby/models/PageRightFileItem.dart'; +import 'package:alixby/states/Global.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; + +class PageRssSearchState extends ChangeNotifier { + PageRssSearchState(); + + List pageRightSearchList = []; + TextEditingController searchcontroller = TextEditingController(); + Widget navBtns = Row(crossAxisAlignment: CrossAxisAlignment.center, children: []); + + int pageIndex = 0; + int pageCount = 0; + int fileCount = 0; + + //绑定显示的 选中文件数 + String get pageRightFileSelectedDes => + "选中 " + pageRightFileSelectedCount.toString() + " / " + pageRightSearchList.length.toString() + " 个"; + //当前选中的文件数 + int pageRightFileSelectedCount = 0; + //最后一次点击的文件key,shift多选时用到 + String pageRightLastClickKey = ""; + //页面调用,选中文件 + pageSelectFile(String key) { + int total = pageRightSearchList.length; + int selected = 0; + if (key == "all") { + pageRightLastClickKey = ""; + bool istoselect = false; + for (int i = 0; i < total; i++) { + if (pageRightSearchList[i].selected) { + istoselect = true; + selected++; + } + } + + if (istoselect && selected == total) { + //已经是全选了,执行反选操作 + selected = 0; + for (int i = 0; i < total; i++) { + pageRightSearchList[i].selected = false; + } + } else { + //一个也没选中 或者 部分文件被选中,执行全选操作 + selected = total; + for (int i = 0; i < total; i++) { + pageRightSearchList[i].selected = true; + } + } + } else { + bool isCtrl = Global.isCtrl; + bool isShift = Global.isShift; + bool isHandle = false; //是否已经成功处理 + if (isShift) { + //从pageRightLastClickKey到key + selected = 0; + int start = -1, end = -1; + for (int i = 0; i < total; i++) { + if (pageRightSearchList[i].key == pageRightLastClickKey) { + start = i; + } + if (pageRightSearchList[i].key == key) { + end = i; + } + if (start > 0 && end > 0) break; + } + if (start >= 0 && end >= 0) { + if (start > end) { + var m = start; + start = end; + end = m; + } + for (int n = start; n <= end; n++) { + pageRightSearchList[n].selected = true; + } + for (int j = 0; j < total; j++) { + if (pageRightSearchList[j].selected) selected++; + } + isHandle = true; + } + } + + if (isHandle == false && isCtrl) { + selected = 0; + for (int i = 0; i < total; i++) { + if (pageRightSearchList[i].key == key) { + pageRightSearchList[i].selected = !pageRightSearchList[i].selected; + break; + } + } + for (int j = 0; j < total; j++) { + if (pageRightSearchList[j].selected) selected++; + } + isHandle = true; + } + if (isHandle == false) { + selected = 0; + int isSomeSelect = 0; //是否已经多选,如果已经多选,最后应该变成单选key这一个 + for (int i = 0; i < total; i++) { + if (pageRightSearchList[i].selected) isSomeSelect++; + if (isSomeSelect > 1) break; //说明有多个选中的 + } + + for (int i = 0; i < total; i++) { + if (pageRightSearchList[i].key == key) { + //如果有多个文件被选中 || 反选 + pageRightSearchList[i].selected = isSomeSelect > 1 || !pageRightSearchList[i].selected; + if (pageRightSearchList[i].selected) { + selected = 1; + } + } else if (pageRightSearchList[i].selected) { + pageRightSearchList[i].selected = false; //其他的全部取消选中 + } + } + } + pageRightLastClickKey = key; + } + pageRightFileSelectedCount = selected; + _updateNavBtns(); + notifyListeners(); + } + + pageSearch(int pageindex) { + var txt = searchcontroller.text; + if (pageindex < 1) pageindex = 1; + if (pageindex > 9) pageindex = 9; + Linker.goLinkSearch(txt, pageindex).then((value) { + _updateFileList(value.searchlist); + pageIndex = value.pageIndex; + pageCount = value.pageCount; + fileCount = value.fileCount; + _updateNavBtns(); + notifyListeners(); + + if (fileCount == 0) { + BotToast.showText(text: "搜不到结果哦,换个关键字试试?"); + } + }); + } + + void _updateFileList(List newlist) { + List selectKeys = []; + + for (int f = 0; f < pageRightSearchList.length; f++) { + if (pageRightSearchList[f].selected) { + selectKeys.add(pageRightSearchList[f].key); + } + } + + for (int i = 0; i < newlist.length; i++) { + var item = newlist[i]; + item.selected = selectKeys.contains(item.key); + } + pageRightSearchList = newlist; + pageRightFileSelectedCount = 0; + for (int g = 0; g < pageRightSearchList.length; g++) { + if (pageRightSearchList[g].selected) { + pageRightFileSelectedCount++; + } + } + } + + //返回所有选中的文件的filelist + List getSelectedFiles() { + List selectKeys = []; + for (int f = 0; f < pageRightSearchList.length; f++) { + if (pageRightSearchList[f].selected) selectKeys.add(pageRightSearchList[f]); + } + return selectKeys; + } + + _updateNavBtns() { + List list = []; + if (pageCount > 0) { + 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); + })); + } else { + list.add(TextButton( + child: Text(i.toString()), + onPressed: () { + Global.pageRssSearchState.pageSearch(i); + })); + } + list.add(Padding(padding: EdgeInsets.only(left: 4))); + } + list.add(Padding(padding: EdgeInsets.only(left: 12))); + } + //list.add(Text(fileCount.toString())); + navBtns = + Row(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.center, children: list); + } +} diff --git a/alixby/lib/utils/APILoadingWidget.dart b/alixby/lib/utils/APILoadingWidget.dart index 76b4409..dc05d82 100644 --- a/alixby/lib/utils/APILoadingWidget.dart +++ b/alixby/lib/utils/APILoadingWidget.dart @@ -70,7 +70,7 @@ class _APILoadingWidgetState extends State with SingleTickerPr width: 200, height: 18, child: Text(widget.title, - style: TextStyle(fontSize: 14, color: MColors.textColor), + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), textAlign: TextAlign.left, softWrap: false, maxLines: 1, diff --git a/alixby/lib/utils/FileLinkifier.dart b/alixby/lib/utils/FileLinkifier.dart index 930fd7e..b6d9d78 100644 --- a/alixby/lib/utils/FileLinkifier.dart +++ b/alixby/lib/utils/FileLinkifier.dart @@ -1,8 +1,8 @@ import 'package:flutter_linkify/flutter_linkify.dart'; class FileLinkifier extends Linkifier { - FileLinkifier(String name, String fileID) { - list.add(FileElement(name, fileID)); + FileLinkifier(String name, String fileid, String box) { + list.add(FileElement(name, fileid, box)); } final list = []; @override @@ -14,10 +14,11 @@ class FileLinkifier extends Linkifier { /// Represents an element containing an email address class FileElement extends LinkableElement { // ignore: non_constant_identifier_names + final String box; final String key; final String name; - FileElement(this.name, this.key) : super(name, key); + FileElement(this.name, this.key, this.box) : super(name, key); @override String toString() { @@ -28,7 +29,7 @@ class FileElement extends LinkableElement { bool operator ==(other) => equals(other); @override - bool equals(other) => other is FileElement && super.equals(other) && other.key == key; + bool equals(other) => other is FileElement && super.equals(other) && other.key == key && other.box == box; @override int get hashCode => super.hashCode; diff --git a/alixby/lib/utils/LoadingWidget.dart b/alixby/lib/utils/LoadingWidget.dart index 2677e05..d2db1e1 100644 --- a/alixby/lib/utils/LoadingWidget.dart +++ b/alixby/lib/utils/LoadingWidget.dart @@ -63,7 +63,7 @@ class _LoadingWidgetState extends State with SingleTickerProvider ), Expanded( child: Text(widget.title, - style: TextStyle(fontSize: 15, color: MColors.textColor), + style: TextStyle(fontSize: 15, color: MColors.textColor, fontFamily: "opposans"), textAlign: TextAlign.left, softWrap: false, maxLines: 10, diff --git a/alixby/lib/utils/MColors.dart b/alixby/lib/utils/MColors.dart index 9dcd411..9909243 100644 --- a/alixby/lib/utils/MColors.dart +++ b/alixby/lib/utils/MColors.dart @@ -57,6 +57,7 @@ class MColors { static get iconFile => mcolor.iconFile; static get iconVideo => mcolor.iconVideo; static get iconAudio => mcolor.iconAudio; + static get iconZip => mcolor.iconZip; static get iconImage => mcolor.iconImage; static get iconTxt => mcolor.iconTxt; static get iconWeiFa => mcolor.iconWeiFa; @@ -78,6 +79,8 @@ class MColors { static get trackColor => mcolor.trackColor; static get trackBorderColor => mcolor.trackBorderColor; static get textColor => mcolor.textColor; + static get textColorGray => mcolor.textColorGray; + static get textColorRed => mcolor.textColorRed; } class MColorsLight { @@ -126,6 +129,7 @@ class MColorsLight { Color iconFile = Color(0xffbcb3b3); Color iconVideo = Color(0xff3482F0); Color iconAudio = Color(0xff474DE2); + Color iconZip = Color(0xff8D51DB); Color iconImage = Color(0xffE03450); Color iconTxt = Color(0xff8BC755); Color iconWeiFa = Color(0xffd81e06); @@ -146,6 +150,8 @@ class MColorsLight { Color trackColor = Color(0x66e0e0e0); Color trackBorderColor = Color(0x99e0e0e0); Color textColor = Color(0xee000000); + Color textColorGray = Color(0xaa333333); + Color textColorRed = Color(0xffeb8381); } class MColorsDark extends MColorsLight { @@ -195,6 +201,7 @@ class MColorsDark extends MColorsLight { Color iconFile = Color(0xffbcb3b3); Color iconVideo = Color(0xff3482F0); Color iconAudio = Color(0xff474DE2); + Color iconZip = Color(0xff8D51DB); Color iconImage = Color(0xffE03450); Color iconTxt = Color(0xff8BC755); Color iconWeiFa = Color(0xffd81e06); @@ -215,4 +222,6 @@ class MColorsDark extends MColorsLight { Color trackColor = Color(0x99e0e0e0); Color trackBorderColor = Color(0x99e0e0e0); Color textColor = Colors.white; + Color textColorGray = Color(0x99ffffff); + Color textColorRed = Color(0xffeb8381); } diff --git a/alixby/lib/utils/MIcons.dart b/alixby/lib/utils/MIcons.dart index 73f916c..219b753 100644 --- a/alixby/lib/utils/MIcons.dart +++ b/alixby/lib/utils/MIcons.dart @@ -444,6 +444,10 @@ class MIcons { return ui; case 'weifa': return weifa; + case 'safebox': + return safebox; + case 'xuanzhuan': + return xuanzhuan; } return file_file; @@ -740,4 +744,6 @@ class MIcons { static const IconData file_xsl = IconData(0xe657, fontFamily: 'iconfont'); static const IconData ui = IconData(0xe600, fontFamily: 'iconfont'); static const IconData weifa = IconData(0xe601, fontFamily: 'iconfont'); + static const IconData safebox = IconData(0xe634, fontFamily: 'iconfont'); + static const IconData xuanzhuan = IconData(0xe68a, fontFamily: 'iconfont'); } diff --git a/alixby/lib/utils/MyBouncingScrollPhysics.dart b/alixby/lib/utils/MyBouncingScrollPhysics.dart new file mode 100644 index 0000000..7f786ff --- /dev/null +++ b/alixby/lib/utils/MyBouncingScrollPhysics.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/physics.dart'; + +class MyBouncingScrollPhysics extends BouncingScrollPhysics { + const MyBouncingScrollPhysics({ScrollPhysics? parent}) : super(parent: parent); + + @override + MyBouncingScrollPhysics applyTo(ScrollPhysics? ancestor) { + return MyBouncingScrollPhysics(parent: buildParent(ancestor)); + } + + @override + SpringDescription get spring => SpringDescription.withDampingRatio( + mass: 0.5, + stiffness: 300.0, // Increase this value as you wish. + ratio: 1.1, + ); +} + +class MyClampingScrollPhysics extends ClampingScrollPhysics { + const MyClampingScrollPhysics({ScrollPhysics? parent}) : super(parent: parent); + + @override + MyClampingScrollPhysics applyTo(ScrollPhysics? ancestor) { + return MyClampingScrollPhysics(parent: buildParent(ancestor)); + } + + @override + SpringDescription get spring => SpringDescription.withDampingRatio( + mass: 0.5, + stiffness: 300.0, // Increase this value as you wish. + ratio: 1.1, + ); +} diff --git a/alixby/lib/views/LoginDialog.dart b/alixby/lib/views/LoginDialog.dart new file mode 100644 index 0000000..748d017 --- /dev/null +++ b/alixby/lib/views/LoginDialog.dart @@ -0,0 +1,205 @@ +import 'dart:async'; +import 'package:alixby/api/AliLogin.dart'; +import 'package:alixby/states/Global.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:alixby/views/LoginDialogCookie.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:qr_flutter/qr_flutter.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +class LoginDialog extends StatefulWidget { + const LoginDialog({ + Key? key, + }) : super(key: key); + @override + _LoginDialogState createState() => _LoginDialogState(); +} + +class _LoginDialogState extends State { + void updateState(fn) { + if (mounted) { + setState(fn); + } + } + + String _qrcodeUrl = ""; + //每一次setState,都会触发执行这里 + Future _qrcodeCheck() async { + if (loadError || loadQrcode) return; + if (loadQrcode == false) { + _qrcodeUrl = await AliLogin.apiQrcodeGenerate(); + bool isLoadQrcode = _qrcodeUrl != ""; + updateState(() { + loadError = !isLoadQrcode; + loadQrcode = isLoadQrcode; + }); + } + } + + Future _qrcodeQuery() async { + if (loadQrcode == true) { + String result = await AliLogin.apiQrcodeQuery(); + if (result == "success") { + Global.userState.loadUser(true); + Navigator.of(context).pop('ok'); + } else if (result == "retry") { + updateState(() { + loadError = true; + loadQrcode = false; + }); + } + } + } + + Widget _buildFuture(BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + return Text(''); + case ConnectionState.active: + return Text(''); + case ConnectionState.waiting: + return Center( + child: CircularProgressIndicator(), + ); + case ConnectionState.done: + if (snapshot.hasError) { + return Text('网络错误'); + } else if (_qrcodeUrl == "") { + return Text('网络错误'); + } else { + return QrImage( + data: _qrcodeUrl, + version: QrVersions.auto, + size: 160, + gapless: false, + ); + } + default: + return Text(''); + } + } + + late Timer timer; + //初始化时需要先读取html数据 + bool loadHtml = false; + //是否显示二维码(不显示二维码就显示刷新按钮) + bool loadQrcode = false; + //第一次强制隐藏刷新按钮 + bool loadError = false; + //避免重复执行timer + bool loading = false; + + @override + void initState() { + super.initState(); + loadError = false; + loadHtml = false; + loadQrcode = false; + timer = Timer.periodic(Duration(milliseconds: 1500), (timer) { + if (loading) return; + loading = true; + try { + _qrcodeQuery(); + } catch (e) {} + loading = false; + }); + } + + @override + void dispose() { + timer.cancel(); + loadHtml = false; + loadQrcode = false; + super.dispose(); + } + + @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: 300, + width: 300, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.white, + ), + 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("请用阿里云盘 App 扫码登录", + style: TextStyle(fontSize: 20, color: MColors.textColor, fontFamily: "opposans"))), + Container( + width: 170, + height: 170, + child: Stack( + alignment: Alignment.center, + children: [ + FutureBuilder( + builder: _buildFuture, + future: _qrcodeCheck(), + ), + Container( + color: Color(0xeeffffff), + alignment: Alignment.center, + width: loadError ? 160 : 0, + height: 160, + child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + Text("二维码已失效"), + Padding(padding: EdgeInsets.only(top: 20)), + ElevatedButton( + child: Text("刷新二维码"), + onPressed: () { + updateState(() { + loadError = false; + loadQrcode = false; + }); + }, + ) + ])), + ], + )), + Container( + padding: EdgeInsets.only(top: 8), + child: TextButton( + child: + Text("使用Cookie登录", style: TextStyle(color: MColors.linkColor, fontFamily: "opposans")), + onPressed: () { + Navigator.of(context).pop('ok'); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: LoginDialogCookie(), + ); + }); + })), + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/views/LoginDialogCookie.dart b/alixby/lib/views/LoginDialogCookie.dart new file mode 100644 index 0000000..963dc6c --- /dev/null +++ b/alixby/lib/views/LoginDialogCookie.dart @@ -0,0 +1,260 @@ +import 'package:alixby/api/AliLogin.dart'; +import 'package:alixby/states/Global.dart'; +import 'package:alixby/utils/FileLinkifier.dart'; +import 'package:alixby/utils/Loading.dart'; +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.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:flutter_linkify/flutter_linkify.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; +import 'LoginDialog.dart'; + +class LoginDialogCookie extends StatelessWidget { + LoginDialogCookie({ + Key? key, + }) : super(key: key); + final TextEditingController controller = TextEditingController(); + + void onSubmitted(BuildContext context) { + String token = controller.text; + token = token.replaceAll('"', '').trim(); + if (token.length != 32) { + BotToast.showText(text: "refresh_token 应该是长度为32位的字符串!!", align: Alignment(0, 0)); + controller.clear(); + } else { + var fcHide = Loading.showLoading(); + AliLogin.apiTokenRefresh(token).then((value) { + fcHide(); + if (value == "success") { + Global.userState.loadUser(true); + BotToast.showText(text: "登录成功"); + Navigator.of(context).pop('ok'); + } else { + BotToast.showText(text: "登录失败请重试"); + } + }); + } + } + + @override + Widget build(BuildContext context) { + var textstyle = TextStyle(color: MColors.textColor, fontFamily: "opposans"); + return Material( + type: MaterialType.transparency, + child: MediaQuery( + data: MediaQuery.of(context) + .copyWith(textScaleFactor: double.parse(context.watch().setting.textScale)), + child: DefaultTextStyle( + //1.设置文本默认样式 + style: textstyle, + child: Center( + child: Container( + height: 400, + width: 460, + 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("请用阿里云盘网页版 Cookie 登录", + style: TextStyle(fontSize: 20, color: MColors.textColor, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 400, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(top: 4, bottom: 4), + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: + TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan(text: "点击观看 ==> ", style: textstyle), + WidgetSpan( + child: Linkify( + onOpen: (link) { + launch(Uri.encodeFull(link.url)); + }, + text: "操作录像", + linkifiers: [ + FileLinkifier( + "操作录像", + "https://p.pstatp.com/origin/pgc-image/cb86a7d7227449d481c32df6677f3461", + "") + ], + linkStyle: TextStyle( + fontSize: 14, + color: MColors.linkColor, + decoration: TextDecoration.none, + fontFamily: "opposans"))), + ]))), + Container( + margin: EdgeInsets.only(top: 4, bottom: 4), + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: + TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan(text: "第1步:点击登录云盘网页版 ==> ", style: textstyle), + WidgetSpan( + child: Linkify( + onOpen: (link) { + launch(Uri.encodeFull(link.url)); + }, + text: "aliyundrive.com", + linkifiers: [ + FileLinkifier( + "aliyundrive.com", + "https://www.aliyundrive.com/sign/in?spm=aliyundrive.index.0.0.2d836020dtzo9Z", + "") + ], + linkStyle: TextStyle( + fontSize: 14, + color: MColors.linkColor, + decoration: TextDecoration.none, + fontFamily: "opposans"))), + ]))), + Container( + margin: EdgeInsets.only(top: 4, bottom: 4), + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: + TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan(text: "第2步:按下键盘", style: textstyle), + TextSpan( + text: "F12", + style: TextStyle(color: Color(0xffdf5659), fontFamily: "opposans")), + TextSpan(text: "键,打开网页控制台", style: textstyle), + ]))), + Container( + margin: EdgeInsets.only(top: 4, bottom: 4), + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: + TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan(text: "第3步:单击复制下面命令,粘贴到控制台,并按下", style: textstyle), + TextSpan( + text: "回车", + style: TextStyle(color: Color(0xffdf5659), fontFamily: "opposans")), + TextSpan(text: "键", style: textstyle), + ]))), + Container( + margin: EdgeInsets.only(top: 4, bottom: 4), + child: Tooltip( + message: "点击自动复制", + child: OutlinedButton( + onPressed: () { + Clipboard.setData(ClipboardData( + text: 'JSON.parse(window.localStorage["token"]).refresh_token')); + BotToast.showText(text: "已复制", align: Alignment(0, 0)); + }, + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(400, 32))), + child: Text( + 'JSON.parse(window.localStorage["token"]).refresh_token', + style: TextStyle( + color: Colors.greenAccent.shade400, fontSize: 14, fontFamily: "opposans"), + textAlign: TextAlign.left, + ))), + ), + Container( + margin: EdgeInsets.only(top: 4, bottom: 4), + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + style: + TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + children: [ + TextSpan(text: "第4步:复制返回的32位字符串,粘贴到下面", style: textstyle), + ]))), + Stack( + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 60, maxWidth: 395), + child: TextField( + controller: controller, + maxLines: 1, + autocorrect: false, + enableSuggestions: false, + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), + cursorColor: MColors.inputBorderHover, + decoration: InputDecoration( + helperText: "例如:ea9876501fac462291618bbec834450f", + 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.inputBorderColor, + width: 1, + ), + ), + ), + onSubmitted: (value) { + onSubmitted(context); + }, + )), + Positioned.directional( + textDirection: TextDirection.rtl, + start: 0, + child: ElevatedButton( + onPressed: () { + onSubmitted(context); + }, + child: Text(" 登录 "), + style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 36))), + )), + ], + ), + ], + )), + Container( + padding: EdgeInsets.only(top: 28), + child: TextButton( + child: Text("扫码登录", style: TextStyle(color: MColors.linkColor, fontFamily: "opposans")), + onPressed: () { + Navigator.of(context).pop('ok'); + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return LoginDialog(); + }); + })), + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/views/PageLeft.dart b/alixby/lib/views/PageLeft.dart index cad95d5..3841bde 100644 --- a/alixby/lib/views/PageLeft.dart +++ b/alixby/lib/views/PageLeft.dart @@ -1,8 +1,8 @@ -import '../widgets/UserNavMenu.dart'; +import 'package:alixby/views/UserNavMenu.dart'; import 'package:hovering/hovering.dart'; -import '../widgets/UserNav.dart'; -import '../utils/MColors.dart'; +import 'package:alixby/views/UserNav.dart'; +import 'package:alixby/utils/MColors.dart'; import 'package:flutter/material.dart'; class PageLeft extends StatefulWidget { @@ -14,7 +14,6 @@ class _PageLeftState extends State { @override void initState() { super.initState(); - print('_PageLeftState initState'); } @override diff --git a/alixby/lib/views/PageLeftSetting.dart b/alixby/lib/views/PageLeftSetting.dart index e6e553c..d6a346c 100644 --- a/alixby/lib/views/PageLeftSetting.dart +++ b/alixby/lib/views/PageLeftSetting.dart @@ -1,9 +1,9 @@ -import '../utils/MIcons.dart'; +import 'package:alixby/utils/MIcons.dart'; -import '../utils/MColors.dart'; +import 'package:alixby/utils/MColors.dart'; import 'package:hovering/hovering.dart'; -import '../models/PageLeftRowItem.dart'; +import 'package:alixby/models/PageLeftRowItem.dart'; import 'package:flutter/material.dart'; class PageLeftSetting extends StatefulWidget { @@ -27,7 +27,6 @@ class _PageLeftSettingState extends State with AutomaticKeepAli @override void initState() { super.initState(); - print('_PageLeftSettingState initState'); } @override @@ -45,7 +44,7 @@ class _PageLeftSettingState extends State with AutomaticKeepAli alignment: Alignment.centerLeft, child: Text( "APP设置", - style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor), + style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor, fontFamily: "opposans"), )), Expanded( child: ListView.builder( @@ -83,7 +82,8 @@ class _PageLeftSettingState extends State with AutomaticKeepAli item.title, style: TextStyle( color: - selectedKey == item.key ? MColors.userNavMenuIconHover : MColors.pageLeftRowItemColor), + selectedKey == item.key ? MColors.userNavMenuIconHover : MColors.pageLeftRowItemColor, + fontFamily: "opposans"), ) ])))), ); diff --git a/alixby/lib/views/PageRight.dart b/alixby/lib/views/PageRight.dart index 2ba2c9a..975ea75 100644 --- a/alixby/lib/views/PageRight.dart +++ b/alixby/lib/views/PageRight.dart @@ -2,11 +2,11 @@ import 'package:alixby/states/Global.dart'; import 'package:alixby/states/UserState.dart'; import 'package:provider/provider.dart'; -import '../utils/MColors.dart'; +import 'package:alixby/utils/MColors.dart'; import 'package:flutter/material.dart'; -import 'PageRightRss.dart'; -import 'PageRightPan.dart'; -import 'PageRightDown.dart'; +import 'package:alixby/pagerss/PageRightRss.dart'; +import 'package:alixby/pagepan/PageRightPan.dart'; +import 'package:alixby/pagedown/PageRightDown.dart'; import 'PageRightSetting.dart'; class PageRight extends StatefulWidget { @@ -18,11 +18,10 @@ class _PageRightState extends State { @override void initState() { super.initState(); - print('_PageRightState initState'); } final PageController _pageController = PageController(initialPage: 0, keepPage: true); - final bodyList = [PageRightRss(), PageRightPan(), PageRightDown(), PageRightSetting()]; + final bodyList = [PageRightRss(), PageRightPan("box"), PageRightPan("xiangce"), PageRightDown(), PageRightSetting()]; final focusnode = FocusNode(); @override Widget build(BuildContext context) { diff --git a/alixby/lib/views/PageRightRssHelp.dart b/alixby/lib/views/PageRightRssHelp.dart deleted file mode 100644 index 4e51663..0000000 --- a/alixby/lib/views/PageRightRssHelp.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:alixby/utils/FileLinkifier.dart'; -import 'package:alixby/utils/MColors.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_linkify/flutter_linkify.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class PageRightRssHelp extends StatefulWidget { - @override - _PageRightRssHelpState createState() => _PageRightRssHelpState(); -} - -class _PageRightRssHelpState extends State { - @override - void initState() { - super.initState(); - print('_PageRightRssHelpState initState'); - } - - @override - // ignore: must_call_super - Widget build(BuildContext context) { - return Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("此功能正在开发中-帮助"), - Padding(padding: EdgeInsets.only(top: 18)), - Text("这是一个正在开发中的版本,"), - Text("遇到BUG不要慌,反馈给我就好"), - Padding(padding: EdgeInsets.only(top: 18)), - Linkify( - onOpen: (link) { - launch(Uri.encodeFull(link.url)); - }, - text: "aliyundrive.com", - linkifiers: [ - FileLinkifier( - "https://github.com/liupan1890/aliyunpan", "https://github.com/liupan1890/aliyunpan/issues") - ], - linkStyle: TextStyle(fontSize: 14, color: MColors.linkColor, decoration: TextDecoration.none)) - ])); - } -} diff --git a/alixby/lib/views/PageRightRssSearch.dart b/alixby/lib/views/PageRightRssSearch.dart deleted file mode 100644 index 26207f4..0000000 --- a/alixby/lib/views/PageRightRssSearch.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:alixby/utils/FileLinkifier.dart'; -import 'package:alixby/utils/MColors.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_linkify/flutter_linkify.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class PageRightRssSearch extends StatefulWidget { - @override - _PageRightRssSearchState createState() => _PageRightRssSearchState(); -} - -class _PageRightRssSearchState extends State { - @override - void initState() { - super.initState(); - print('_PageRightRssSearchState initState'); - } - - @override - // ignore: must_call_super - Widget build(BuildContext context) { - return Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("此功能正在开发中-聚合搜索"), - Padding(padding: EdgeInsets.only(top: 18)), - Text("这是一个正在开发中的版本,"), - Text("遇到BUG不要慌,反馈给我就好"), - Padding(padding: EdgeInsets.only(top: 18)), - Linkify( - onOpen: (link) { - launch(Uri.encodeFull(link.url)); - }, - text: "aliyundrive.com", - linkifiers: [ - FileLinkifier( - "https://github.com/liupan1890/aliyunpan", "https://github.com/liupan1890/aliyunpan/issues") - ], - linkStyle: TextStyle(fontSize: 14, color: MColors.linkColor, decoration: TextDecoration.none)) - ])); - } -} diff --git a/alixby/lib/views/PageRightSetting.dart b/alixby/lib/views/PageRightSetting.dart index 26635d7..9fc3c12 100644 --- a/alixby/lib/views/PageRightSetting.dart +++ b/alixby/lib/views/PageRightSetting.dart @@ -1,5 +1,6 @@ import 'package:alixby/states/Global.dart'; import 'package:alixby/states/SettingState.dart'; +import 'package:alixby/states/UserState.dart'; import 'package:alixby/utils/FileLinkifier.dart'; import 'package:alixby/utils/MColors.dart'; import 'package:alixby/utils/MIcons.dart'; @@ -18,14 +19,19 @@ class _PageRightSettingState extends State with AutomaticKeepA @override void initState() { super.initState(); - print('_PageRightSettingState initState'); } final verticalScroll = ScrollController(); + @override + void dispose() { + verticalScroll.dispose(); + super.dispose(); + } @override // ignore: must_call_super Widget build(BuildContext context) { + var userName = context.watch().userName; return Column( children: [ Container( @@ -38,9 +44,12 @@ class _PageRightSettingState extends State with AutomaticKeepA child: Linkify( onOpen: null, text: "APP设置", - linkifiers: [FileLinkifier("APP设置", "")], - linkStyle: - TextStyle(fontSize: 13, color: MColors.linkColor, decoration: TextDecoration.none))))), + linkifiers: [FileLinkifier("APP设置", "", "")], + linkStyle: TextStyle( + fontSize: 13, + color: MColors.linkColor, + decoration: TextDecoration.none, + fontFamily: "opposans"))))), Container(height: 1, width: double.infinity, color: MColors.pageRightBorderColor), Expanded( child: Scrollbar( @@ -62,14 +71,26 @@ class _PageRightSettingState extends State with AutomaticKeepA Padding(padding: EdgeInsets.only(top: 32)), Container( width: 400, - child: Text("∷界面设置"), + child: Text("∷界面设置", + style: TextStyle( + fontFamily: "opposans", + decoration: TextDecoration.underline, + decorationStyle: TextDecorationStyle.solid, + decorationThickness: 2, + decorationColor: Colors.yellowAccent.shade700)), ), Padding(padding: EdgeInsets.only(top: 8)), _buildTextSize(context), Padding(padding: EdgeInsets.only(top: 32)), Container( width: 400, - child: Text("∷下载文件保存位置"), + child: Text("∷下载文件保存位置", + style: TextStyle( + fontFamily: "opposans", + decoration: TextDecoration.underline, + decorationStyle: TextDecorationStyle.solid, + decorationThickness: 2, + decorationColor: Colors.yellowAccent.shade700)), ), Padding(padding: EdgeInsets.only(top: 8)), _buildSavePath(), @@ -77,20 +98,63 @@ class _PageRightSettingState extends State with AutomaticKeepA Padding(padding: EdgeInsets.only(top: 24)), Container( width: 400, - child: Text("∷全局下载速度限制"), + child: Text("∷全局下载速度限制", + style: TextStyle( + fontFamily: "opposans", + decoration: TextDecoration.underline, + decorationStyle: TextDecorationStyle.solid, + decorationThickness: 2, + decorationColor: Colors.yellowAccent.shade700)), ), Padding(padding: EdgeInsets.only(top: 8)), _buildDownSpeed(), Padding(padding: EdgeInsets.only(top: 32)), Container( width: 400, - child: Text("∷同时上传/下载任务数"), + child: Text("∷同时上传/下载任务数", + style: TextStyle( + fontFamily: "opposans", + decoration: TextDecoration.underline, + decorationStyle: TextDecorationStyle.solid, + decorationThickness: 2, + decorationColor: Colors.yellowAccent.shade700)), ), Padding(padding: EdgeInsets.only(top: 8)), _buildDownMax(context), - Padding(padding: EdgeInsets.only(top: 24)), + Padding(padding: EdgeInsets.only(top: 8)), _buildSha1Check(context), Padding(padding: EdgeInsets.only(top: 24)), + Container( + width: 400, + child: Text("∷账号设置", + style: TextStyle( + fontFamily: "opposans", + decoration: TextDecoration.underline, + decorationStyle: TextDecorationStyle.solid, + decorationThickness: 2, + decorationColor: Colors.yellowAccent.shade700)), + ), + Padding(padding: EdgeInsets.only(top: 8)), + Container( + width: 400, + child: Row(children: [ + Text( + userName, + style: TextStyle( + color: MColors.userNavColor, + fontSize: 14, + fontWeight: FontWeight.bold, + fontFamily: "opposans"), + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + ), + Padding(padding: EdgeInsets.only(left: 16)), + OutlinedButton( + child: Text("退出登录"), + onPressed: () => Global.userState.logoffUser(), + ), + ])), ], ), )))), @@ -114,18 +178,18 @@ class _PageRightSettingState extends State with AutomaticKeepA child: Stack( children: [ ConstrainedBox( - constraints: BoxConstraints(maxHeight: 56), + constraints: BoxConstraints(maxHeight: 60), child: TextField( readOnly: true, controller: Global.settingState.savePathController, maxLines: 1, autocorrect: false, enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), cursorColor: MColors.inputBorderHover, decoration: InputDecoration( helperText: "选择一个文件夹,所有文件默认都下载到此文件夹内", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), + helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( @@ -168,12 +232,15 @@ class _PageRightSettingState extends State with AutomaticKeepA selectedTileColor: Colors.transparent, checkColor: Colors.white, activeColor: MColors.inputBorderHover, - title: Text( - '每次下载都提示我选择保存位置', - style: TextStyle( - fontSize: 14, - color: Global.settingState.setting.savePathCheck ? MColors.inputBorderHover : MColors.textColor), - ), + title: Tooltip( + message: '不推荐勾选,默认按照网盘全路径保存,勾选后可以自己选择路径', + child: Text( + '每次下载都提示我选择保存位置', + style: TextStyle( + fontSize: 14, + color: Global.settingState.setting.savePathCheck ? MColors.inputBorderHover : MColors.textColor, + fontFamily: "opposans"), + )), value: (context.watch().setting.savePathCheck ? true : null), selected: context.watch().setting.savePathCheck, onChanged: (bool? value) { @@ -188,17 +255,17 @@ class _PageRightSettingState extends State with AutomaticKeepA child: Stack( children: [ ConstrainedBox( - constraints: BoxConstraints(maxHeight: 56), + constraints: BoxConstraints(maxHeight: 60), child: TextField( controller: Global.settingState.downSpeedController, maxLines: 1, autocorrect: false, enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"), cursorColor: MColors.inputBorderHover, decoration: InputDecoration( helperText: "按照 '你填的' MB/s 限制最大下载速度,填0不限速", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), + helperStyle: TextStyle(fontSize: 13, color: MColors.textColor, fontFamily: "opposans"), contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), focusedBorder: OutlineInputBorder( borderSide: BorderSide( @@ -248,6 +315,7 @@ class _PageRightSettingState extends State with AutomaticKeepA ), child: DropdownButton( isDense: true, + style: TextStyle(color: MColors.textColor, fontFamily: "opposans"), itemHeight: 32, //需要修改kMinInteractiveDimension =32 elevation: 0, value: context.watch().setting.downMax, @@ -260,7 +328,8 @@ class _PageRightSettingState extends State with AutomaticKeepA .map>((String value) { return DropdownMenuItem( value: value, - child: Text('同时上传/下载' + value + '个文件', style: TextStyle(fontSize: 14, color: MColors.textColor)), + child: Text('同时上传/下载' + value + '个文件', + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans")), ); }).toList(), )))); @@ -279,12 +348,15 @@ class _PageRightSettingState extends State with AutomaticKeepA selectedTileColor: Colors.transparent, checkColor: Colors.white, activeColor: MColors.inputBorderHover, - title: Text( - '每次下载完成后校验文件完整性(sha1)', - style: TextStyle( - fontSize: 14, - color: Global.settingState.setting.downSha1Check ? MColors.inputBorderHover : MColors.textColor), - ), + title: Tooltip( + message: '不推荐勾选,会占用大量CPU', + child: Text( + '每次下载完成后校验文件完整性(sha1)', + style: TextStyle( + fontSize: 14, + color: Global.settingState.setting.downSha1Check ? MColors.inputBorderHover : MColors.textColor, + fontFamily: "opposans"), + )), value: (context.watch().setting.downSha1Check ? true : null), selected: context.watch().setting.downSha1Check, onChanged: (bool? value) { @@ -312,6 +384,7 @@ class _PageRightSettingState extends State with AutomaticKeepA ), child: DropdownButton( isDense: true, + style: TextStyle(color: MColors.textColor, fontFamily: "opposans"), itemHeight: 32, //需要修改kMinInteractiveDimension =32 elevation: 0, value: context.watch().setting.textScale.toString(), @@ -323,13 +396,16 @@ class _PageRightSettingState extends State with AutomaticKeepA items: [ DropdownMenuItem( value: "1.0", - child: Text('正常文字大小', style: TextStyle(fontSize: 14, color: MColors.textColor))), + child: Text('正常文字大小', + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"))), DropdownMenuItem( value: "1.1", - child: Text('较大文字大小', style: TextStyle(fontSize: 15, color: MColors.textColor))), + child: Text('较大文字大小', + style: TextStyle(fontSize: 15, color: MColors.textColor, fontFamily: "opposans"))), DropdownMenuItem( value: "1.2", - child: Text('最大文字大小', style: TextStyle(fontSize: 16, color: MColors.textColor))), + child: Text('最大文字大小', + style: TextStyle(fontSize: 16, color: MColors.textColor, fontFamily: "opposans"))), ]))), Padding(padding: EdgeInsets.only(left: 24)), UnconstrainedBox( @@ -352,8 +428,6 @@ class _PageRightSettingState extends State with AutomaticKeepA underline: Container(height: 0), dropdownColor: MColors.userNavMenuBG, onChanged: (String? newValue) { - BotToast.showText(text: "此功能还在开发中"); - //return; if (newValue != null) { Global.settingState.theme(newValue); BotToast.showText(text: "皮肤模式需要退出程序重新打开后才能生效", duration: Duration(seconds: 10)); @@ -362,20 +436,16 @@ class _PageRightSettingState extends State with AutomaticKeepA items: [ DropdownMenuItem( value: "day", - child: Text('浅色模式', style: TextStyle(fontSize: 14, color: MColors.textColor))), + child: Text('浅色模式', + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"))), DropdownMenuItem( value: "dark", - child: Text('深色模式', style: TextStyle(fontSize: 14, color: MColors.textColor))), + child: Text('深色模式', + style: TextStyle(fontSize: 14, color: MColors.textColor, fontFamily: "opposans"))), ]))), ])); } @override bool get wantKeepAlive => true; - - @override - void dispose() { - verticalScroll.dispose(); - super.dispose(); - } } diff --git a/alixby/lib/views/UserNav.dart b/alixby/lib/views/UserNav.dart new file mode 100644 index 0000000..ed53e18 --- /dev/null +++ b/alixby/lib/views/UserNav.dart @@ -0,0 +1,118 @@ +import 'package:alixby/states/Global.dart'; +import 'package:alixby/views/LoginDialog.dart'; +import 'package:extended_image/extended_image.dart'; +import 'package:hovering/hovering.dart'; + +import 'package:alixby/states/UserState.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/utils/MIcons.dart'; + +import 'package:alixby/utils/MColors.dart'; +import 'package:flutter/material.dart'; + +class UserNav extends StatefulWidget { + UserNav({required Key key}) : super(key: key); + @override + _UserNavState createState() => _UserNavState(); +} + +class _UserNavState extends State { + var userFaceTryTime = 0; + + @override + Widget build(BuildContext context) { + var userFace = context.watch().userFace; + var userName = context.watch().userName; + return Row( + children: [ + userFace == "" + ? Image.asset("assets/images/app.png", width: 24, fit: BoxFit.cover) + : ExtendedImage.network( + userFace, + width: 24, + height: 24, + fit: BoxFit.cover, + cache: true, + retries: 1, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(5.0)), + loadStateChanged: (ExtendedImageState state) { + switch (state.extendedImageLoadState) { + case LoadState.loading: + return null; + case LoadState.completed: + userFaceTryTime = 0; + return ExtendedRawImage(image: state.extendedImageInfo?.image); + case LoadState.failed: + userFaceTryTime++; + if (userFaceTryTime < 3) { + print("retry userface"); + Future.delayed(Duration(milliseconds: 2000), () { + Global.userState.loadUser(false); + }); + } + return Image.asset("assets/images/app.png", width: 24, fit: BoxFit.cover); + } + }, + //cancelToken: cancellationToken, + ), + //Image.asset("assets/images/app.png", width: 24, fit: BoxFit.cover), + + Padding(padding: EdgeInsets.only(left: 6)), + Expanded( + child: InkWell( + child: Text( + userName, + style: TextStyle( + color: MColors.userNavColor, fontSize: 16, fontWeight: FontWeight.bold, fontFamily: "opposans"), + maxLines: 1, + softWrap: false, + overflow: TextOverflow.clip, + ), + onTap: () async { + if (!Global.userState.isLogin) { + //先检查一遍是否登录 + await Global.userState.loadUser(true); + } else { + //已经登录,就是刷新用户信息 + Global.userState.loadUser(false); + } + + if (Global.userState.isLogin) { + //todo::显示用户信息 + } else { + showDialog( + barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 + context: context, + builder: (context) { + return WillPopScope( + onWillPop: () async => false, //关键代码 + child: LoginDialog()); + }); + } + })), + + Padding(padding: EdgeInsets.only(left: 8)), + Material( + color: Colors.transparent, + shape: CircleBorder(), + child: SizedBox( + width: userName == "点击登录" ? 0 : 26, + height: 26.0, + child: HoverContainer( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG), + hoverDecoration: + BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.userNavMenuBGHover), + child: IconButton( + iconSize: 22, + padding: EdgeInsets.all(0), + color: MColors.userNavMenuIcon, + icon: Icon(MIcons.setting), + onPressed: () => Global.userState.updatePageIndex(4), + tooltip: "APP设置", + )))), + Padding(padding: EdgeInsets.only(left: 5)), + ], + ); + } +} diff --git a/alixby/lib/widgets/UserNavMenu.dart b/alixby/lib/views/UserNavMenu.dart similarity index 76% rename from alixby/lib/widgets/UserNavMenu.dart rename to alixby/lib/views/UserNavMenu.dart index 826e022..3d5ede8 100644 --- a/alixby/lib/widgets/UserNavMenu.dart +++ b/alixby/lib/views/UserNavMenu.dart @@ -1,16 +1,16 @@ import 'package:alixby/states/Global.dart'; import 'package:alixby/states/UserState.dart'; -import '../utils/MIcons.dart'; +import 'package:alixby/utils/MIcons.dart'; import 'package:hovering/hovering.dart'; -import '../views/PageLeftPan.dart'; +import 'package:alixby/pagepan/PageLeftPan.dart'; -import '../utils/MColors.dart'; +import 'package:alixby/utils/MColors.dart'; -import '../views/PageLeftRss.dart'; -import '../views/PageLeftDown.dart'; -import '../views/PageLeftSetting.dart'; +import 'package:alixby/pagerss/PageLeftRss.dart'; +import 'package:alixby/pagedown/PageLeftDown.dart'; +import 'package:alixby/views/PageLeftSetting.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -20,7 +20,7 @@ class UserNavMenu extends StatefulWidget { } class _UserNavMenuState extends State { - final bodyList = [PageLeftRss(), PageLeftPan(), PageLeftDown(), PageLeftSetting()]; + final bodyList = [PageLeftRss(), PageLeftPan('box'), PageLeftPan('xiangce'), PageLeftDown(), PageLeftSetting()]; void onTap(int index) { Global.userState.updatePageIndex(index); @@ -51,7 +51,7 @@ class _UserNavMenuState extends State { @override Widget build(BuildContext context) { - var index = context.watch().userNavPageIndex; + var pageindex = context.watch().userNavPageIndex; return Column(children: [ Container( alignment: Alignment.topLeft, @@ -60,13 +60,13 @@ class _UserNavMenuState extends State { child: Row( children: [ Padding(padding: EdgeInsets.only(left: 8)), - _buildMenu(index, 0, MIcons.rss, "Rss"), + _buildMenu(pageindex, 0, MIcons.rss, "Rss"), Expanded(child: Padding(padding: EdgeInsets.only(left: 8))), - _buildMenu(index, 1, MIcons.ali, "云盘文件"), + _buildMenu(pageindex, 1, MIcons.ali, "云盘"), Expanded(child: Padding(padding: EdgeInsets.only(left: 8))), - _buildMenu(index, 2, MIcons.download, "下载上传"), + _buildMenu(pageindex, 2, MIcons.file_img, "相册"), Expanded(child: Padding(padding: EdgeInsets.only(left: 8))), - _buildMenu(index, 3, MIcons.setting, "APP设置"), + _buildMenu(pageindex, 3, MIcons.download, "下载上传"), Padding(padding: EdgeInsets.only(left: 8)), ], ))), diff --git a/alixby/lib/views/VerDialog.dart b/alixby/lib/views/VerDialog.dart new file mode 100644 index 0000000..4f48ce9 --- /dev/null +++ b/alixby/lib/views/VerDialog.dart @@ -0,0 +1,59 @@ +import 'package:alixby/utils/MColors.dart'; +import 'package:alixby/utils/MIcons.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:provider/provider.dart'; +import 'package:alixby/states/SettingState.dart'; + +class VerDialog extends StatelessWidget { + const VerDialog({ + Key? key, + }) : super(key: key); + + @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: 200, + width: 460, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.white, + ), + 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("有新版本发布了", + style: + TextStyle(fontSize: 20, color: MColors.textColor, height: 0, fontFamily: "opposans"))), + Container(padding: EdgeInsets.only(top: 20)), + Container( + width: 380, + padding: EdgeInsets.only(top: 20), + child: Text("!"), + ), + ], + ), + )), + ))); + } +} diff --git a/alixby/lib/widgets/CreatDirDialog.dart b/alixby/lib/widgets/CreatDirDialog.dart deleted file mode 100644 index 5fabdd4..0000000 --- a/alixby/lib/widgets/CreatDirDialog.dart +++ /dev/null @@ -1,110 +0,0 @@ -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:bot_toast/bot_toast.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -class CreatDirDialog extends StatelessWidget { - CreatDirDialog({ - Key? key, - }) : super(key: key); - final TextEditingController controller = TextEditingController(); - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 200, - width: 460, - 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("新建文件夹", style: TextStyle(fontSize: 20, color: MColors.textColor))), - Container( - width: 380, - margin: EdgeInsets.only(top: 24), - child: Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints(maxHeight: 56, maxWidth: 375), - child: TextField( - controller: controller, - maxLines: 1, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: true, - decoration: InputDecoration( - helperText: "文件夹名不要有特殊字符:<>!:*?\\/.'\"", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderHover, - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderColor, - width: 1, - ), - ), - ), - )), - Positioned.directional( - textDirection: TextDirection.rtl, - start: 0, - child: ElevatedButton( - onPressed: () { - String dirname = controller.text; - dirname = dirname.replaceAll('"', '').trim(); - - var fcHide = Loading.showLoading(); - var parentid = Global.panFileState.pageRightDirKey; - AliFile.apiCreatForder(parentid, dirname).then((value) { - fcHide(); - if (value == "success") { - Global.panTreeState.pageRefreshNode(); - BotToast.showText(text: "创建成功"); - Navigator.of(context).pop('ok'); - } else { - BotToast.showText(text: "创建失败请重试"); - } - }); - }, - child: Text(" 创建 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - )), - ], - ), - ), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/CreatMiaoChuanBackDialog.dart b/alixby/lib/widgets/CreatMiaoChuanBackDialog.dart deleted file mode 100644 index a4bbb88..0000000 --- a/alixby/lib/widgets/CreatMiaoChuanBackDialog.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.dart'; -import 'package:bot_toast/bot_toast.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; - -// ignore: must_be_immutable -class CreatMiaoChuanBackDialog extends StatelessWidget { - CreatMiaoChuanBackDialog({Key? key, required this.link}) : super(key: key) { - controller.text = link; - } - String link = ""; - final TextEditingController controller = TextEditingController(); - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 200, - width: 460, - 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("新建秒传短链接", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0))), - Container( - width: 380, - height: 120, - margin: EdgeInsets.only(top: 24), - child: Stack( - children: [ - TextField( - controller: controller, - maxLines: 2, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: false, - decoration: InputDecoration( - helperText: "秒传短链接创建成功,复制后发出去吧", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - 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, - ), - ), - ), - ), - Positioned.directional( - textDirection: TextDirection.rtl, - start: 0, - top: 80, - child: ElevatedButton( - onPressed: () { - String dirname = controller.text; - dirname = dirname.replaceAll('"', '').trim(); - Clipboard.setData(ClipboardData(text: dirname)); - BotToast.showText(text: "已复制"); - }, - child: Text(" 复制短链接 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - )), - Positioned.directional( - textDirection: TextDirection.ltr, - start: 0, - top: 80, - child: OutlinedButton( - onPressed: () { - String dirname = controller.text; - dirname = dirname.replaceAll('"', '').trim(); - - Clipboard.setData(ClipboardData(text: dirname)); - BotToast.showText(text: "已复制"); - }, - child: Text(" 复制直链(aliyun://....) "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - )), - ], - ), - ), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/CreatMiaoChuanDialog.dart b/alixby/lib/widgets/CreatMiaoChuanDialog.dart deleted file mode 100644 index fc2c451..0000000 --- a/alixby/lib/widgets/CreatMiaoChuanDialog.dart +++ /dev/null @@ -1,315 +0,0 @@ -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/widgets/CreatMiaoChuanBackDialog.dart'; -import 'package:bot_toast/bot_toast.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; - -// ignore: must_be_immutable -class CreatMiaoChuanDialog extends StatefulWidget { - CreatMiaoChuanDialog({Key? key, required this.parentid, required this.filelist}) : super(key: key); - String parentid = ""; - List filelist = []; - - @override - _CreatMiaoChuanDialogState createState() => _CreatMiaoChuanDialogState(); -} - -class _CreatMiaoChuanDialogState extends State { - final TextEditingController pwdcontroller = TextEditingController(); - final TextEditingController jianjiecontroller = TextEditingController(); - String outDay = "0"; - String outSave = "0"; - bool isPublic = false; - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 440, - width: 500, - 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("新建秒传短链接", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0))), - Container( - padding: EdgeInsets.only(left: 20, right: 20), - alignment: Alignment.topLeft, - child: Column(children: [ - Padding(padding: EdgeInsets.only(top: 32)), - Container( - alignment: Alignment.topLeft, - child: Text("为选中的 " + widget.filelist.length.toString() + " 个文件/文件夹创建一条秒传短链接"), - ), - Padding(padding: EdgeInsets.only(top: 24)), - _buildCanShu(context), - Padding(padding: EdgeInsets.only(top: 24)), - TextField( - controller: jianjiecontroller, - maxLines: 1, - maxLength: 40, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: false, - decoration: InputDecoration( - hintText: "这里可以空着,也可以备注一句话", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderHover, - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderColor, - width: 1, - ), - ), - ), - ), - Container( - padding: EdgeInsets.only(right: 8), - alignment: Alignment.topLeft, - child: CheckboxListTile( - tristate: true, - dense: true, - tileColor: Colors.transparent, - contentPadding: EdgeInsets.all(0), - selectedTileColor: Colors.transparent, - checkColor: Colors.white, - activeColor: MColors.inputBorderHover, - title: Text( - '是否把链接公布到聚合搜索中?(默认否)', - style: TextStyle( - fontSize: 14, color: isPublic ? MColors.inputBorderHover : MColors.textColor), - ), - value: (isPublic ? true : null), - selected: isPublic, - onChanged: (bool? value) { - isPublic = !isPublic; - setState(() {}); - }, - )), - Padding(padding: EdgeInsets.only(top: 48)), - Container( - alignment: Alignment.topLeft, - child: Text("密码可以为空(不设置密码),或是4位数字字母组合(区分大小写)", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - Container( - alignment: Alignment.topLeft, - child: Text("选中了文件夹时,会自动遍历全部子文件,可能会耗时很长", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - Container( - alignment: Alignment.topLeft, - child: Text("短链接举例:https://xby.writeas.com/?t=XXXXXXXX", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - Container( - alignment: Alignment.topLeft, - child: RichText( - textAlign: TextAlign.left, - text: TextSpan( - style: TextStyle(fontSize: 13, color: MColors.pageLeftRowHeadColor), - children: [ - TextSpan(text: "隐私警告:", style: TextStyle(color: Color(0xffdf5659), fontSize: 16)), - TextSpan( - text: "创建时会把(sha1|size|name)同步到服务器!\n", - style: TextStyle(color: MColors.pageLeftRowHeadColor)), - TextSpan(text: "请不要分享任何 ", style: TextStyle(color: MColors.pageLeftRowHeadColor)), - TextSpan(text: "个人文件、重要文件、隐私文件等等!!", style: TextStyle(color: Color(0xccdf5659))), - ])), - ), - ])), - ], - ), - )), - )); - } - - Widget _buildCanShu(BuildContext context) { - return Container( - alignment: Alignment.topLeft, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - UnconstrainedBox( - child: Container( - height: 30, - padding: EdgeInsets.only(left: 7, right: 5), - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(3.0), //3像素圆角 - border: Border.all( - color: MColors.inputBorderColor, - width: 1.0, - ), - ), - child: DropdownButton( - isDense: true, - itemHeight: 32, - elevation: 0, - value: outDay, - underline: Container(height: 0), - dropdownColor: MColors.userNavMenuBG, - onChanged: (String? newValue) { - if (newValue != null) { - outDay = newValue; - setState(() {}); - print(newValue); - } - }, - items: [ - DropdownMenuItem( - value: "0", child: Text('永久有效', style: TextStyle(fontSize: 14, color: MColors.textColor))), - DropdownMenuItem( - value: "31", - child: Text('31天后失效', style: TextStyle(fontSize: 14, color: MColors.textColor))), - DropdownMenuItem( - value: "7", child: Text('7天后失效', style: TextStyle(fontSize: 14, color: MColors.textColor))), - DropdownMenuItem( - value: "1", child: Text('1天后失效', style: TextStyle(fontSize: 14, color: MColors.textColor))), - ]))), - Padding(padding: EdgeInsets.only(left: 24)), - UnconstrainedBox( - child: Container( - height: 30, - padding: EdgeInsets.only(left: 7, right: 5), - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(3.0), //3像素圆角 - border: Border.all( - color: MColors.inputBorderColor, - width: 1.0, - ), - ), - child: DropdownButton( - isDense: true, - itemHeight: 32, - elevation: 0, - value: outSave, - underline: Container(height: 0), - dropdownColor: MColors.userNavMenuBG, - onChanged: (String? newValue) { - if (newValue != null) { - outSave = newValue; - setState(() {}); - print(newValue); - } - }, - items: [ - DropdownMenuItem( - value: "0", child: Text('不限次数', style: TextStyle(fontSize: 14, color: MColors.textColor))), - DropdownMenuItem( - value: "100", - child: Text('可转存100次', style: TextStyle(fontSize: 14, color: MColors.textColor))), - DropdownMenuItem( - value: "50", - child: Text('可转存50次', style: TextStyle(fontSize: 14, color: MColors.textColor))), - DropdownMenuItem( - value: "10", - child: Text('可转存10次', style: TextStyle(fontSize: 14, color: MColors.textColor))), - ]))), - Padding(padding: EdgeInsets.only(left: 24)), - Expanded( - child: ConstrainedBox( - constraints: BoxConstraints(maxHeight: 56, maxWidth: 20), - child: TextField( - controller: pwdcontroller, - maxLines: 1, - maxLength: 4, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: false, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp("[0-9a-zA-Z]")), //只允许输入数字字母 - ], - decoration: InputDecoration( - hintText: "无", - helperText: "密码", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - contentPadding: EdgeInsets.symmetric(vertical: 4, 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)), - ElevatedButton( - onPressed: () { - String password = pwdcontroller.text; - if (password != "" && password.length != 4) { - BotToast.showText(text: "密码必须是空的或者是4位数字字母组合", align: Alignment(0, 0)); - return; - } - String jianjie = jianjiecontroller.text; - - var fcHide = Loading.showLoading(); - - Linker.goLinkCreat(jianjie, isPublic, password, outDay, outSave, widget.parentid, widget.filelist) - .then((value) { - fcHide(); - if (value.indexOf("xby") > 0) { - Navigator.of(context).pop('ok'); - BotToast.showText(text: "创建成功"); - Global.pageRssMiaoChuanState.refreshLink(); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: CreatMiaoChuanBackDialog(link: value)); - }); - } else { - BotToast.showText(text: "创建失败:" + value); - } - }); - }, - child: Text("创建短链接"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - ), - ], - ), - ); - } -} diff --git a/alixby/lib/widgets/DownFileList.dart b/alixby/lib/widgets/DownFileList.dart deleted file mode 100644 index c04aec9..0000000 --- a/alixby/lib/widgets/DownFileList.dart +++ /dev/null @@ -1,283 +0,0 @@ -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:bot_toast/bot_toast.dart'; -import 'package:flutter/rendering.dart'; -import 'package:gradient_widgets/gradient_widgets.dart'; -import 'package:hovering/hovering.dart'; -import 'package:provider/provider.dart'; -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.dart'; -import 'package:flutter/material.dart'; - -class DownFileList extends StatefulWidget { - @override - _DownFileListState createState() => _DownFileListState(); -} - -class _DownFileListState extends State { - @override - void initState() { - super.initState(); - print('_DownFileListState initState'); - } - - @override - void dispose() { - verticalScroll.dispose(); - super.dispose(); - } - - final verticalScroll = ScrollController(); - final GlobalKey fileConKey = GlobalKey(); - @override - Widget build(BuildContext context) { - return Container( - key: fileConKey, - width: double.infinity, - decoration: BoxDecoration(border: Border(top: BorderSide(width: 1, color: MColors.pageRightBorderColor))), - alignment: Alignment.topLeft, - child: Scrollbar( - controller: verticalScroll, - isAlwaysShown: true, - showTrackOnHover: true, - thickness: 9, - hoverThickness: 9, - child: Row( - children: [ - Expanded( - child: ListView.builder( - controller: verticalScroll, - shrinkWrap: false, - primary: false, - addSemanticIndexes: false, - addAutomaticKeepAlives: true, - addRepaintBoundaries: true, - scrollDirection: Axis.vertical, - physics: ClampingScrollPhysics(), - itemExtent: 60, - itemCount: context.watch().pageRightDownList.length, - itemBuilder: _buildList, - )), - Container(width: 16), - ], - ))); - } - - //static BoxDecoration decoration = BoxDecoration(color: Color(0xfff7f8fa), border: border); - - static Padding padding4 = Padding(padding: EdgeInsets.only(left: 4)); - static Padding padding12 = Padding(padding: EdgeInsets.only(left: 12)); - static Padding padding16 = Padding(padding: EdgeInsets.only(left: 16)); - static Padding padding22 = Padding(padding: EdgeInsets.only(left: 22)); - TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor); - SizedBox downBox = SizedBox(width: 40, height: 40, child: Icon(MIcons.download, color: MColors.iconDown)); - SizedBox downBoxed = SizedBox(width: 40, height: 40, child: Icon(MIcons.download, color: MColors.iconSelected)); - 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 onTapFile(String key) { - Global.pageDownState.pageSelectFile(key); - print('选中文件'); - } - - static onTapBtn(String button, String key, String downPage) async { - print('点击按钮'); - var result = ""; - if (downPage == "downing") { - if (button == "forder") { - result = await Downloader.goDowningForder(key); - } else { - if (button == "start") result = await Downloader.goDowningStart(key); - if (button == "stop") result = await Downloader.goDowningStop(key); - if (button == "delete") result = await Downloader.goDowningDelete(key); - Global.pageDownState.refreshDownByTimer(false); //触发刷新 - } - } - if (downPage == "downed") { - if (button == "forder") { - result = await Downloader.goDownedForder(key); - } else { - if (button == "delete") result = await Downloader.goDownedDelete(key); - Global.pageDownState.refreshDownByTimer(false); //触发刷新 - } - } else if (downPage == "uploading") { - if (button == "forder") { - result = await Uploader.goUploadingForder(key); - } else { - if (button == "start") result = await Uploader.goUploadingStart(key); - if (button == "stop") result = await Uploader.goUploadingStop(key); - if (button == "delete") result = await Uploader.goUploadingDelete(key); - Global.pageDownState.refreshDownByTimer(false); //触发刷新 - } - } else if (downPage == "upload") { - if (button == "forder") { - result = await Uploader.goUploadForder(key); - } else { - if (button == "delete") result = await Uploader.goUploadDelete(key); - Global.pageDownState.refreshDownByTimer(false); //触发刷新 - } - } - - if (result != "success") { - BotToast.showText(text: "操作失败:" + result); - } - } - - Widget _buildList(BuildContext context, int index) { - var item = Global.pageDownState.pageRightDownList[index]; - var decoration = BoxDecoration( - color: MColors.pageRightFileBG, - border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); - var decorations = BoxDecoration( - color: MColors.pageRightFileBGSelect, - border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); - - var hoverDecoration = BoxDecoration( - color: MColors.pageRightFileBGHover, - border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); - var hoverDecorations = BoxDecoration( - color: MColors.pageRightFileBGSelect, - border: Border(bottom: BorderSide(width: 1, color: MColors.pageRightBorderColor))); - //print("buildfile " + item.key); - //if (item.icon[0] == '.') item.icon = FileIcons.getFileIcon(item.icon, ""); - return HoverContainer( - //key: Key("prd_h_" + item.key), - cursor: SystemMouseCursors.basic, - height: 60, - decoration: item.selected ? decorations : decoration, - hoverDecoration: item.selected ? hoverDecorations : hoverDecoration, - child: Container( - key: Key("prd_hc_" + item.key), - height: 60, - child: InkWell( - mouseCursor: SystemMouseCursors.basic, - onTap: () => onTapFile(item.key), - child: Row( - key: Key("prd_hcr_" + item.key), - children: [ - item.downPage.startsWith("down") - ? (item.isDowning ? downBoxed : downBox) - : (item.isDowning ? uploadBoxed : uploadBox), - padding4, - Expanded( - child: Tooltip( - message: item.path, - child: Text(item.title, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 2), - ), - ), - Container( - key: Key("prd_hcr_s_" + item.key), - width: 88, - alignment: Alignment.centerRight, - child: Text(item.fileSize, style: textStyle, maxLines: 1)), - padding22, - Container( - height: 60, - child: Stack(alignment: Alignment.topLeft, children: [ - HoverWidget( - key: Key("prd_hcr_hbtn_" + item.key), - child: item.downPage.contains("ing") - ? Container( - width: 220, - height: 60, - child: Row(key: Key("prd_hcr_hbtnr_" + item.key), children: [ - Container( - key: Key("prd_hcr_t_" + item.key), - width: 90, - alignment: Alignment.center, - child: Column(children: [ - Padding(padding: EdgeInsets.only(top: 20)), - SizedBox( - height: 3, - child: GradientProgressIndicator( - gradient: Gradients.coralCandyGradient, - value: item.downProgress / 100, - )), - Padding(padding: EdgeInsets.only(top: 4)), - Text(item.lastTime, - style: TextStyle(fontSize: 12, color: MColors.textColor), - maxLines: 1, - softWrap: false), - ])), - padding12, - Container( - key: Key("prd_hcr_sp_" + item.key), - width: 110, - alignment: Alignment.centerRight, - child: Text(item.downSpeed, - style: TextStyle(fontSize: 20, color: MColors.pageRightDownSpeedColor), - maxLines: 1, - softWrap: false, - overflow: TextOverflow.visible)) - ])) - : Container( - width: 120, - height: 60, - child: Row( - key: Key("prd_hcr_hbtnr2_" + item.key), - mainAxisAlignment: MainAxisAlignment.center, - children: [ - OutlinedButton( - child: Icon(MIcons.file_folder, size: 16), - onPressed: () => onTapBtn("forder", item.key, item.downPage)), - padding16, - OutlinedButton( - child: Icon(MIcons.delete, size: 16), - onPressed: () => onTapBtn("delete", item.key, item.downPage)), - ])), - hoverChild: item.downPage.contains("ing") - ? Container( - width: 220, - height: 60, - child: Row( - key: Key("prd_hcr_hbtnr2_" + item.key), - mainAxisAlignment: MainAxisAlignment.center, - children: [ - OutlinedButton( - child: Icon(MIcons.start, size: 16), - onPressed: () => onTapBtn("start", item.key, item.downPage)), - padding16, - OutlinedButton( - child: Icon(MIcons.pause, size: 16), - onPressed: () => onTapBtn("stop", item.key, item.downPage)), - padding16, - OutlinedButton( - child: Icon(MIcons.file_folder, size: 16), - onPressed: () => onTapBtn("forder", item.key, item.downPage)), - padding16, - OutlinedButton( - child: Icon(MIcons.delete, size: 16), - onPressed: () => onTapBtn("delete", item.key, item.downPage)), - ])) - : Container( - width: 120, - height: 60, - child: Row( - key: Key("prd_hcr_hbtnr2_" + item.key), - mainAxisAlignment: MainAxisAlignment.center, - children: [ - OutlinedButton( - child: Icon(MIcons.file_folder, size: 16), - onPressed: () => onTapBtn("forder", item.key, item.downPage)), - padding16, - OutlinedButton( - child: Icon(MIcons.delete, size: 16), - onPressed: () => onTapBtn("delete", item.key, item.downPage)), - ])), - onHover: (p) {}), - Positioned( - left: 0, - top: 39, - child: Text( - item.failedMessage, - style: TextStyle(color: Colors.red, fontSize: 12), - ), - ), - ])), - padding12, - ], - )))); - } -} diff --git a/alixby/lib/widgets/DownSaveDialog.dart b/alixby/lib/widgets/DownSaveDialog.dart deleted file mode 100644 index 4ebfd1d..0000000 --- a/alixby/lib/widgets/DownSaveDialog.dart +++ /dev/null @@ -1,149 +0,0 @@ -import 'package:alixby/api/Downloader.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:bot_toast/bot_toast.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; - -// ignore: must_be_immutable -class DownSaveDialog extends StatefulWidget { - DownSaveDialog({Key? key, required this.parentID, required this.parentPath, required this.filelist}) - : super(key: key) { - var savePath = Global.settingState.setting.savePath; - var spc = "\\"; - if (savePath.contains("/")) { - spc = "/"; //mac linux - } else { - parentPath = parentPath.replaceAll('/', '\\'); - } - while (savePath.endsWith(spc)) { - savePath = savePath.substring(0, savePath.length - 1); - } - savePath = savePath + spc; - while (parentPath.startsWith(spc)) { - parentPath = parentPath.substring(1); - } - controller.text = savePath + parentPath; - } - String parentID = ""; - String parentPath = ""; - List filelist = []; - TextEditingController controller = TextEditingController(); - @override - _DownSaveDialogState createState() => _DownSaveDialogState(); -} - -class _DownSaveDialogState extends State { - void _getDirectoryPath() async { - final directoryPath = await FileSelectorPlatform.instance.getDirectoryPath( - initialDirectory: widget.controller.text, - confirmButtonText: "选择保存到的文件夹", - ); - if (directoryPath != null) widget.controller.text = directoryPath; - } - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 240, - width: 460, - 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("下载文件保存到", style: TextStyle(fontSize: 20, color: MColors.textColor))), - Container( - width: 380, - margin: EdgeInsets.only(top: 24), - child: Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints(maxHeight: 56), - child: TextField( - controller: widget.controller, - maxLines: 1, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - decoration: InputDecoration( - helperText: "默认是下载文件夹+网盘路径+文件名,不推荐选择其他文件夹", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderHover, - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderColor, - width: 1, - ), - ), - ), - )), - Positioned.directional( - textDirection: TextDirection.rtl, - start: 0, - child: ConstrainedBox( - constraints: BoxConstraints(minHeight: 31), - child: ElevatedButton.icon( - icon: Icon(MIcons.file_folder, size: 16), - label: Text('选择'), - onPressed: () => _getDirectoryPath()))), - ], - ), - ), - Container( - width: 380, - padding: EdgeInsets.only(top: 38, bottom: 8), - child: ElevatedButton.icon( - icon: Icon(MIcons.download, size: 16), - label: Text('立即下载 (选中的文件夹很多时要耐心等很久)'), - onPressed: () { - String savepath = widget.controller.text; - savepath = savepath.replaceAll('"', '').trim(); - var fcHide = Loading.showLoading(); - var parentid = Global.panFileState.pageRightDirKey; - Downloader.goDownFile(parentid, savepath, widget.filelist).then((value) { - fcHide(); - if (value > 0) { - BotToast.showText(text: "成功创建" + value.toString() + "个文件的下载任务"); - Navigator.of(context).pop('ok'); - } else { - BotToast.showText(text: "创建下载任务失败请重试"); - } - }); - }, - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - )), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/ImageDialog.dart b/alixby/lib/widgets/ImageDialog.dart deleted file mode 100644 index e8f13b5..0000000 --- a/alixby/lib/widgets/ImageDialog.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.dart'; -import 'package:extended_image/extended_image.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -// ignore: must_be_immutable -class ImageDialog extends StatelessWidget { - ImageDialog({Key? key, required this.imageUrl}) : super(key: key); - String imageUrl = ""; - final verticalScroll = ScrollController(); - @override - Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; - var imagew = size.width * 0.8 - 40; - var imageh = size.height * 0.9 - 80; - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: size.height * 0.9, - width: size.width * 0.8, - 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("图片预览", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0))), - Container( - width: imagew, - height: imageh, - margin: EdgeInsets.only(top: 20), - alignment: Alignment.topLeft, - child: Scrollbar( - controller: verticalScroll, - isAlwaysShown: true, - showTrackOnHover: true, - thickness: 9, - hoverThickness: 9, - child: SingleChildScrollView( - controller: verticalScroll, - scrollDirection: Axis.vertical, - physics: BouncingScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: imagew, minHeight: imageh), - child: Container( - width: imagew, - alignment: Alignment.topCenter, - decoration: BoxDecoration( - border: Border.all(width: 1, color: Colors.grey), - borderRadius: BorderRadius.circular(6.0)), - padding: EdgeInsets.all(4), - margin: EdgeInsets.only(right: 16), - child: ExtendedImage.network(imageUrl, - headers: {"Referer": "https://www.aliyundrive.com/"}, - fit: BoxFit.none, - filterQuality: FilterQuality.high, - cache: true, - //enableLoadState: false, - mode: ExtendedImageMode.none, loadStateChanged: (ExtendedImageState state) { - switch (state.extendedImageLoadState) { - case LoadState.loading: - return null; - case LoadState.completed: - verticalScroll.animateTo(1, - duration: Duration(milliseconds: 100), - curve: Curves.ease); //奇怪这里必须刷新一下才显示 - return ExtendedRawImage(image: state.extendedImageInfo?.image); - case LoadState.failed: - return null; - } - })))))), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/LoginDialog.dart b/alixby/lib/widgets/LoginDialog.dart deleted file mode 100644 index 44ca15d..0000000 --- a/alixby/lib/widgets/LoginDialog.dart +++ /dev/null @@ -1,200 +0,0 @@ -import 'dart:async'; -import 'package:alixby/api/AliLogin.dart'; -import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.dart'; -import 'package:alixby/widgets/LoginDialogCookie.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:qr_flutter/qr_flutter.dart'; - -class LoginDialog extends StatefulWidget { - const LoginDialog({ - Key? key, - }) : super(key: key); - @override - _LoginDialogState createState() => _LoginDialogState(); -} - -class _LoginDialogState extends State { - void updateState(fn) { - if (mounted) { - setState(fn); - } - } - - String _qrcodeUrl = ""; - //每一次setState,都会触发执行这里 - Future _qrcodeCheck() async { - if (loadError || loadQrcode) return; - if (loadQrcode == false) { - print('apiQrcodeGenerate'); - _qrcodeUrl = await AliLogin.apiQrcodeGenerate(); - bool isLoadQrcode = _qrcodeUrl != ""; - updateState(() { - loadError = !isLoadQrcode; - loadQrcode = isLoadQrcode; - }); - } - } - - Future _qrcodeQuery() async { - if (loadQrcode == true) { - String result = await AliLogin.apiQrcodeQuery(); - print(result); - if (result == "success") { - Global.userState.loadUser(); - Navigator.of(context).pop('ok'); - } else if (result == "retry") { - updateState(() { - loadError = true; - loadQrcode = false; - }); - } - } - } - - Widget _buildFuture(BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.none: - return Text(''); - case ConnectionState.active: - return Text(''); - case ConnectionState.waiting: - return Center( - child: CircularProgressIndicator(), - ); - case ConnectionState.done: - if (snapshot.hasError) { - return Text('网络错误'); - } else if (_qrcodeUrl == "") { - return Text('网络错误'); - } else { - return QrImage( - data: _qrcodeUrl, - version: QrVersions.auto, - size: 160, - gapless: false, - ); - } - default: - return Text(''); - } - } - - late Timer timer; - //初始化时需要先读取html数据 - bool loadHtml = false; - //是否显示二维码(不显示二维码就显示刷新按钮) - bool loadQrcode = false; - //第一次强制隐藏刷新按钮 - bool loadError = false; - //避免重复执行timer - bool loading = false; - - @override - void initState() { - super.initState(); - print('initState LoginDialog'); - loadError = false; - loadHtml = false; - loadQrcode = false; - timer = Timer.periodic(Duration(milliseconds: 1500), (timer) { - if (loading) return; - loading = true; - try { - _qrcodeQuery(); - } catch (e) {} - loading = false; - }); - } - - @override - void dispose() { - timer.cancel(); - loadHtml = false; - loadQrcode = false; - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 300, - width: 300, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Colors.white, - ), - 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("请用阿里云盘 App 扫码登录", style: TextStyle(fontSize: 20, color: MColors.textColor))), - Container( - width: 170, - height: 170, - child: Stack( - alignment: Alignment.center, - children: [ - FutureBuilder( - builder: _buildFuture, - future: _qrcodeCheck(), - ), - Container( - color: Color(0xeeffffff), - alignment: Alignment.center, - width: loadError ? 160 : 0, - height: 160, - child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ - Text("二维码已失效"), - Padding(padding: EdgeInsets.only(top: 20)), - ElevatedButton( - child: Text("刷新二维码"), - onPressed: () { - updateState(() { - loadError = false; - loadQrcode = false; - }); - }, - ) - ])), - ], - )), - Container( - padding: EdgeInsets.only(top: 8), - child: TextButton( - child: Text("使用Cookie登录", style: TextStyle(color: MColors.linkColor)), - onPressed: () { - Navigator.of(context).pop('ok'); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: LoginDialogCookie(), - ); - }); - })), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/LoginDialogCookie.dart b/alixby/lib/widgets/LoginDialogCookie.dart deleted file mode 100644 index 115b662..0000000 --- a/alixby/lib/widgets/LoginDialogCookie.dart +++ /dev/null @@ -1,218 +0,0 @@ -import 'package:alixby/api/AliLogin.dart'; -import 'package:alixby/states/Global.dart'; -import 'package:alixby/utils/FileLinkifier.dart'; -import 'package:alixby/utils/Loading.dart'; -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.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:flutter_linkify/flutter_linkify.dart'; -import 'package:url_launcher/url_launcher.dart'; - -import 'LoginDialog.dart'; - -class LoginDialogCookie extends StatelessWidget { - LoginDialogCookie({ - Key? key, - }) : super(key: key); - final TextEditingController controller = TextEditingController(); - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 400, - width: 460, - 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("请用阿里云盘网页版 Cookie 登录", style: TextStyle(fontSize: 20, color: MColors.textColor))), - Container( - width: 380, - margin: EdgeInsets.only(top: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - margin: EdgeInsets.only(top: 4, bottom: 4), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan(style: TextStyle(fontSize: 14, color: MColors.textColor), children: [ - TextSpan(text: "点击观看 ==> ", style: TextStyle(color: MColors.textColor)), - WidgetSpan( - child: Linkify( - onOpen: (link) { - launch(Uri.encodeFull(link.url)); - }, - text: "操作录像", - linkifiers: [ - FileLinkifier("操作录像", - "https://p.pstatp.com/origin/pgc-image/cb86a7d7227449d481c32df6677f3461") - ], - linkStyle: TextStyle( - fontSize: 14, - color: MColors.linkColor, - decoration: TextDecoration.none))), - ]))), - Container( - margin: EdgeInsets.only(top: 4, bottom: 4), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan(style: TextStyle(fontSize: 14, color: MColors.textColor), children: [ - TextSpan(text: "第1步:点击登录云盘网页版 ==> ", style: TextStyle(color: MColors.textColor)), - WidgetSpan( - child: Linkify( - onOpen: (link) { - launch(Uri.encodeFull(link.url)); - }, - text: "aliyundrive.com", - linkifiers: [ - FileLinkifier("aliyundrive.com", - "https://www.aliyundrive.com/sign/in?spm=aliyundrive.index.0.0.2d836020dtzo9Z") - ], - linkStyle: TextStyle( - fontSize: 14, - color: MColors.linkColor, - decoration: TextDecoration.none))), - ]))), - Container( - margin: EdgeInsets.only(top: 4, bottom: 4), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan(style: TextStyle(fontSize: 14, color: MColors.textColor), children: [ - TextSpan(text: "第2步:按下键盘", style: TextStyle(color: MColors.textColor)), - TextSpan(text: "F12", style: TextStyle(color: Color(0xffdf5659))), - TextSpan(text: "键,打开网页控制台", style: TextStyle(color: MColors.textColor)), - ]))), - Container( - margin: EdgeInsets.only(top: 4, bottom: 4), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan(style: TextStyle(fontSize: 14, color: MColors.textColor), children: [ - TextSpan(text: "第3步:单击复制下面命令,粘贴到控制台,并按下", style: TextStyle(color: MColors.textColor)), - TextSpan(text: "回车", style: TextStyle(color: Color(0xffdf5659))), - TextSpan(text: "键", style: TextStyle(color: MColors.textColor)), - ]))), - Container( - margin: EdgeInsets.only(top: 4, bottom: 4), - child: Tooltip( - message: "点击自动复制", - child: OutlinedButton( - onPressed: () { - Clipboard.setData( - ClipboardData(text: 'JSON.parse(window.localStorage["token"]).refresh_token')); - BotToast.showText(text: "已复制", align: Alignment(0, 0)); - }, - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(380, 32))), - child: Text( - 'JSON.parse(window.localStorage["token"]).refresh_token', - style: TextStyle(color: Colors.greenAccent.shade400, fontSize: 14), - textAlign: TextAlign.left, - ))), - ), - Container( - margin: EdgeInsets.only(top: 4, bottom: 4), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan(style: TextStyle(fontSize: 14, color: MColors.textColor), children: [ - TextSpan(text: "第4步:复制返回的32位字符串,粘贴到下面", style: TextStyle(color: MColors.textColor)), - ]))), - Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints(maxHeight: 56, maxWidth: 375), - child: TextField( - controller: controller, - maxLines: 1, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - decoration: InputDecoration( - helperText: "例如:ea9876501fac462291618bbec834450f", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderHover, - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderColor, - width: 1, - ), - ), - ), - )), - Positioned.directional( - textDirection: TextDirection.rtl, - start: 0, - child: ElevatedButton( - onPressed: () { - String token = controller.text; - token = token.replaceAll('"', '').trim(); - if (token.length != 32) { - BotToast.showText(text: "refresh_token 应该是长度为32位的字符串!!", align: Alignment(0, 0)); - controller.clear(); - } else { - var fcHide = Loading.showLoading(); - AliLogin.apiTokenRefresh(token).then((value) { - fcHide(); - if (value == "success") { - Global.userState.loadUser(); - BotToast.showText(text: "登录成功"); - Navigator.of(context).pop('ok'); - } else { - BotToast.showText(text: "登录失败请重试"); - } - }); - } - }, - child: Text(" 登录 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - )), - ], - ), - ], - )), - Container( - padding: EdgeInsets.only(top: 8), - child: TextButton( - child: Text("扫码登录", style: TextStyle(color: MColors.linkColor)), - onPressed: () { - Navigator.of(context).pop('ok'); - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return LoginDialog(); - }); - })), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/MoveDialog.dart b/alixby/lib/widgets/MoveDialog.dart deleted file mode 100644 index 56d6446..0000000 --- a/alixby/lib/widgets/MoveDialog.dart +++ /dev/null @@ -1,313 +0,0 @@ -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:bot_toast/bot_toast.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_treeview/flutter_treeview.dart'; -import 'package:hovering/hovering.dart'; - -// ignore: must_be_immutable -class MoveDialog extends StatefulWidget { - // ignore: non_constant_identifier_names - MoveDialog({Key? key, required this.parentid, required this.filelist}) : super(key: key); - // ignore: non_constant_identifier_names - String parentid = ""; - // ignore: non_constant_identifier_names - List filelist = []; - - @override - _MoveDialogState createState() => _MoveDialogState(); -} - -class _MoveDialogState extends State { - @override - void initState() { - super.initState(); - print("_MoveDialogState"); - pageExpandedNode("root", true); - } - - static Node _makeNode(String parentkey, String key, String label, int leve, List children) { - var dir = DirNode2(parentkey, key, label, leve); - return Node(label: dir.label, key: dir.key, parent: true, data: dir, children: children); - } - - static ScrollController verticalScroll = ScrollController(); - static TreeViewController treeController = TreeViewController(children: [_makeNode("", "root", "网盘目录树", 0, [])]); - static String selectKey = ""; - static Map loading = {}; - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 500, - width: 500, - 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("移动文件/文件夹", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0))), - Container( - width: 440, - height: 370, - margin: EdgeInsets.only(top: 22), - alignment: Alignment.topLeft, - child: Scrollbar( - controller: verticalScroll, - isAlwaysShown: true, - hoverThickness: 9, - thickness: 9, - showTrackOnHover: true, - child: SingleChildScrollView( - controller: verticalScroll, - scrollDirection: Axis.vertical, - physics: BouncingScrollPhysics(), - child: Container( - alignment: Alignment.topLeft, - padding: EdgeInsets.only(bottom: 12), - child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - //color: Colors.red[50], - alignment: Alignment.topLeft, - width: 424, - padding: EdgeInsets.only(bottom: 12), - child: TreeView( - shrinkWrap: true, - primary: true, - controller: treeController, - physics: BouncingScrollPhysics(), - allowParentSelect: true, - supportParentDoubleTap: true, - onExpansionChanged: _expandNodeHandler, - onNodeTap: _onNodeTap, - nodeBuilder: _builderTreeNode, - theme: TreeViewTheme( - expanderTheme: ExpanderThemeData( - type: ExpanderType.caret, - modifier: ExpanderModifier.none, - position: ExpanderPosition.start, - color: MColors.userNavColor, - size: 20, - ), - labelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.normal), - parentLabelStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.normal), - iconTheme: IconThemeData(size: 18, color: MColors.pageLeftRowItemIconColor), - colorScheme: ColorScheme.light().copyWith(primary: Colors.transparent), - expandSpeed: Duration(milliseconds: 100), - ), - )), - Container(width: 16, height: 300), - ]))))), - Container( - width: 440, - padding: EdgeInsets.only(top: 12), - child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ - Text("把选中的 " + widget.filelist.length.toString() + " 个文件"), - Padding(padding: EdgeInsets.only(left: 24)), - OutlinedButton( - onPressed: () => Navigator.of(context).pop('ok'), - child: Text("取消"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - ), - Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { - if (widget.filelist.length > 0) { - var fcHide = Loading.showLoading(); - - AliFile.apiMoveBatch(widget.filelist, selectKey).then((value) { - fcHide(); - PanData.loadFileList(widget.parentid, "move"); //触发联网加载 - pageExpandedNode("root", true); - Navigator.of(context).pop('ok'); - BotToast.showText(text: "成功移动" + value.toString() + "个文件"); - }); - } - }, - child: Text("移动到此处"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - ), - ]), - ), - ], - ), - )), - )); - } - - _updateTree(TreeViewController tree) { - treeController = tree; - if (mounted) { - setState(() {}); - } - } - - //页面调用,点击文件树的一个文件夹时触发 - pageExpandedNode(String key, bool expanded) { - Node? node = treeController.getNode(key); - if (node != null) { - selectKey = key; - //选中并展开 - print((expanded ? 'expanded ' : 'close ') + key); - Node node2 = node.copyWith(expanded: expanded); - List updated = treeController.updateNode(key, node2); - _updateTree(treeController.copyWith(children: updated, selectedKey: key)); - - if (expanded == true) { - if (!loading.containsKey(key) || loading[key] == false) { - loading[key] = true; - //是文件夹&&children子文件数==0&&要展开显示了 - //注意node.parent,当联网后发现是空文件夹,node.parent会变成false - - AliFile.apiDirList(key, node.label).then((loadData) { - if (loadData.key == "error") return; - var leve = node.data.leve + 1; - //动态新增 - List children = []; - var total = loadData.list.length; - for (int i = 0; i < total; i++) { - var m = loadData.list[i]; - if (m.isDir) children.add(_makeNode(m.parentkey, m.key, m.name, leve, [])); - } - Node node2 = node.copyWith(expanded: true, parent: true, children: children); //注意这里更新了parent - //更新并展开 - List updated = treeController.updateNode(key, node2); - _updateTree(treeController.copyWith(children: updated, selectedKey: selectKey)); - loading[key] = false; - }); - } - } - } - } - - pageSelectNode(String key) { - Node? node = treeController.getNode(key); - if (node != null) { - pageExpandedNode(node.key, !node.expanded); - } - } - - _expandNodeHandler(String key, bool expanded) { - pageExpandedNode(key, expanded); - } - - _onNodeTap(String key) { - pageSelectNode(key); - } - - Widget _builderTreeNode(BuildContext context, Node node) { - DirNode2? dir = node.data; - if (dir != null) { - return selectKey == node.key ? dir.widgetSelect : dir.widget; - } else { - return Container(); - } - } -} - -class DirNode2 { - DirNode2(this.parentkey, this.key, this.label, this.leve) { - widget = Container( - key: Key("pdt_rc_" + key), - alignment: Alignment.centerLeft, - padding: EdgeInsets.only(top: 2, bottom: 2), - child: UnconstrainedBox( - alignment: Alignment.centerLeft, - child: HoverContainer( - key: Key("pdt_rch_" + key), - cursor: SystemMouseCursors.click, - height: 24, - decoration: decoration, - hoverDecoration: hoverDecoration, - child: Container( - key: Key("pdt_rchc_" + key), - width: 400 - leve * 20, - height: 24, - padding: padding, - child: Row(key: Key("pdt_rchcr_" + key), children: [ - icon, - padding2, - Expanded( - child: Text( - label, - key: Key("pdt_rchcrt_" + key), - style: style, - overflow: TextOverflow.ellipsis, - )) - ]))))); - - widgetSelect = Container( - key: Key("pdt_rc_" + key), - alignment: Alignment.centerLeft, - padding: EdgeInsets.only(top: 2, bottom: 2), - child: UnconstrainedBox( - alignment: Alignment.centerLeft, - child: HoverContainer( - key: Key("pdt_rch_" + key), - cursor: SystemMouseCursors.click, - height: 24, - decoration: decorations, - hoverDecoration: hoverDecorations, - child: Container( - key: Key("pdt_rchc_" + key), - width: 400 - leve * 20, - height: 24, - padding: padding, - child: Row(key: Key("pdt_rchcr_" + key), children: [ - icons, - padding2, - Expanded( - child: Text( - label, - key: Key("pdt_rchcrt_" + key), - style: styles, - overflow: TextOverflow.ellipsis, - )) - ]))))); - } - - String label = ""; - String key = ""; - //父文件夹key - String parentkey = ""; - //文件夹层级 - int leve = 0; - - Widget widget = Container(); - Widget widgetSelect = Container(); - - var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); - var decorations = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); - - var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); - var hoverDecorations = - BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGSelect); - - var padding = EdgeInsets.only(left: 3, right: 3); - var padding2 = Padding(padding: EdgeInsets.only(left: 8)); - var icon = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); - var icons = Icon(MIcons.folder, size: 20, color: MColors.userNavMenuIconHover); - var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor); - var styles = TextStyle(fontSize: 14, color: MColors.userNavMenuIconHover); -} diff --git a/alixby/lib/widgets/RenameDialog.dart b/alixby/lib/widgets/RenameDialog.dart deleted file mode 100644 index 7499a1f..0000000 --- a/alixby/lib/widgets/RenameDialog.dart +++ /dev/null @@ -1,115 +0,0 @@ -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:bot_toast/bot_toast.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -// ignore: must_be_immutable -class RenameDialog extends StatelessWidget { - // ignore: non_constant_identifier_names - RenameDialog({Key? key, required this.file_id, required this.file_name}) : super(key: key) { - controller.text = this.file_name; - } - // ignore: non_constant_identifier_names - String file_id = ""; - // ignore: non_constant_identifier_names - String file_name = ""; - final TextEditingController controller = TextEditingController(); - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 200, - width: 460, - 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("重命名", style: TextStyle(fontSize: 20, color: MColors.textColor))), - Container( - width: 380, - margin: EdgeInsets.only(top: 24), - child: Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints(maxHeight: 56, maxWidth: 375), - child: TextField( - controller: controller, - maxLines: 1, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: true, - decoration: InputDecoration( - helperText: "文件名不要有特殊字符:<>!:*?\\/.'\"", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - contentPadding: EdgeInsets.symmetric(vertical: 4, horizontal: 8), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderHover, - width: 1, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: MColors.inputBorderColor, - width: 1, - ), - ), - ), - )), - Positioned.directional( - textDirection: TextDirection.rtl, - start: 0, - child: ElevatedButton( - onPressed: () { - String dirname = controller.text; - dirname = dirname.replaceAll('"', '').trim(); - - var fcHide = Loading.showLoading(); - - AliFile.apiRename(file_id, dirname).then((value) { - fcHide(); - if (value == "success") { - BotToast.showText(text: "重命名成功"); - Navigator.of(context).pop('ok'); - Global.panTreeState.pageRefreshNode(); - } else { - BotToast.showText(text: "重命名失败请重试"); - } - }); - }, - child: Text(" 重命名 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - )), - ], - ), - ), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/SaveMiaoChuanBackDialog.dart b/alixby/lib/widgets/SaveMiaoChuanBackDialog.dart deleted file mode 100644 index 432ef97..0000000 --- a/alixby/lib/widgets/SaveMiaoChuanBackDialog.dart +++ /dev/null @@ -1,193 +0,0 @@ -import 'package:alixby/api/Linker.dart'; -import 'package:alixby/utils/Loading.dart'; -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.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:hovering/hovering.dart'; - -// ignore: must_be_immutable -class SaveMiaoChuanBackDialog extends StatefulWidget { - // ignore: non_constant_identifier_names - SaveMiaoChuanBackDialog({Key? key, required this.parentid, required this.link}) : super(key: key); - // ignore: non_constant_identifier_names - String parentid = ""; - // ignore: non_constant_identifier_names - LinkFileModel link = LinkFileModel(); - - @override - _SaveMiaoChuanBackDialogState createState() => _SaveMiaoChuanBackDialogState(); -} - -class _SaveMiaoChuanBackDialogState extends State { - List list = []; - @override - void initState() { - super.initState(); - print("_SaveMiaoChuanBackDialogState"); - //创建树 - list.addAll(_addNodes(widget.link.children, 0)); - } - - List _addNodes(List list, int leve) { - List clist = []; - - for (int i = 0; i < list.length; i++) { - if (list[i].isdir) { - list[i].leve = leve; - clist.add(list[i]); - clist.addAll(_addNodes(list[i].children, leve + 1)); - } - } - for (int i = 0; i < list.length; i++) { - if (list[i].isdir == false) { - list[i].leve = leve; - clist.add(list[i]); - } - } - return clist; - } - - static ScrollController verticalScroll = ScrollController(); - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 540, - width: 500, - 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("导入秒传短链接", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0))), - Container(width: 440, height: 1, margin: EdgeInsets.only(top: 22), color: MColors.pageRightBorderColor), - Container( - width: 440, - height: 370, - alignment: Alignment.topLeft, - child: Scrollbar( - controller: verticalScroll, - isAlwaysShown: true, - showTrackOnHover: true, - thickness: 9, - hoverThickness: 9, - child: Row( - children: [ - Expanded( - child: ListView.builder( - controller: verticalScroll, - shrinkWrap: false, - primary: false, - addSemanticIndexes: false, - addAutomaticKeepAlives: false, - addRepaintBoundaries: false, - scrollDirection: Axis.vertical, - physics: ClampingScrollPhysics(), - itemExtent: 28, - itemCount: list.length, - itemBuilder: _buildList, - )), - Container(width: 16), - ], - ))), - Container(width: 440, height: 1, color: MColors.pageRightBorderColor), - Container( - width: 440, height: 54, padding: EdgeInsets.only(top: 8), child: Text("备注信息:" + widget.link.name)), - Container( - width: 440, - padding: EdgeInsets.only(top: 8), - child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [ - OutlinedButton( - onPressed: () => Navigator.of(context).pop('ok'), - child: Text("取消"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - ), - Padding(padding: EdgeInsets.only(left: 24)), - ElevatedButton( - onPressed: () { - if (widget.link.hash == "") { - var fcHide = Loading.showLoading(); - - Linker.goLinkUpload(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: "导入秒传任务失败,请重试"); - } - }); - } - }, - child: Text("导入这些文件"), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - ), - ]), - ), - ], - ), - )), - )); - } - - var decoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftBG); - var hoverDecoration = BoxDecoration(borderRadius: BorderRadius.circular(3.0), color: MColors.pageLeftRowItemBGHover); - var padding = EdgeInsets.only(left: 3, right: 3); - var padding2 = Padding(padding: EdgeInsets.only(left: 4)); - var icondir = Icon(MIcons.folder, size: 20, color: MColors.iconFolder); - var iconfile = Icon(MIcons.file_file, size: 20, color: MColors.iconFile); - var style = TextStyle(fontSize: 14, color: MColors.pageLeftRowItemColor); - - static TextStyle textStyle = TextStyle(fontSize: 13, color: MColors.textColor); - Widget _buildList(BuildContext context, int index) { - var item = list[index]; - //print("buildfile " + item.key); - //if (item.icon[0] == '.') item.icon = FileIcons.getFileIcon(item.icon, ""); - return HoverContainer( - //key: Key("prd_h_" + item.key), - cursor: SystemMouseCursors.basic, - height: 24, - margin: EdgeInsets.only(top: 4), - decoration: decoration, - hoverDecoration: hoverDecoration, - child: Container( - height: 24, - child: Row( - children: [ - Container(width: (22 * item.leve).toDouble()), - item.isdir ? icondir : iconfile, - padding2, - Expanded( - child: Tooltip( - message: item.name, - child: Text(item.name, softWrap: false, overflow: TextOverflow.ellipsis, maxLines: 1)), - ), - Container( - width: 88, - alignment: Alignment.centerRight, - child: Text(item.isdir ? "" : filesize(item.size), style: textStyle, maxLines: 1)), - ], - ))); - } -} diff --git a/alixby/lib/widgets/SaveMiaoChuanDialog.dart b/alixby/lib/widgets/SaveMiaoChuanDialog.dart deleted file mode 100644 index 5d285b0..0000000 --- a/alixby/lib/widgets/SaveMiaoChuanDialog.dart +++ /dev/null @@ -1,249 +0,0 @@ -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/widgets/SaveMiaoChuanBackDialog.dart'; -import 'package:bot_toast/bot_toast.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; - -// ignore: must_be_immutable -class SaveMiaoChuanDialog extends StatefulWidget { - SaveMiaoChuanDialog({Key? key, required this.parentid, required this.parentname}) : super(key: key); - String parentid = ""; - String parentname = ""; - - @override - _SaveMiaoChuanDialogState createState() => _SaveMiaoChuanDialogState(); -} - -class _SaveMiaoChuanDialogState extends State { - final TextEditingController linkcontroller = TextEditingController(); - final TextEditingController pwdcontroller = TextEditingController(); - final verticalScroll = ScrollController(); - - @override - void initState() { - super.initState(); - Clipboard.getData("text/plain").then((value) { - if (value != null) { - var text = value.text; - if (text != null) { - if (text.indexOf("密码:") > 0 && text.indexOf("xby") > 0) { - var pwd = text.substring(text.indexOf("密码:") + "密码:".length).trim(); - if (pwd.length == 4) { - pwdcontroller.text = pwd; - text = text.substring(0, text.indexOf("密码:")).trim(); - } - } - if (text.indexOf("xby") > 0 || text.indexOf("115://") >= 0) { - linkcontroller.text = text; - } - } - } - }); - } - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 520, - width: 500, - 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("导入秒传链接", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0))), - Container( - padding: EdgeInsets.only(left: 20, right: 20), - alignment: Alignment.topLeft, - child: Column(children: [ - Padding(padding: EdgeInsets.only(top: 24)), - ConstrainedBox( - constraints: BoxConstraints(maxHeight: 70, minWidth: double.infinity), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan(style: TextStyle(fontSize: 14, color: MColors.textColor), children: [ - TextSpan(text: "文件会被保存在当前路径下:", style: TextStyle(color: MColors.textColor)), - TextSpan( - text: "/网盘根目录" + widget.parentname, - style: TextStyle(fontSize: 12, color: MColors.linkColor)), - ])), - ), - Padding(padding: EdgeInsets.only(top: 12)), - _buildLink(context), - Padding(padding: EdgeInsets.only(top: 24)), - _buildCanShu(context), - Padding(padding: EdgeInsets.only(top: 32)), - Container( - alignment: Alignment.topLeft, - child: Text("密码可以为空(未设置密码),或是4位数字字母组合(区分大小写)", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - Container( - alignment: Alignment.topLeft, - child: Text("短链接举例:https://xby.writeas.com/?t=XXXXXXXX", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - Container( - alignment: Alignment.topLeft, - child: Text("115链接举例:115://文件名|大小|sha1|hash|保存路径", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - Container( - alignment: Alignment.topLeft, - child: Text("aliyun链接举例:aliyun://文件名|sha1|大小|文件类型", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - Container( - alignment: Alignment.topLeft, - child: Text("秒传短链接一次只能提交一条!115链接可以批量提交", - style: TextStyle(fontSize: 12, color: MColors.pageLeftRowHeadColor)), - ), - ])), - ], - ), - )), - )); - } - - Widget _buildLink(BuildContext context) { - return Container( - alignment: Alignment.topLeft, - child: ConstrainedBox( - constraints: BoxConstraints(minHeight: 156, minWidth: double.infinity), - child: Scrollbar( - controller: verticalScroll, - isAlwaysShown: true, - showTrackOnHover: true, - thickness: 9, - hoverThickness: 9, - child: TextField( - controller: linkcontroller, - scrollController: verticalScroll, - maxLines: 8, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: true, - decoration: InputDecoration( - helperText: "一条xby.短链接 | 多条115://秒传链接 | 多条aliyun://秒传链接", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - 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: 56, maxWidth: 120), - child: TextField( - controller: pwdcontroller, - maxLines: 1, - maxLength: 4, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: false, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp("[0-9a-zA-Z]")), //只允许输入数字字母 - ], - decoration: InputDecoration( - hintText: "无", - helperText: "密码", - helperStyle: TextStyle(fontSize: 13, color: MColors.textColor), - contentPadding: EdgeInsets.symmetric(vertical: 4, 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)), - ElevatedButton( - onPressed: () { - String link = linkcontroller.text; - String pwd = pwdcontroller.text; - var fcHide = Loading.showLoading(); - - Linker.goLinkParse(link, pwd).then((value) { - fcHide(); - 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(parentid: widget.parentid, link: value)); - }); - } else { - BotToast.showText(text: "解析链接失败:" + value.hash); - } - }); - }, - child: Text(" 解析链接 "), - style: ButtonStyle(minimumSize: MaterialStateProperty.all(Size(0, 35))), - ), - ], - ), - ); - } -} diff --git a/alixby/lib/widgets/TextDialog.dart b/alixby/lib/widgets/TextDialog.dart deleted file mode 100644 index f856232..0000000 --- a/alixby/lib/widgets/TextDialog.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -// ignore: must_be_immutable -class TextDialog extends StatelessWidget { - TextDialog({Key? key, required this.text}) : super(key: key) { - controller.text = text; - } - String text = ""; - final verticalScroll = ScrollController(); - final TextEditingController controller = TextEditingController(); - @override - Widget build(BuildContext context) { - var size = MediaQuery.of(context).size; - var imagew = size.width * 0.8 - 40; - var imageh = size.height * 0.9 - 80; - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: size.height * 0.9, - width: size.width * 0.8, - 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("小文本预览(仅显示前1万字)", style: TextStyle(fontSize: 20, color: MColors.textColor, height: 0))), - Container( - width: imagew, - height: imageh, - margin: EdgeInsets.only(top: 20), - alignment: Alignment.topLeft, - child: Scrollbar( - controller: verticalScroll, - isAlwaysShown: true, - showTrackOnHover: true, - thickness: 9, - hoverThickness: 9, - child: TextField( - controller: controller, - scrollController: verticalScroll, - maxLines: 48, - autocorrect: false, - enableSuggestions: false, - style: TextStyle(fontSize: 14, color: MColors.textColor), - cursorColor: MColors.inputBorderHover, - autofocus: false, - 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, - ), - ), - ), - ))), - ], - ), - )), - )); - } -} diff --git a/alixby/lib/widgets/UserNav.dart b/alixby/lib/widgets/UserNav.dart deleted file mode 100644 index 465ff0b..0000000 --- a/alixby/lib/widgets/UserNav.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:alixby/states/Global.dart'; -import 'package:alixby/widgets/LoginDialog.dart'; - -import '../states/UserState.dart'; -import 'package:provider/provider.dart'; -import '../utils/MIcons.dart'; - -import '../utils/MColors.dart'; -import 'package:flutter/material.dart'; - -class UserNav extends StatefulWidget { - UserNav({required Key key}) : super(key: key); - @override - _UserNavState createState() => _UserNavState(); -} - -class _UserNavState extends State { - @override - Widget build(BuildContext context) { - return Row( - children: [ - ClipRRect( - //剪裁为圆角矩形 - borderRadius: BorderRadius.circular(5.0), - child: Image.asset("assets/images/app.png", width: 24, fit: BoxFit.cover), - ), - Padding(padding: EdgeInsets.only(left: 6)), - Expanded( - child: InkWell( - child: Text( - context.watch().userName, - style: TextStyle(color: MColors.userNavColor, fontSize: 16, fontWeight: FontWeight.bold), - maxLines: 1, - softWrap: false, - overflow: TextOverflow.clip, - ), - onTap: () async { - if (!Global.userState.isLogin) { - //先检查一遍是否登录 - bool islogin = await Global.userState.loadUser(); - if (islogin) return; - } - - //todo::显示用户信息 - if (Global.userState.isLogin) { - } else { - showDialog( - barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框 - context: context, - builder: (context) { - return WillPopScope( - onWillPop: () async => false, //关键代码 - child: LoginDialog()); - }); - } - })), - Padding(padding: EdgeInsets.only(left: 8)), - Material( - color: Colors.transparent, - shape: CircleBorder(), - child: SizedBox( - width: context.watch().userBtnWidth, - height: 26.0, - child: PopupMenuButton( - onSelected: (value) { - if (value == "logoff") Global.userState.logoffUser(); - }, - offset: Offset(0, 26), - shape: RoundedRectangleBorder( - side: BorderSide(color: MColors.userNavBtnBorder), borderRadius: BorderRadius.circular(4)), - tooltip: 'logoff', - padding: EdgeInsets.all(0), - color: MColors.userNavBtnBG, - icon: Icon(MIcons.logout, color: MColors.userNavBtnColor), - iconSize: 20, - itemBuilder: (context) { - return >[ - PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15), - height: 32, - value: 'logoff', - child: Text('退出登录'), - ), - PopupMenuItem( - textStyle: TextStyle(color: MColors.userNavBtnColor, fontSize: 15), - height: 32, - value: 'chance', - child: Text('取消'), - ), - ]; - }, - ))), - Padding(padding: EdgeInsets.only(left: 5)), - ], - ); - } -} diff --git a/alixby/lib/widgets/VerDialog.dart b/alixby/lib/widgets/VerDialog.dart deleted file mode 100644 index 9e07bf9..0000000 --- a/alixby/lib/widgets/VerDialog.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:alixby/utils/MColors.dart'; -import 'package:alixby/utils/MIcons.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -class VerDialog extends StatelessWidget { - const VerDialog({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: DefaultTextStyle( - //1.设置文本默认样式 - style: TextStyle(color: MColors.textColor), - child: Center( - child: Container( - height: 200, - width: 460, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Colors.white, - ), - 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("有新版本发布了", style: TextStyle(fontSize: 20, color: MColors.textColor))), - Container( - width: 380, - margin: EdgeInsets.only(top: 24), - child: Text("!"), - ), - ], - ), - )), - )); - } -} diff --git a/alixby/pubspec.yaml b/alixby/pubspec.yaml index 34941a9..c051d38 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.10 +version: 1.6.21 environment: sdk: ">=2.12.0 <3.0.0" @@ -41,6 +41,8 @@ dependencies: 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 dev_dependencies: flutter_test: sdk: flutter