- dialog.NewCustom selalu menambah tombol dismiss walau labelnya kosong; modal kita pakai baris tombol sendiri, jadi pindah ke NewCustomWithoutButtons (ditambah tes yang menolak pemakaian dialog.NewCustom lagi) - Ikon: SVG/webp/gif/bmp/ico/jpeg semuanya dikonversi ke PNG saat dipasang (desktop environment tidak konsisten membaca format lain), gambar besar diperkecil ke maksimal 512px - Filter file picker ikon menambah webp/gif/bmp - Perbaiki data race pada endpoint pencarian ikon (iconifyBase) yang ditemukan oleh go test -race; tes UI menunggu goroutine pencarian selesai - go test -race -count=1 ./... hijau untuk semua paket
157 lines
4.0 KiB
Go
157 lines
4.0 KiB
Go
package ui
|
|
|
|
import (
|
|
"net/url"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/dialog"
|
|
"fyne.io/fyne/v2/theme"
|
|
"fyne.io/fyne/v2/widget"
|
|
|
|
"lazyrun/internal/browser"
|
|
"lazyrun/internal/icon"
|
|
"lazyrun/internal/shortcut"
|
|
"lazyrun/internal/store"
|
|
)
|
|
|
|
func (ui *app) showWebAppDialog() {
|
|
if len(ui.browsers) == 0 {
|
|
dialog.ShowInformation(T("err_title"), T("no_browser"), ui.win)
|
|
return
|
|
}
|
|
|
|
var iconPath, iconURL string
|
|
var iconData []byte
|
|
var nameTouched, filling bool
|
|
|
|
urlEntry := widget.NewEntry()
|
|
urlEntry.SetPlaceHolder("https://web.whatsapp.com")
|
|
nameEntry := widget.NewEntry()
|
|
nameEntry.SetPlaceHolder("WhatsApp Web")
|
|
iconLabel := muted(T("icon_auto"))
|
|
picker := widget.NewSelect(browserNames(ui.browsers), nil)
|
|
picker.SetSelected(ui.browsers[0].Name)
|
|
menu := widget.NewCheck(T("check_menu"), nil)
|
|
menu.SetChecked(true)
|
|
desktop := widget.NewCheck(T("check_desktop"), nil)
|
|
desktop.SetChecked(true)
|
|
|
|
nameEntry.OnChanged = func(string) {
|
|
if !filling {
|
|
nameTouched = true
|
|
}
|
|
}
|
|
urlEntry.OnChanged = func(value string) {
|
|
if nameTouched {
|
|
return
|
|
}
|
|
if host := hostOf(value); host != "" {
|
|
filling = true
|
|
nameEntry.SetText(host)
|
|
filling = false
|
|
}
|
|
}
|
|
|
|
browseIcon := widget.NewButtonWithIcon(T("browse"), theme.FolderOpenIcon(), func() {
|
|
pickFile(ui.win, imageFilter, func(path string) {
|
|
iconPath, iconURL, iconData = path, "", nil
|
|
iconLabel.SetText(filepath.Base(path))
|
|
})
|
|
})
|
|
onlineIcon := widget.NewButtonWithIcon(T("online"), theme.SearchIcon(), func() {
|
|
ui.showIconSearch(nameEntry.Text, func(result icon.Result, data []byte) {
|
|
iconURL, iconPath, iconData = result.URL, "", data
|
|
iconLabel.SetText(result.Name)
|
|
})
|
|
})
|
|
|
|
var d *dialog.CustomDialog
|
|
install := widget.NewButtonWithIcon(T("install"), theme.DownloadIcon(), func() {
|
|
switch {
|
|
case strings.TrimSpace(urlEntry.Text) == "":
|
|
dialog.ShowInformation(T("err_title"), T("need_url"), ui.win)
|
|
return
|
|
case strings.TrimSpace(nameEntry.Text) == "":
|
|
dialog.ShowInformation(T("err_title"), T("need_name"), ui.win)
|
|
return
|
|
case !menu.Checked && !desktop.Checked:
|
|
dialog.ShowInformation(T("err_title"), T("need_target"), ui.win)
|
|
return
|
|
}
|
|
b := ui.browsers[indexOf(ui.browsers, picker.Selected)]
|
|
opts := shortcut.WebOptions{
|
|
URL: urlEntry.Text,
|
|
Name: nameEntry.Text,
|
|
Browser: shortcut.BrowserArg{Name: b.Name, Exec: b.Exec, Firefox: b.Kind == browser.Firefox},
|
|
IconPath: iconPath,
|
|
IconURL: iconURL,
|
|
IconData: iconData,
|
|
Menu: menu.Checked,
|
|
Desktop: desktop.Checked,
|
|
}
|
|
ui.install(
|
|
func() (store.Shortcut, error) { return shortcut.InstallWebApp(opts) },
|
|
func(sc store.Shortcut, err error) { ui.added(sc, err, d.Hide) },
|
|
)
|
|
})
|
|
install.Importance = widget.HighImportance
|
|
|
|
form := widget.NewForm(
|
|
widget.NewFormItem(T("field_url"), urlEntry),
|
|
widget.NewFormItem(T("field_name"), nameEntry),
|
|
widget.NewFormItem(T("field_browser"), picker),
|
|
widget.NewFormItem(T("field_icon"), container.NewBorder(nil, nil, nil,
|
|
container.NewHBox(onlineIcon, browseIcon), iconLabel)),
|
|
)
|
|
content := container.NewVScroll(container.NewVBox(
|
|
closeRow(func() { d.Hide() }),
|
|
form,
|
|
widget.NewSeparator(),
|
|
sectionTitle(T("section_location")),
|
|
menu,
|
|
desktop,
|
|
muted(T("web_hint")),
|
|
container.NewHBox(logoBox(newLogo(), 20), spacer(),
|
|
widget.NewButton(T("cancel"), func() { d.Hide() }),
|
|
install),
|
|
))
|
|
|
|
d = dialog.NewCustomWithoutButtons(T("new_web_title"), content, ui.win)
|
|
showDialog(d, ui.win, 560, 520)
|
|
}
|
|
|
|
func browserNames(list []browser.Browser) []string {
|
|
names := make([]string, len(list))
|
|
for i, b := range list {
|
|
names[i] = b.Name
|
|
}
|
|
return names
|
|
}
|
|
|
|
func indexOf(list []browser.Browser, name string) int {
|
|
for i, b := range list {
|
|
if b.Name == name {
|
|
return i
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// hostOf mengambil hostname dari URL yang mungkin ditulis tanpa skema.
|
|
func hostOf(raw string) string {
|
|
raw = strings.TrimSpace(raw)
|
|
if raw == "" {
|
|
return ""
|
|
}
|
|
if !strings.Contains(raw, "://") {
|
|
raw = "https://" + raw
|
|
}
|
|
u, err := url.Parse(raw)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return u.Hostname()
|
|
}
|