Skip to content

Commit 1848103

Browse files
committed
improved the widget panel appearance
1 parent 454b657 commit 1848103

6 files changed

Lines changed: 75 additions & 41 deletions

File tree

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,18 @@ A compact weather widget for your desktop.
1212

1313
![Win32 Transparent Background](images/win32-transparent-background.png)
1414

15-
**Weather Widget Settings**
15+
**Weather Widget Location Settings**
1616

1717
![Weather Widget Settings](images/weather-widget-sesstings.png)
1818

19+
**Weather Widget Appearance Settings**
20+
21+
![Weather Widget Settings](images/weather-widget-sesstings-apperance.png)
22+
23+
## Download
24+
25+
You can download the latest pre-compiled binaries for Windows and Linux from the [GitHub Releases](https://github.com/gcclinux/WeatherWidget/releases) page.
26+
1927
## Compilation
2028

2129
### Windows
54.3 KB
Loading
-21.5 KB
Loading
11.7 KB
Loading

internal/ui/panel/panel.go

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fyne.io/fyne/v2/canvas"
1111
"fyne.io/fyne/v2/container"
1212
"fyne.io/fyne/v2/layout"
13+
"fyne.io/fyne/v2/theme"
1314
"fyne.io/fyne/v2/widget"
1415

1516
"weatherwidget/assets"
@@ -20,10 +21,10 @@ import (
2021
type CityPanel struct {
2122
container *fyne.Container
2223
iconWidget *canvas.Image
23-
tempLabel *widget.Label
24+
tempText *canvas.Text
2425
descLabel *widget.Label
25-
cityLabel *widget.Label
26-
timeLabel *widget.Label
26+
cityText *canvas.Text
27+
timeText *canvas.Text
2728
dateLabel *widget.Label
2829
errorIcon *canvas.Image
2930

@@ -50,42 +51,52 @@ func NewCityPanel() *CityPanel {
5051
res := loadIconFromAssets(weather.IconCloudy)
5152
p.iconWidget = canvas.NewImageFromResource(res)
5253
p.iconWidget.FillMode = canvas.ImageFillContain
53-
p.iconWidget.SetMinSize(fyne.NewSize(40, 40))
54+
p.iconWidget.SetMinSize(fyne.NewSize(64, 64))
5455

5556
// Error indicator icon — hidden by default.
5657
p.errorIcon = canvas.NewImageFromResource(nil)
5758
p.errorIcon.FillMode = canvas.ImageFillContain
5859
p.errorIcon.SetMinSize(fyne.NewSize(16, 16))
5960
p.errorIcon.Hide()
6061

61-
// Labels with placeholder text.
62-
p.tempLabel = widget.NewLabel("--°C")
63-
p.tempLabel.Alignment = fyne.TextAlignCenter
62+
// Labels with appealing typography.
63+
p.cityText = canvas.NewText("City, RG", theme.ForegroundColor())
64+
p.cityText.TextSize = 18
65+
p.cityText.TextStyle = fyne.TextStyle{Bold: true}
66+
p.cityText.Alignment = fyne.TextAlignCenter
67+
68+
p.tempText = canvas.NewText("--°C", theme.ForegroundColor())
69+
p.tempText.TextSize = 42
70+
p.tempText.TextStyle = fyne.TextStyle{Bold: true}
71+
p.tempText.Alignment = fyne.TextAlignCenter
6472

6573
p.descLabel = widget.NewLabel("--")
6674
p.descLabel.Alignment = fyne.TextAlignCenter
75+
p.descLabel.TextStyle = fyne.TextStyle{Italic: true}
6776

68-
p.cityLabel = widget.NewLabel("City, RG")
69-
p.cityLabel.Alignment = fyne.TextAlignCenter
70-
71-
p.timeLabel = widget.NewLabel("--:--:--")
72-
p.timeLabel.Alignment = fyne.TextAlignCenter
77+
p.timeText = canvas.NewText("--:--:--", theme.ForegroundColor())
78+
p.timeText.TextSize = 20
79+
p.timeText.TextStyle = fyne.TextStyle{Bold: true}
80+
p.timeText.Alignment = fyne.TextAlignCenter
7381

7482
p.dateLabel = widget.NewLabel("--/--/----")
7583
p.dateLabel.Alignment = fyne.TextAlignCenter
7684

7785
// Icon row: weather icon + error icon overlay.
7886
iconRow := container.NewHBox(layout.NewSpacer(), p.iconWidget, p.errorIcon, layout.NewSpacer())
7987

80-
// Vertical stack: city, icon, temp, description, time, date.
81-
p.container = container.NewVBox(
82-
container.NewCenter(p.cityLabel),
88+
// Vertical stack with extra breathing room and separators
89+
p.container = container.NewPadded(container.NewVBox(
90+
container.NewCenter(p.cityText),
91+
layout.NewSpacer(),
8392
iconRow,
84-
container.NewCenter(p.tempLabel),
93+
container.NewCenter(p.tempText),
8594
container.NewCenter(p.descLabel),
86-
container.NewCenter(p.timeLabel),
95+
layout.NewSpacer(),
96+
widget.NewSeparator(),
97+
container.NewCenter(p.timeText),
8798
container.NewCenter(p.dateLabel),
88-
)
99+
))
89100

90101
return p
91102
}
@@ -110,9 +121,13 @@ func (p *CityPanel) Update(data *weather.WeatherData) {
110121
}
111122

112123
// Update labels.
113-
p.tempLabel.SetText(weather.FormatTemperature(data.Temperature))
124+
p.tempText.Text = weather.FormatTemperature(data.Temperature)
125+
p.tempText.Refresh()
126+
114127
p.descLabel.SetText(weather.FormatDescription(data.Description))
115-
p.cityLabel.SetText(weather.FormatCityRegion(data.CityName, data.Region))
128+
129+
p.cityText.Text = weather.FormatCityRegion(data.CityName, data.Region)
130+
p.cityText.Refresh()
116131

117132
// Hide error indicator on successful update.
118133
p.errorIcon.Hide()
@@ -158,7 +173,8 @@ func (p *CityPanel) StartClock(timezone string) {
158173

159174
// Set the time immediately before the first tick.
160175
now := time.Now()
161-
p.timeLabel.SetText(weather.FormatTime(now, timezone))
176+
p.timeText.Text = weather.FormatTime(now, timezone)
177+
p.timeText.Refresh()
162178
p.dateLabel.SetText(weather.FormatDate(now, timezone))
163179

164180
go func() {
@@ -170,7 +186,8 @@ func (p *CityPanel) StartClock(timezone string) {
170186
timeStr := weather.FormatTime(t, timezone)
171187
dateStr := weather.FormatDate(t, timezone)
172188
fyne.Do(func() {
173-
p.timeLabel.SetText(timeStr)
189+
p.timeText.Text = timeStr
190+
p.timeText.Refresh()
174191
p.dateLabel.SetText(dateStr)
175192
})
176193
}

internal/ui/panel/panel_test.go

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"testing"
55
"time"
66

7+
"fyne.io/fyne/v2/test"
78
"weatherwidget/internal/weather"
89
)
910

1011
func TestNewCityPanel(t *testing.T) {
12+
test.NewApp()
1113
p := NewCityPanel()
1214
if p == nil {
1315
t.Fatal("NewCityPanel returned nil")
@@ -18,35 +20,36 @@ func TestNewCityPanel(t *testing.T) {
1820
if p.iconWidget == nil {
1921
t.Error("iconWidget is nil")
2022
}
21-
if p.tempLabel == nil {
22-
t.Error("tempLabel is nil")
23+
if p.tempText == nil {
24+
t.Error("tempText is nil")
2325
}
2426
if p.descLabel == nil {
2527
t.Error("descLabel is nil")
2628
}
27-
if p.cityLabel == nil {
28-
t.Error("cityLabel is nil")
29+
if p.cityText == nil {
30+
t.Error("cityText is nil")
2931
}
30-
if p.timeLabel == nil {
31-
t.Error("timeLabel is nil")
32+
if p.timeText == nil {
33+
t.Error("timeText is nil")
3234
}
3335
if p.errorIcon == nil {
3436
t.Error("errorIcon is nil")
3537
}
3638

3739
// Placeholder content checks.
38-
if p.tempLabel.Text != "--°C" {
39-
t.Errorf("tempLabel placeholder = %q, want %q", p.tempLabel.Text, "--°C")
40+
if p.tempText.Text != "--°C" {
41+
t.Errorf("tempText placeholder = %q, want %q", p.tempText.Text, "--°C")
4042
}
41-
if p.cityLabel.Text != "City, RG" {
42-
t.Errorf("cityLabel placeholder = %q, want %q", p.cityLabel.Text, "City, RG")
43+
if p.cityText.Text != "City, RG" {
44+
t.Errorf("cityText placeholder = %q, want %q", p.cityText.Text, "City, RG")
4345
}
4446
if p.errorIcon.Visible() {
4547
t.Error("errorIcon should be hidden initially")
4648
}
4749
}
4850

4951
func TestCityPanel_Container(t *testing.T) {
52+
test.NewApp()
5053
p := NewCityPanel()
5154
c := p.Container()
5255
if c == nil {
@@ -58,6 +61,7 @@ func TestCityPanel_Container(t *testing.T) {
5861
}
5962

6063
func TestCityPanel_Update(t *testing.T) {
64+
test.NewApp()
6165
p := NewCityPanel()
6266

6367
data := &weather.WeatherData{
@@ -72,30 +76,32 @@ func TestCityPanel_Update(t *testing.T) {
7276

7377
p.Update(data)
7478

75-
if p.tempLabel.Text != "24°C" {
76-
t.Errorf("tempLabel = %q, want %q", p.tempLabel.Text, "24°C")
79+
if p.tempText.Text != "24°C" {
80+
t.Errorf("tempText = %q, want %q", p.tempText.Text, "24°C")
7781
}
7882
if p.descLabel.Text != "Partial Sunny" {
7983
t.Errorf("descLabel = %q, want %q", p.descLabel.Text, "Partial Sunny")
8084
}
81-
if p.cityLabel.Text != "Holambra, SP" {
82-
t.Errorf("cityLabel = %q, want %q", p.cityLabel.Text, "Holambra, SP")
85+
if p.cityText.Text != "Holambra, SP" {
86+
t.Errorf("cityText = %q, want %q", p.cityText.Text, "Holambra, SP")
8387
}
8488
if p.errorIcon.Visible() {
8589
t.Error("errorIcon should be hidden after successful update")
8690
}
8791
}
8892

8993
func TestCityPanel_UpdateNil(t *testing.T) {
94+
test.NewApp()
9095
p := NewCityPanel()
9196
// Should not panic.
9297
p.Update(nil)
93-
if p.tempLabel.Text != "--°C" {
94-
t.Errorf("tempLabel should remain placeholder after nil update, got %q", p.tempLabel.Text)
98+
if p.tempText.Text != "--°C" {
99+
t.Errorf("tempText should remain placeholder after nil update, got %q", p.tempText.Text)
95100
}
96101
}
97102

98103
func TestCityPanel_ShowError(t *testing.T) {
104+
test.NewApp()
99105
p := NewCityPanel()
100106

101107
// Non-stale error.
@@ -115,6 +121,7 @@ func TestCityPanel_ShowError(t *testing.T) {
115121
}
116122

117123
func TestCityPanel_ShowErrorThenUpdate(t *testing.T) {
124+
test.NewApp()
118125
p := NewCityPanel()
119126
p.ShowError(false)
120127
if !p.errorIcon.Visible() {
@@ -137,16 +144,17 @@ func TestCityPanel_ShowErrorThenUpdate(t *testing.T) {
137144
}
138145

139146
func TestCityPanel_StartStopClock(t *testing.T) {
147+
test.NewApp()
140148
p := NewCityPanel()
141149

142150
p.StartClock("America/Sao_Paulo")
143151

144152
// Give the ticker a moment to fire.
145153
time.Sleep(1200 * time.Millisecond)
146154

147-
text := p.timeLabel.Text
155+
text := p.timeText.Text
148156
if text == "--/--/---- - --:--:--" {
149-
t.Error("timeLabel should have been updated by the clock")
157+
t.Error("timeText should have been updated by the clock")
150158
}
151159

152160
p.StopClock()
@@ -156,6 +164,7 @@ func TestCityPanel_StartStopClock(t *testing.T) {
156164
}
157165

158166
func TestCityPanel_StartClockReplacesExisting(t *testing.T) {
167+
test.NewApp()
159168
p := NewCityPanel()
160169

161170
p.StartClock("UTC")

0 commit comments

Comments
 (0)