diff --git a/base/web/toast.go b/base/web/toast.go new file mode 100644 index 00000000..ae74f297 --- /dev/null +++ b/base/web/toast.go @@ -0,0 +1,122 @@ +package web + +import ( + "strings" + "time" + + ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/cli" + "shylinux.com/x/icebergs/base/ctx" + "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/web/html" + kit "shylinux.com/x/toolkits" +) + +const ( + TOAST_INIT = "init" + TOAST_DONE = "done" +) +const TOAST = "toast" + +func init() { + Index.MergeCommands(ice.Commands{ + TOAST: {Help: "进度村", Actions: ice.MergeActions(ice.Actions{ + ctx.PREVIEW: &ice.Action{Hand: func(m *ice.Message, arg ...string) { ProcessHashPodCmd(m, arg...) }}, + mdb.PRUNES: &ice.Action{Name: "prunes status=done"}, + }, mdb.StatusHashAction(html.CHECKBOX, ice.TRUE, + mdb.FIELD, "time,hash,type,name,text,cost,status,index,icons,agent,system,ip,ua", + )), Hand: func(m *ice.Message, arg ...string) { + mdb.HashSelect(m, arg...).PushAction(ctx.PREVIEW, mdb.REMOVE).Action(mdb.PRUNES, html.FILTER) + m.Sort("status,cost", []string{"", TOAST_INIT, TOAST_DONE}, func(value string) int { return -int(kit.Duration(value)) }) + }}, + }) +} +func toastCreate(m *ice.Message, arg ...string) (string, time.Time) { + return m.Cmdx(TOAST, mdb.CREATE, mdb.TYPE, kit.FuncName(2), mdb.NAME, toastTitle(m), mdb.STATUS, TOAST_INIT, ctx.INDEX, m.PrefixKey(), ParseUA(m), arg), time.Now() +} +func toastUpdate(m *ice.Message, h string, begin time.Time, arg ...string) string { + cost := kit.FmtDuration(time.Now().Sub(begin)) + m.Cmd(TOAST, mdb.MODIFY, mdb.HASH, h, cli.COST, cost, arg) + return cost +} + +var Icons = map[string]string{ice.PROCESS: "πŸ•‘", ice.FAILURE: "❌", ice.SUCCESS: "βœ…"} + +func toastTitle(m *ice.Message) string { + return kit.GetValid( + func() string { return m.Option(ice.MSG_TITLE) }, + func() string { + return kit.Keys(m.Option(ice.MSG_USERPOD0), m.Option(ice.MSG_USERPOD), ctx.ShortCmd(m.PrefixKey())) + }, + ) +} +func toastContent(m *ice.Message, state string, arg ...ice.Any) string { + if len(arg) == 0 { + return kit.JoinWord(kit.Simple(Icons[state], kit.Select(ice.LIST, m.ActionKey()), state)...) + } else { + return kit.JoinWord(kit.Simple(Icons[state], arg)...) + } +} +func ToastSuccess(m *ice.Message, arg ...ice.Any) { + Toast(m, toastContent(m, ice.SUCCESS, arg...), "", cli.TIME_3s) +} +func ToastFailure(m *ice.Message, arg ...ice.Any) { + Toast(m, toastContent(m, ice.FAILURE, arg...), "", m.OptionDefault(ice.TOAST_DURATION, cli.TIME_3s)).Sleep(m.OptionDefault(ice.TOAST_DURATION, cli.TIME_3s)) +} +func ToastProcess(m *ice.Message, arg ...ice.Any) func(...ice.Any) { + text := toastContent(m, ice.PROCESS, arg...) + h, begin := toastCreate(m, mdb.TEXT, text) + Toast(m, text, "", "-1", "", h) + Count(m, kit.FuncName(1), toastTitle(m), text) + return func(arg ...ice.Any) { + text := toastContent(m, ice.SUCCESS, arg...) + toastUpdate(m, h, begin, mdb.TEXT, text, mdb.STATUS, TOAST_DONE) + Toast(m, text, "", cli.TIME_3s, "", h) + } +} +func GoToastTable(m *ice.Message, key string, cb func(value ice.Maps)) *ice.Message { + if m.Length() == 0 { + return m + } + return GoToast(m, func(toast func(string, int, int)) []string { + m.Table(func(value ice.Maps, index, total int) { toast(value[key], index, total); cb(value) }) + return nil + }) +} +func GoToast(m *ice.Message, cb func(toast func(name string, count, total int)) []string) *ice.Message { + h, begin := toastCreate(m) + icon, _total := Icons[ice.PROCESS], 1 + toast := func(name string, count, total int) { + kit.If(total == 0, func() { total = 1 }) + text := kit.JoinWord(icon, kit.Select(ice.LIST, m.ActionKey()), name, strings.ReplaceAll(kit.FmtSize(count, total), "B", "")) + cost := toastUpdate(m, h, begin, mdb.TEXT, text, mdb.STATUS, kit.Select("", TOAST_DONE, count == total)) + Toast(m, kit.JoinWord(text, cost), "", m.OptionDefault(ice.TOAST_DURATION, "-1"), count*100/total, h) + _total = total + } + if list := cb(toast); len(list) > 0 { + icon = Icons[ice.FAILURE] + m.Option(ice.TOAST_DURATION, cli.TIME_30s) + toast(kit.JoinWord(list...), len(list), _total) + } else { + icon = Icons[ice.SUCCESS] + m.Option(ice.TOAST_DURATION, cli.TIME_3s) + toast(ice.SUCCESS, _total, _total) + } + Count(m, kit.FuncName(1), toastTitle(m), kit.FmtDuration(time.Now().Sub(begin))) + m.Sleep(m.Option(ice.TOAST_DURATION)) + return m +} +func Toast(m *ice.Message, text string, arg ...ice.Any) *ice.Message { // [title [duration [progress [hash]]]] + if len(arg) > 1 { + switch val := arg[1].(type) { + case string: + if value, err := time.ParseDuration(val); err == nil { + arg[1] = int(value / time.Millisecond) + } + } + } + kit.If(len(arg) == 0, func() { arg = append(arg, "") }) + kit.If(len(arg) > 0 && arg[0] == "", func() { arg[0] = toastTitle(m) }) + PushNoticeToast(m, text, arg) + return m +}