This commit is contained in:
Aynakeya
2022-06-26 01:44:26 -07:00
parent 8c6ea48ad4
commit dd46c167ff
16 changed files with 400 additions and 57 deletions

View File

@@ -10,4 +10,5 @@ QQ group: 621035845
```
go build -ldflags -H=windowsgui app/gui/main.go
```

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config"
"AynaLivePlayer/controller"
"AynaLivePlayer/gui"
"AynaLivePlayer/i18n"
"AynaLivePlayer/logger"
"AynaLivePlayer/plugin/diange"
"AynaLivePlayer/plugin/qiege"
@@ -32,6 +33,7 @@ func main() {
defer func() {
controller.Destroy()
config.SaveToConfigFile(config.CONFIG_PATH)
i18n.SaveTranslation()
}()
gui.Initialize()
gui.MainWindow.ShowAndRun()

220
assets/translation.json Normal file
View File

@@ -0,0 +1,220 @@
{
"Languages": [
"en",
"zh-CN"
],
"Messages": {
"gui.player.button.lrc": {
"en": "lrc",
"zh-CN": "歌词"
},
"gui.player.playlist.artist": {
"en": "Artist",
"zh-CN": "歌手"
},
"gui.player.playlist.op.delete": {
"en": "Delete",
"zh-CN": "删除"
},
"gui.player.playlist.op.top": {
"en": "Top",
"zh-CN": "置顶"
},
"gui.player.playlist.ops": {
"en": "OPs",
"zh-CN": "操作"
},
"gui.player.playlist.title": {
"en": "Title",
"zh-CN": "歌名"
},
"gui.player.playlist.user": {
"en": "User",
"zh-CN": "用户"
},
"gui.playlist.add.cancel": {
"en": "Cancel",
"zh-CN": "取消"
},
"gui.playlist.add.confirm": {
"en": "Confirm",
"zh-CN": "确认"
},
"gui.playlist.add.id_url": {
"en": "ID/URL",
"zh-CN": "ID/网址"
},
"gui.playlist.add.prompt": {
"en": "Please enter the ID or URL of the song you want to add.",
"zh-CN": "输入歌单ID或者歌单网址。"
},
"gui.playlist.add.title": {
"en": "Add Playlist",
"zh-CN": "添加歌单"
},
"gui.playlist.button.add": {
"en": "Add",
"zh-CN": "添加"
},
"gui.playlist.button.refresh": {
"en": "Refresh",
"zh-CN": "刷新"
},
"gui.playlist.button.remove": {
"en": "Remove",
"zh-CN": "移除"
},
"gui.playlist.button.set_as_system": {
"en": "SetAsSystem",
"zh-CN": "设为默认歌单"
},
"gui.playlist.current": {
"en": "Current: ",
"zh-CN": "当前为: "
},
"gui.playlist.current.none": {
"en": "Current: None",
"zh-CN": "当前为: 无"
},
"gui.room.btn.connect": {
"en": "Connect",
"zh-CN": "连接"
},
"gui.room.btn.disconnect": {
"en": "Disconnect",
"zh-CN": "断开"
},
"gui.room.id": {
"en": "Room ID: ",
"zh-CN": "房间号: "
},
"gui.room.status.connected": {
"en": "Connected",
"zh-CN": "已连接"
},
"gui.room.status.disconnected": {
"en": "Disconnected",
"zh-CN": "已断开"
},
"gui.room.status.failed": {
"en": "Set Failed",
"zh-CN": "设置失败"
},
"gui.room.waiting": {
"en": "Waiting",
"zh-CN": "等待连接"
},
"gui.search.artist": {
"en": "Artist",
"zh-CN": "歌手"
},
"gui.search.filter": {
"en": "Source Filter: ",
"zh-CN": "选择源: "
},
"gui.search.operation": {
"en": "Operation",
"zh-CN": "操作 "
},
"gui.search.placeholder": {
"en": "Keyword",
"zh-CN": "Keyword"
},
"gui.search.search": {
"en": "Search",
"zh-CN": "搜索"
},
"gui.search.source": {
"en": "Source",
"zh-CN": "歌源"
},
"gui.search.title": {
"en": "Title",
"zh-CN": "歌名"
},
"gui.tab.config": {
"en": "Config",
"zh-CN": "设置"
},
"gui.tab.player": {
"en": "Player",
"zh-CN": "播放器"
},
"gui.tab.playlist": {
"en": "Playlist",
"zh-CN": "播放列表"
},
"gui.tab.room": {
"en": "Room",
"zh-CN": "直播间"
},
"gui.tab.search": {
"en": "Search",
"zh-CN": "搜索"
},
"plugin.diange.admin": {
"en": "Admin",
"zh-CN": "管理员"
},
"plugin.diange.cooldown": {
"en": "Cooldown",
"zh-CN": "点歌冷却"
},
"plugin.diange.custom_cmd": {
"en": "Custom Command (Default one still works)",
"zh-CN": "自定义命令 (默认的依然可用)"
},
"plugin.diange.description": {
"en": "Basic Diange Configuration",
"zh-CN": "点歌基本设置"
},
"plugin.diange.permission": {
"en": "Permission",
"zh-CN": "点歌权限"
},
"plugin.diange.privilege": {
"en": "Privilege",
"zh-CN": "舰长"
},
"plugin.diange.queue_max": {
"en": "Max Queue",
"zh-CN": "最大点歌数"
},
"plugin.diange.title": {
"en": "Diange",
"zh-CN": "点歌"
},
"plugin.diange.user": {
"en": "User",
"zh-CN": "普通用户"
},
"plugin.qiege.admin": {
"en": "Admin",
"zh-CN": "管理员"
},
"plugin.qiege.custom_cmd": {
"en": "Custom Command (Default one still works)",
"zh-CN": "自定义命令 (默认的依然可用)"
},
"plugin.qiege.description": {
"en": "Basic Qiege configuration",
"zh-CN": "基础切歌设置"
},
"plugin.qiege.permission": {
"en": "Permission",
"zh-CN": "切歌权限"
},
"plugin.qiege.privilege": {
"en": "Privilege",
"zh-CN": "舰长"
},
"plugin.qiege.title": {
"en": "Qiege",
"zh-CN": "切歌"
},
"plugin.qiege.user": {
"en": "User",
"zh-CN": "切自己"
}
}
}

View File

@@ -6,7 +6,7 @@ import (
"path"
)
const VERSION = "alpha 0.6.3"
const VERSION = "alpha 0.6.5"
const CONFIG_PATH = "./config.ini"
const Assests_PATH = "./assets"
@@ -38,7 +38,7 @@ func init() {
fmt.Println("config not found, using default config")
ConfigFile = ini.Empty()
}
for _, cfg := range []Config{Log, LiveRoom, Player, Provider} {
for _, cfg := range []Config{Log, LiveRoom, Player, Provider, General} {
LoadConfig(cfg)
}
}

13
config/config_general.go Normal file
View File

@@ -0,0 +1,13 @@
package config
type _GeneralConfig struct {
Language string
}
func (c *_GeneralConfig) Name() string {
return "General"
}
var General = &_GeneralConfig{
Language: "en",
}

View File

@@ -2,6 +2,7 @@ package gui
import (
"AynaLivePlayer/config"
"AynaLivePlayer/i18n"
"AynaLivePlayer/logger"
"fmt"
"fyne.io/fyne/v2"
@@ -33,19 +34,19 @@ func Initialize() {
MainWindow = App.NewWindow(fmt.Sprintf("AynaLivePlayer Ver.%s", config.VERSION))
tabs := container.NewAppTabs(
container.NewTabItem("Player",
container.NewTabItem(i18n.T("gui.tab.player"),
newPaddedBoarder(nil, createPlayController(), nil, nil, createPlaylist()),
),
container.NewTabItem("Search",
container.NewTabItem(i18n.T("gui.tab.search"),
newPaddedBoarder(createSearchBar(), nil, nil, nil, createSearchList()),
),
container.NewTabItem("Room",
container.NewTabItem(i18n.T("gui.tab.room"),
newPaddedBoarder(createRoomController(), nil, nil, nil, createRoomLogger()),
),
container.NewTabItem("Playlist",
container.NewTabItem(i18n.T("gui.tab.playlist"),
newPaddedBoarder(nil, nil, createPlaylists(), nil, createPlaylistMedias()),
),
container.NewTabItem("Config",
container.NewTabItem(i18n.T("gui.tab.config"),
newPaddedBoarder(nil, nil, nil, nil, createConfigLayout()),
),
)

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config"
"AynaLivePlayer/controller"
"AynaLivePlayer/event"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player"
"AynaLivePlayer/util"
"fyne.io/fyne/v2"
@@ -64,7 +65,7 @@ func createPlayController() fyne.CanvasObject {
PlayController.Volume = widget.NewSlider(0, 100)
volumeIcon := widget.NewIcon(theme.VolumeMuteIcon())
PlayController.ButtonLrc = widget.NewButton("lrc", func() {})
PlayController.ButtonLrc = widget.NewButton(i18n.T("gui.player.button.lrc"), func() {})
volumeControl := container.NewBorder(nil, nil, container.NewHBox(widget.NewLabel(" "), volumeIcon), nil,
container.NewGridWithColumns(3, container.NewMax(PlayController.Volume), PlayController.ButtonLrc))

View File

@@ -3,6 +3,7 @@ package gui
import (
"AynaLivePlayer/controller"
"AynaLivePlayer/event"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player"
"fmt"
"fyne.io/fyne/v2"
@@ -23,10 +24,10 @@ func (b *playlistOperationButton) Tapped(e *fyne.PointEvent) {
func newPlaylistOperationButton() *playlistOperationButton {
b := &playlistOperationButton{Index: 0}
deleteItem := fyne.NewMenuItem("Delete", func() {
deleteItem := fyne.NewMenuItem(i18n.T("gui.player.playlist.op.delete"), func() {
fmt.Println("delete", b.Index)
})
topItem := fyne.NewMenuItem("Top", func() {
topItem := fyne.NewMenuItem(i18n.T("gui.player.playlist.op.top"), func() {
controller.UserPlaylist.Move(b.Index, 0)
})
m := fyne.NewMenu("", deleteItem, topItem)
@@ -72,8 +73,11 @@ func createPlaylist() fyne.CanvasObject {
registerPlaylistHandler()
return container.NewBorder(
container.NewBorder(nil, nil,
widget.NewLabel("#"), widget.NewLabel("OPs"),
container.NewGridWithColumns(3, widget.NewLabel("Title"), widget.NewLabel("Artist"), widget.NewLabel("User"))),
widget.NewLabel("#"), widget.NewLabel(i18n.T("gui.player.playlist.ops")),
container.NewGridWithColumns(3,
widget.NewLabel(i18n.T("gui.player.playlist.title")),
widget.NewLabel(i18n.T("gui.player.playlist.artist")),
widget.NewLabel(i18n.T("gui.player.playlist.user")))),
widget.NewSeparator(),
nil, nil,
UserPlaylist.List,

View File

@@ -3,6 +3,7 @@ package gui
import (
"AynaLivePlayer/config"
"AynaLivePlayer/controller"
"AynaLivePlayer/i18n"
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
@@ -25,9 +26,9 @@ type PlaylistManagerContainer struct {
func (p *PlaylistManagerContainer) UpdateCurrentSystemPlaylist() {
if config.Player.PlaylistIndex >= len(controller.PlaylistManager) {
p.CurrentSystemPlaylist.SetText("Current: None")
p.CurrentSystemPlaylist.SetText(i18n.T("gui.playlist.current.none"))
}
p.CurrentSystemPlaylist.SetText("Current: " + controller.PlaylistManager[config.Player.PlaylistIndex].Name)
p.CurrentSystemPlaylist.SetText(i18n.T("gui.playlist.current") + controller.PlaylistManager[config.Player.PlaylistIndex].Name)
}
var PlaylistManager = &PlaylistManagerContainer{}
@@ -44,22 +45,22 @@ func createPlaylists() fyne.CanvasObject {
object.(*widget.Label).SetText(
controller.PlaylistManager[id].Name)
})
PlaylistManager.AddBtn = widget.NewButton("Add", func() {
PlaylistManager.AddBtn = widget.NewButton(i18n.T("gui.playlist.button.add"), func() {
providerEntry := widget.NewSelect(config.Provider.Priority, nil)
idEntry := widget.NewEntry()
dia := dialog.NewCustomConfirm(
"Add Playlist",
"Add",
"Cancel",
i18n.T("gui.playlist.add.title"),
i18n.T("gui.playlist.add.confirm"),
i18n.T("gui.playlist.add.cancel"),
container.NewVBox(
container.New(
layout.NewFormLayout(),
widget.NewLabel("Provider"),
widget.NewLabel(i18n.T("gui.playlist.add.confirm")),
providerEntry,
widget.NewLabel("ID/URL"),
widget.NewLabel(i18n.T("gui.playlist.add.id_url")),
idEntry,
),
widget.NewLabel("Please Enter playlist id or playlist url"),
widget.NewLabel(i18n.T("gui.playlist.add.prompt")),
),
func(b bool) {
if b && len(providerEntry.Selected) > 0 && len(idEntry.Text) > 0 {
@@ -73,7 +74,7 @@ func createPlaylists() fyne.CanvasObject {
dia.Resize(fyne.NewSize(512, 256))
dia.Show()
})
PlaylistManager.RemoveBtn = widget.NewButton("Remove", func() {
PlaylistManager.RemoveBtn = widget.NewButton(i18n.T("gui.playlist.button.remove"), func() {
controller.RemovePlaylist(PlaylistManager.Index)
//PlaylistManager.Index = 0
PlaylistManager.Playlists.Select(0)
@@ -95,13 +96,13 @@ func createPlaylists() fyne.CanvasObject {
func createPlaylistMedias() fyne.CanvasObject {
PlaylistManager.RefreshBtn = createAsyncButton(
widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), nil),
widget.NewButtonWithIcon(i18n.T("gui.playlist.button.refresh"), theme.ViewRefreshIcon(), nil),
func() {
controller.PreparePlaylistByIndex(PlaylistManager.Index)
PlaylistManager.PlaylistMedia.Refresh()
})
PlaylistManager.SetAsSystemBtn = createAsyncButton(
widget.NewButton("SetAsSystem", nil),
widget.NewButton(i18n.T("gui.playlist.button.set_as_system"), nil),
func() {
controller.SetSystemPlaylist(PlaylistManager.Index)
PlaylistManager.PlaylistMedia.Refresh()
@@ -143,7 +144,7 @@ func createPlaylistMedias() fyne.CanvasObject {
}
})
return container.NewBorder(
container.NewHBox(PlaylistManager.RefreshBtn, PlaylistManager.SetAsSystemBtn), nil,
container.NewHBox(PlaylistManager.RefreshBtn, PlaylistManager.SetAsSystemBtn, PlaylistManager.CurrentSystemPlaylist), nil,
nil, nil,
PlaylistManager.PlaylistMedia)
}

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config"
"AynaLivePlayer/controller"
"AynaLivePlayer/event"
"AynaLivePlayer/i18n"
"AynaLivePlayer/liveclient"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
@@ -21,11 +22,11 @@ var RoomController = &RoomControllerContainer{}
func createRoomController() fyne.CanvasObject {
RoomController.Input = widget.NewSelectEntry(config.LiveRoom.History)
RoomController.ConnectBtn = widget.NewButton("Connect", func() {
RoomController.ConnectBtn = widget.NewButton(i18n.T("gui.room.btn.connect"), func() {
RoomController.ConnectBtn.Disable()
controller.SetDanmuClient(RoomController.Input.Text)
if controller.LiveClient == nil {
RoomController.Status.SetText("Set Failed")
RoomController.Status.SetText(i18n.T("gui.room.status.failed"))
RoomController.ConnectBtn.Enable()
RoomController.Status.Refresh()
return
@@ -34,9 +35,9 @@ func createRoomController() fyne.CanvasObject {
controller.LiveClient.Handler().RegisterA(liveclient.EventStatusChange, "gui.liveclient.status", func(event *event.Event) {
d := event.Data.(liveclient.StatusChangeEvent)
if d.Connected {
RoomController.Status.SetText("Connected")
RoomController.Status.SetText(i18n.T("gui.room.status.connected"))
} else {
RoomController.Status.SetText("Disconnected")
RoomController.Status.SetText(i18n.T("gui.room.status.disconnected"))
}
RoomController.Status.Refresh()
})
@@ -45,13 +46,13 @@ func createRoomController() fyne.CanvasObject {
RoomController.ConnectBtn.Enable()
}()
})
RoomController.DisConnectBtn = widget.NewButton("Disconnect", func() {
RoomController.DisConnectBtn = widget.NewButton(i18n.T("gui.room.btn.disconnect"), func() {
controller.ResetDanmuClient()
})
RoomController.Status = widget.NewLabel("Waiting")
RoomController.Status = widget.NewLabel(i18n.T("gui.room.waiting"))
return container.NewBorder(
nil, nil,
widget.NewLabel("Room ID:"), container.NewHBox(RoomController.ConnectBtn, RoomController.DisConnectBtn),
widget.NewLabel(i18n.T("gui.room.id")), container.NewHBox(RoomController.ConnectBtn, RoomController.DisConnectBtn),
container.NewBorder(nil, nil, nil, RoomController.Status, RoomController.Input),
)
}

View File

@@ -3,6 +3,7 @@ package gui
import (
"AynaLivePlayer/config"
"AynaLivePlayer/controller"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
@@ -20,8 +21,8 @@ var SearchBar = &SearchBarContainer{}
func createSearchBar() fyne.CanvasObject {
SearchBar.Input = widget.NewEntry()
SearchBar.Input.SetPlaceHolder("Keyword")
SearchBar.Button = widget.NewButton("Search", nil)
SearchBar.Input.SetPlaceHolder(i18n.T("gui.search.placeholder"))
SearchBar.Button = widget.NewButton(i18n.T("gui.search.search"), nil)
SearchBar.Button.OnTapped = createAsyncOnTapped(SearchBar.Button, func() {
keyword := SearchBar.Input.Text
s := make([]string, len(SearchBar.UseSource.Selected))
@@ -44,10 +45,10 @@ func createSearchBar() fyne.CanvasObject {
SearchBar.UseSource.Horizontal = true
SearchBar.UseSource.SetSelected(s)
searchInput := container.NewBorder(
nil, nil, widget.NewLabel("Search"), SearchBar.Button,
nil, nil, widget.NewLabel(i18n.T("gui.search.search")), SearchBar.Button,
SearchBar.Input)
return container.NewVBox(
searchInput,
container.NewHBox(widget.NewLabel("Source filter: "), SearchBar.UseSource),
container.NewHBox(widget.NewLabel(i18n.T("gui.search.filter")), SearchBar.UseSource),
widget.NewSeparator())
}

View File

@@ -2,6 +2,7 @@ package gui
import (
"AynaLivePlayer/controller"
"AynaLivePlayer/i18n"
"AynaLivePlayer/player"
"AynaLivePlayer/provider"
"fmt"
@@ -53,11 +54,11 @@ func createSearchList() fyne.CanvasObject {
})
return container.NewBorder(
container.NewBorder(nil, nil,
widget.NewLabel("#"), widget.NewLabel("Operation"),
widget.NewLabel("#"), widget.NewLabel(i18n.T("gui.search.operation")),
container.NewGridWithColumns(3,
widget.NewLabel("title"),
widget.NewLabel("artist"),
widget.NewLabel("source"))),
widget.NewLabel(i18n.T("gui.search.title")),
widget.NewLabel(i18n.T("gui.search.artist")),
widget.NewLabel(i18n.T("gui.search.source")))),
nil, nil, nil,
SearchResult.List,
)

63
i18n/i18n.go Normal file
View File

@@ -0,0 +1,63 @@
package i18n
import (
"AynaLivePlayer/config"
"AynaLivePlayer/util"
"encoding/json"
"io/ioutil"
)
const FILENAME = "translation.json"
type Translation struct {
Languages []string
Messages map[string]map[string]string
}
func (t *Translation) HasLanguage(lang string) bool {
for _, l := range t.Languages {
if l == lang {
return true
}
}
return false
}
var TranslationMap Translation
var CurrentLanguage string
func init() {
TranslationMap = Translation{make([]string, 0), make(map[string]map[string]string)}
file, err := ioutil.ReadFile(config.GetAssetPath(FILENAME))
if err == nil {
_ = json.Unmarshal([]byte(file), &TranslationMap)
}
LoadLanguage(config.General.Language)
}
func LoadLanguage(lang string) {
CurrentLanguage = lang
if TranslationMap.HasLanguage(lang) {
return
}
TranslationMap.Languages = append(TranslationMap.Languages, lang)
for id, m := range TranslationMap.Messages {
m[lang] = id
}
}
func T(id string) string {
if x, ok := TranslationMap.Messages[id]; ok {
return x[CurrentLanguage]
}
TranslationMap.Messages[id] = make(map[string]string)
for _, l := range TranslationMap.Languages {
TranslationMap.Messages[id][l] = id
}
return id
}
func SaveTranslation() {
content, _ := util.MarshalIndentUnescape(TranslationMap, "", " ")
_ = ioutil.WriteFile(config.GetAssetPath(FILENAME), []byte(content), 0666)
}

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config"
"AynaLivePlayer/controller"
"AynaLivePlayer/gui"
"AynaLivePlayer/i18n"
"AynaLivePlayer/liveclient"
"AynaLivePlayer/logger"
"fyne.io/fyne/v2"
@@ -91,11 +92,11 @@ func (d *Diange) Execute(command string, args []string, danmu *liveclient.DanmuM
}
func (d *Diange) Title() string {
return "Diange"
return i18n.T("plugin.diange.title")
}
func (d *Diange) Description() string {
return "Basic diange configuration"
return i18n.T("plugin.diange.description")
}
func (d *Diange) CreatePanel() fyne.CanvasObject {
@@ -103,21 +104,21 @@ func (d *Diange) CreatePanel() fyne.CanvasObject {
return d.panel
}
dgPerm := container.NewHBox(
widget.NewLabel("点歌权限"),
widget.NewCheckWithData("用户", binding.BindBool(&d.UserPermission)),
widget.NewCheckWithData("舰长", binding.BindBool(&d.PrivilegePermission)),
widget.NewCheckWithData("管理员", binding.BindBool(&d.AdminPermission)),
widget.NewLabel(i18n.T("plugin.diange.permission")),
widget.NewCheckWithData(i18n.T("plugin.diange.user"), binding.BindBool(&d.UserPermission)),
widget.NewCheckWithData(i18n.T("plugin.diange.privilege"), binding.BindBool(&d.PrivilegePermission)),
widget.NewCheckWithData(i18n.T("plugin.diange.admin"), binding.BindBool(&d.AdminPermission)),
)
dgQueue := container.NewBorder(nil, nil,
widget.NewLabel("最大点歌数"), nil,
widget.NewLabel(i18n.T("plugin.diange.queue_max")), nil,
widget.NewEntryWithData(binding.IntToString(binding.BindInt(&d.QueueMax))),
)
dgCoolDown := container.NewBorder(nil, nil,
widget.NewLabel("点歌冷却时间"), nil,
widget.NewLabel(i18n.T("plugin.diange.cooldown")), nil,
widget.NewEntryWithData(binding.IntToString(binding.BindInt(&d.UserCoolDown))),
)
dgShortCut := container.NewBorder(nil, nil,
widget.NewLabel("自定义命令 (默认的依然可用)"), nil,
widget.NewLabel(i18n.T("plugin.diange.custom_cmd")), nil,
widget.NewEntryWithData(binding.BindString(&d.CustomCMD)),
)
d.panel = container.NewVBox(dgPerm, dgQueue, dgCoolDown, dgShortCut)

View File

@@ -4,6 +4,7 @@ import (
"AynaLivePlayer/config"
"AynaLivePlayer/controller"
"AynaLivePlayer/gui"
"AynaLivePlayer/i18n"
"AynaLivePlayer/liveclient"
"AynaLivePlayer/logger"
"fyne.io/fyne/v2"
@@ -74,26 +75,25 @@ func (d *Qiege) Execute(command string, args []string, danmu *liveclient.DanmuMe
}
func (d *Qiege) Title() string {
return "Qiege"
return i18n.T("plugin.qiege.title")
}
func (d *Qiege) Description() string {
return "Basic Qiege configuration"
return i18n.T("plugin.qiege.description")
}
func (d *Qiege) CreatePanel() fyne.CanvasObject {
if d.panel != nil {
return d.panel
}
dgPerm := container.NewHBox(
widget.NewLabel("切歌权限"),
widget.NewCheckWithData("切自己", binding.BindBool(&d.UserPermission)),
widget.NewCheckWithData("舰长", binding.BindBool(&d.PrivilegePermission)),
widget.NewCheckWithData("管理员", binding.BindBool(&d.AdminPermission)),
widget.NewLabel(i18n.T("plugin.qiege.permission")),
widget.NewCheckWithData(i18n.T("plugin.qiege.user"), binding.BindBool(&d.UserPermission)),
widget.NewCheckWithData(i18n.T("plugin.qiege.privilege"), binding.BindBool(&d.PrivilegePermission)),
widget.NewCheckWithData(i18n.T("plugin.qiege.admin"), binding.BindBool(&d.AdminPermission)),
)
qgShortCut := container.NewBorder(nil, nil,
widget.NewLabel("自定义命令 (默认的依然可用)"), nil,
widget.NewLabel(i18n.T("plugin.qiege.custom_cmd")), nil,
widget.NewEntryWithData(binding.BindString(&d.CustomCMD)),
)
d.panel = container.NewVBox(dgPerm, qgShortCut)

33
util/json.go Normal file
View File

@@ -0,0 +1,33 @@
package util
import (
"bytes"
"encoding/json"
)
func MarshalUnescape(v interface{}) (string, error) {
bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
err := jsonEncoder.Encode(v)
if err != nil {
return "", err
}
return bf.String(), nil
}
func MarshalIndentUnescape(v interface{}, prefix, indent string) (string, error) {
bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
err := jsonEncoder.Encode(v)
if err != nil {
return "", err
}
var buf bytes.Buffer
err = json.Indent(&buf, bf.Bytes(), prefix, indent)
if err != nil {
return "", err
}
return buf.String(), nil
}