UI: animasi dan branding tambahan
- Garis aksen gradien berdenyut terus (indigo <-> cyan) - Kartu shortcut: transisi warna halus saat disorot mouse (hoverCard) - Kartu baru berkedip warna brand saat daftar dimuat / setelah install - Logo LazyRun + brand mark di dialog, footer 'LazyRun vX · oxpoe' - Thumbnail shortcut bersudut membulat - Versi logo fade-in dibuang: canvas.Image.Translucency tidak ter-render di Fyne 2.8
This commit is contained in:
1 parent
b12efefd6a
commit
70534bf6e2
6 files changed
+132
-17
No files matched your search
+31
-11
@@ -6,6 +6,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
@@ -26,6 +27,7 @@ type app struct {
|
||||
store *store.Store
|
||||
browsers []browser.Browser
|
||||
rows *fyne.Container
|
||||
cards map[string]*hoverCard
|
||||
count *canvas.Text // angka jumlah shortcut di header daftar
|
||||
version string
|
||||
}
|
||||
@@ -34,6 +36,7 @@ type app struct {
|
||||
func Run(a fyne.App, version string) {
|
||||
ui, loadErr := build(a, version)
|
||||
ui.win.Show()
|
||||
ui.flashCards()
|
||||
if loadErr != nil {
|
||||
dialog.ShowError(loadErr, ui.win)
|
||||
}
|
||||
@@ -61,7 +64,7 @@ func build(a fyne.App, version string) (*app, error) {
|
||||
addExec.Importance = widget.HighImportance
|
||||
addWeb := widget.NewButtonWithIcon(T("btn_webapp"), theme.ContentAddIcon(), ui.showWebAppDialog)
|
||||
|
||||
leftHeader := container.NewHBox(logoImage(40), container.NewVBox(
|
||||
leftHeader := container.NewHBox(logoBox(newLogo(), 40), container.NewVBox(
|
||||
heading("LazyRun"),
|
||||
caption(T("tagline")),
|
||||
))
|
||||
@@ -75,10 +78,12 @@ func build(a fyne.App, version string) (*app, error) {
|
||||
footer := container.NewBorder(
|
||||
widget.NewSeparator(), nil,
|
||||
container.NewHBox(update, github, donate),
|
||||
caption("v"+version),
|
||||
caption("LazyRun v"+version+" · oxpoe"),
|
||||
)
|
||||
|
||||
top := container.NewVBox(header, accentBar(),
|
||||
accent := accentBar()
|
||||
pulseGradient(accent)
|
||||
top := container.NewVBox(header, accent,
|
||||
container.NewHBox(sectionLabel(T("installed")), countChip))
|
||||
body := container.NewBorder(
|
||||
top,
|
||||
@@ -106,12 +111,15 @@ func (ui *app) reload() {
|
||||
if len(ui.store.Items) == 0 {
|
||||
ui.rows.Add(emptyState())
|
||||
}
|
||||
ui.cards = map[string]*hoverCard{}
|
||||
for _, sc := range ui.store.Items {
|
||||
ui.rows.Add(ui.row(sc))
|
||||
row := ui.row(sc)
|
||||
ui.rows.Add(row)
|
||||
ui.cards[sc.Slug] = row
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *app) row(sc store.Shortcut) fyne.CanvasObject {
|
||||
func (ui *app) row(sc store.Shortcut) *hoverCard {
|
||||
info := container.NewVBox(
|
||||
subheading(sc.Name),
|
||||
caption(metaText(sc)),
|
||||
@@ -137,11 +145,9 @@ func (ui *app) row(sc store.Shortcut) fyne.CanvasObject {
|
||||
}))
|
||||
actions.Add(iconButton(theme.DeleteIcon(), func() { ui.confirmDelete(sc) }))
|
||||
|
||||
return container.NewVBox(
|
||||
card(container.NewBorder(nil, nil,
|
||||
container.NewHBox(thumb(sc.IconPath, fallbackIcon(sc)), info),
|
||||
actions)),
|
||||
)
|
||||
return newHoverCard(container.NewBorder(nil, nil,
|
||||
container.NewHBox(thumb(sc.IconPath, fallbackIcon(sc)), info),
|
||||
actions))
|
||||
}
|
||||
|
||||
// metaText menampilkan tipe shortcut dan penanda singkatnya.
|
||||
@@ -169,12 +175,23 @@ func emptyState() fyne.CanvasObject {
|
||||
hint := muted(T("empty_hint"))
|
||||
hint.Alignment = fyne.TextAlignCenter
|
||||
return container.NewCenter(container.NewVBox(
|
||||
container.NewCenter(logoImage(88)),
|
||||
container.NewCenter(logoBox(newLogo(), 88)),
|
||||
subheading(T("empty_title")),
|
||||
hint,
|
||||
))
|
||||
}
|
||||
|
||||
// flashCards memberi kilatan berurutan saat daftar dimuat/diubah.
|
||||
func (ui *app) flashCards() {
|
||||
for i, sc := range ui.store.Items {
|
||||
card, ok := ui.cards[sc.Slug]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
card.flash(time.Duration(min(i, 6)) * 70 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *app) confirmDelete(sc store.Shortcut) {
|
||||
content := container.NewVBox(widget.NewLabel(fmt.Sprintf(T("confirm_delete_msg"), sc.Name)))
|
||||
|
||||
@@ -231,6 +248,9 @@ func (ui *app) added(sc store.Shortcut, err error, closeDialog func()) {
|
||||
}
|
||||
closeDialog()
|
||||
ui.reload()
|
||||
if card, ok := ui.cards[sc.Slug]; ok {
|
||||
card.flash(0)
|
||||
}
|
||||
dialog.ShowInformation(T("success_title"), fmt.Sprintf(T("success_msg"), sc.Name), ui.win)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user