Skip to content

Commit 52b1f4a

Browse files
committed
win32: several improvements
1 parent 2859025 commit 52b1f4a

18 files changed

Lines changed: 561 additions & 57 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# EasyWidge
1+
# EasyWeatherWidget
22

33
A compact weather widget for your desktop.
44

assets/demo.png

135 KB
Loading

assets/embed.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ import "embed"
66
//
77
//go:embed icons/*.png
88
var Icons embed.FS
9+
10+
// DemoPNG embeds the demo screenshot shown in the About tab.
11+
//
12+
//go:embed demo.png
13+
var DemoPNG []byte

docs/site/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
<h1 class="hero-title">
5555
Your Desktop.<br />
5656
<span class="gradient-text">Your Weather.</span>
57+
<span class="gradient-text">Local Time.</span>
5758
</h1>
5859
<p class="hero-subtitle">
5960
A compact, transparent weather widget that lives on your desktop.

installer/AppxManifest.xml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55

66
<!--
77
Identity:
8-
- Name: Must match your Microsoft Partner Center reservation (e.g., "12345YourPublisher.WeatherWidget")
9-
- Publisher: Must match your signing certificate subject (e.g., "CN=Your Publisher ID, O=Your Org, L=City, S=State, C=US")
10-
- Update these values after registering your app in Partner Center
8+
- Name and Publisher MUST match the values from Microsoft Partner Center > Product Identity.
9+
- Partner Center App ID: 47955afa-afc7-46ee-abc1-02ab2632b4ad
10+
- Go to Partner Center > Your App > Product Identity to find the exact Name and Publisher values.
11+
- The Publisher field must match exactly (including CN= prefix).
12+
- For Store submissions, Microsoft signs the package — no local certificate needed.
1113
-->
12-
<Identity Name="YourPublisherId.WeatherWidget"
13-
Publisher="CN=YourPublisherId"
14-
Version="1.0.0.0"
14+
<Identity Name="47955afa-afc7-46ee-abc1-02ab2632b4ad"
15+
Publisher="CN=47955afa-afc7-46ee-abc1-02ab2632b4ad"
16+
Version="0.0.5"
1517
ProcessorArchitecture="x64" />
1618

1719
<Properties>

installer/README.md

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,21 @@ installers for the Weather Widget application.
4848
.\installer\build-msi.ps1 -Version "1.0.0.0" -CertPath ".\cert.pfx" -CertPassword "yourpassword"
4949
```
5050

51-
### Build an MSIX for Microsoft Store
51+
### Build an MSIX for Microsoft Store (recommended)
5252

5353
```powershell
54+
# For Store submission — no certificate needed, Microsoft signs it:
55+
.\installer\build-msix.ps1 -Version "1.0.0.0" -StoreUpload
56+
57+
# For local sideload testing with your own cert:
5458
.\installer\build-msix.ps1 -Version "1.0.0.0" -CertPath ".\cert.pfx" -CertPassword "yourpassword"
5559
```
5660

61+
The `-StoreUpload` flag produces an unsigned `.msixupload` file that you
62+
upload directly to Partner Center. Microsoft signs the package during
63+
certification — you do not need your own code signing certificate for Store
64+
submissions.
65+
5766
Output goes to `.\build\`.
5867

5968
## Store Assets (MSIX only)
@@ -84,11 +93,25 @@ magick convert icon.png -define icon:auto-resize=256,128,64,48,32,16 icon.ico
8493

8594
## AppxManifest.xml Configuration
8695

87-
Before submitting to the Store, update these fields in `AppxManifest.xml`:
96+
Before submitting to the Store, verify these fields in `AppxManifest.xml`
97+
match your Partner Center **Product Identity** page exactly:
98+
99+
- `Identity Name` — from Partner Center > Product Identity > "Package/Identity/Name"
100+
- `Identity Publisher` — from Partner Center > Product Identity > "Package/Identity/Publisher"
101+
- `PublisherDisplayName` — your publisher display name from Partner Center
102+
103+
The manifest is currently configured with the Partner Center App ID
104+
(`47955afa-afc7-46ee-abc1-02ab2632b4ad`) as a placeholder. You **must**
105+
replace the Name and Publisher with the exact values from your Product
106+
Identity page before uploading, or Partner Center will reject the package.
107+
108+
### How to find your Product Identity values
88109

89-
- `Identity Name` — your Partner Center app reservation name
90-
- `Identity Publisher` — must match your signing certificate subject exactly
91-
- `PublisherDisplayName` — your display name in the Store
110+
1. Go to [Partner Center](https://partner.microsoft.com/dashboard)
111+
2. Select your app (Weather Widget)
112+
3. Go to **Product management** > **Product Identity**
113+
4. Copy the **Package/Identity/Name** and **Package/Identity/Publisher** values
114+
5. Update `installer/AppxManifest.xml` with those values
92115

93116
## File Structure
94117

installer/build-msix.ps1

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,27 @@
22
# Weather Widget - MSIX Package Builder (Microsoft Store)
33
# ============================================================================
44
# Usage:
5-
# .\installer\build-msix.ps1 -Version "1.0.0.0"
5+
# # For Microsoft Store submission (unsigned — Store signs it for you):
6+
# .\installer\build-msix.ps1 -Version "1.0.0.0" -StoreUpload
7+
#
8+
# # For local testing with self-signed cert:
69
# .\installer\build-msix.ps1 -Version "1.0.0.0" -CertPath "cert.pfx" -CertPassword "pass"
10+
#
11+
# # For local testing without signing:
712
# .\installer\build-msix.ps1 -Version "1.0.0.0" -SkipSign
813
#
914
# Prerequisites:
1015
# - Go 1.25+ with CGO enabled (for Fyne)
1116
# - go-winres: go install github.com/tc-hib/go-winres@latest
1217
# - Windows SDK (for MakeAppx.exe and SignTool.exe)
13-
# - Code signing certificate (for production builds)
18+
# - Code signing certificate (only for local/sideload builds)
19+
#
20+
# Microsoft Store Notes:
21+
# - Use -StoreUpload to produce an .msixupload file for Partner Center.
22+
# - The Store signs the package — you do NOT need a certificate for submission.
23+
# - The AppxManifest.xml Identity Name and Publisher must match Partner Center
24+
# values exactly. Check Partner Center > Product Identity for your values.
25+
# - Partner Center App ID: 47955afa-afc7-46ee-abc1-02ab2632b4ad
1426
# ============================================================================
1527

1628
param(
@@ -20,7 +32,8 @@ param(
2032
[string]$CertPath = "",
2133
[string]$CertPassword = "",
2234
[switch]$SkipSign,
23-
[switch]$SkipBuild
35+
[switch]$SkipBuild,
36+
[switch]$StoreUpload
2437
)
2538

2639
$ErrorActionPreference = "Stop"
@@ -42,17 +55,28 @@ try {
4255
$BuildDir = ".\build"
4356
$PackageDir = ".\build\package"
4457
$OutputMsix = ".\build\WeatherWidget-$Version.msix"
58+
$OutputMsixUpload = ".\build\WeatherWidget-$Version.msixupload"
59+
60+
# Determine total steps based on mode
61+
if ($StoreUpload) {
62+
$totalSteps = 7
63+
} else {
64+
$totalSteps = 6
65+
}
4566

4667
Write-Host ""
4768
Write-Host "============================================" -ForegroundColor Cyan
4869
Write-Host " Weather Widget MSIX Builder v$Version" -ForegroundColor Cyan
70+
if ($StoreUpload) {
71+
Write-Host " Mode: Microsoft Store Upload" -ForegroundColor Cyan
72+
}
4973
Write-Host "============================================" -ForegroundColor Cyan
5074
Write-Host ""
5175

5276
# -------------------------------------------------------------------------
5377
# Step 1: Clean previous build
5478
# -------------------------------------------------------------------------
55-
Write-Host "[1/6] Cleaning previous build..." -ForegroundColor Yellow
79+
Write-Host "[1/$totalSteps] Cleaning previous build..." -ForegroundColor Yellow
5680
if (Test-Path $BuildDir) { Remove-Item -Recurse -Force $BuildDir }
5781
New-Item -ItemType Directory -Path $PackageDir -Force | Out-Null
5882
New-Item -ItemType Directory -Path "$PackageDir\assets" -Force | Out-Null
@@ -62,7 +86,7 @@ try {
6286
# Step 2: Generate Windows resources (icon, manifest, version info)
6387
# -------------------------------------------------------------------------
6488
if (-not $SkipBuild) {
65-
Write-Host "[2/6] Generating Windows resources..." -ForegroundColor Yellow
89+
Write-Host "[2/$totalSteps] Generating Windows resources..." -ForegroundColor Yellow
6690

6791
# Update version in winres.json before generating
6892
$winresJson = Get-Content ".\winres\winres.json" -Raw | ConvertFrom-Json
@@ -79,7 +103,7 @@ try {
79103
# ---------------------------------------------------------------------
80104
# Step 3: Build the executable
81105
# ---------------------------------------------------------------------
82-
Write-Host "[3/6] Building weatherwidget.exe..." -ForegroundColor Yellow
106+
Write-Host "[3/$totalSteps] Building weatherwidget.exe..." -ForegroundColor Yellow
83107
$env:GOOS = "windows"
84108
$env:GOARCH = "amd64"
85109
$env:CGO_ENABLED = "1"
@@ -89,18 +113,20 @@ try {
89113
if ($LASTEXITCODE -ne 0) { throw "Go build failed" }
90114
Write-Host " Done. Output: $BuildDir\weatherwidget.exe" -ForegroundColor Green
91115
} else {
92-
Write-Host "[2/6] Skipping resource generation (SkipBuild)." -ForegroundColor DarkGray
93-
Write-Host "[3/6] Skipping build (SkipBuild)." -ForegroundColor DarkGray
116+
Write-Host "[2/$totalSteps] Skipping resource generation (SkipBuild)." -ForegroundColor DarkGray
117+
Write-Host "[3/$totalSteps] Skipping build (SkipBuild)." -ForegroundColor DarkGray
94118
if (-not (Test-Path "$BuildDir\weatherwidget.exe")) {
95119
throw "No existing exe found at $BuildDir\weatherwidget.exe. Remove -SkipBuild flag."
96120
}
97121
}
98122

99123
# -------------------------------------------------------------------------
100-
# Step 4: Sign the executable
124+
# Step 4: Sign the executable (skip for Store uploads)
101125
# -------------------------------------------------------------------------
102-
if (-not $SkipSign -and $CertPath) {
103-
Write-Host "[4/6] Signing executable..." -ForegroundColor Yellow
126+
if ($StoreUpload) {
127+
Write-Host "[4/$totalSteps] Skipping exe signing (Store signs the package)." -ForegroundColor DarkGray
128+
} elseif (-not $SkipSign -and $CertPath) {
129+
Write-Host "[4/$totalSteps] Signing executable..." -ForegroundColor Yellow
104130
$signArgs = @(
105131
"sign", "/fd", "SHA256",
106132
"/tr", "http://timestamp.digicert.com",
@@ -114,13 +140,13 @@ try {
114140
if ($LASTEXITCODE -ne 0) { throw "Executable signing failed" }
115141
Write-Host " Done." -ForegroundColor Green
116142
} else {
117-
Write-Host "[4/6] Skipping exe signing." -ForegroundColor DarkGray
143+
Write-Host "[4/$totalSteps] Skipping exe signing." -ForegroundColor DarkGray
118144
}
119145

120146
# -------------------------------------------------------------------------
121147
# Step 5: Assemble MSIX package layout
122148
# -------------------------------------------------------------------------
123-
Write-Host "[5/6] Assembling package layout..." -ForegroundColor Yellow
149+
Write-Host "[5/$totalSteps] Assembling package layout..." -ForegroundColor Yellow
124150

125151
# Copy exe
126152
Copy-Item "$BuildDir\weatherwidget.exe" "$PackageDir\"
@@ -150,9 +176,9 @@ try {
150176
Write-Host " Done." -ForegroundColor Green
151177

152178
# -------------------------------------------------------------------------
153-
# Step 6: Create and sign MSIX
179+
# Step 6: Create MSIX package
154180
# -------------------------------------------------------------------------
155-
Write-Host "[6/6] Creating MSIX package..." -ForegroundColor Yellow
181+
Write-Host "[6/$totalSteps] Creating MSIX package..." -ForegroundColor Yellow
156182

157183
# Find MakeAppx.exe from Windows SDK
158184
$sdkPaths = @(
@@ -182,9 +208,14 @@ try {
182208

183209
& $makeAppx pack /d $PackageDir /p $OutputMsix /o
184210
if ($LASTEXITCODE -ne 0) { throw "MakeAppx failed" }
211+
Write-Host " Done." -ForegroundColor Green
185212

186-
# Sign the MSIX
187-
if (-not $SkipSign -and $CertPath) {
213+
# -------------------------------------------------------------------------
214+
# Step 6b: Sign the MSIX (local/sideload only — not for Store)
215+
# -------------------------------------------------------------------------
216+
if ($StoreUpload) {
217+
# No signing needed — Partner Center signs Store packages
218+
} elseif (-not $SkipSign -and $CertPath) {
188219
Write-Host " Signing MSIX..." -ForegroundColor Yellow
189220
$signArgs = @(
190221
"sign", "/fd", "SHA256",
@@ -197,17 +228,50 @@ try {
197228

198229
& signtool @signArgs
199230
if ($LASTEXITCODE -ne 0) { throw "MSIX signing failed" }
231+
Write-Host " Signed." -ForegroundColor Green
232+
}
233+
234+
# -------------------------------------------------------------------------
235+
# Step 7 (Store only): Create .msixupload for Partner Center
236+
# -------------------------------------------------------------------------
237+
if ($StoreUpload) {
238+
Write-Host "[7/$totalSteps] Creating .msixupload for Partner Center..." -ForegroundColor Yellow
239+
240+
# .msixupload is a ZIP containing the .msix (and optionally .msixsym)
241+
# Partner Center expects this format for Store submissions.
242+
if (Test-Path $OutputMsixUpload) { Remove-Item $OutputMsixUpload -Force }
243+
Compress-Archive -Path $OutputMsix -DestinationPath $OutputMsixUpload -Force
244+
245+
Write-Host " Done." -ForegroundColor Green
200246
}
201247

248+
# -------------------------------------------------------------------------
249+
# Summary
250+
# -------------------------------------------------------------------------
202251
Write-Host ""
203252
Write-Host "============================================" -ForegroundColor Green
204253
Write-Host " BUILD SUCCESSFUL" -ForegroundColor Green
205-
Write-Host " Output: $OutputMsix" -ForegroundColor Green
254+
Write-Host " MSIX: $OutputMsix" -ForegroundColor Green
255+
if ($StoreUpload) {
256+
Write-Host " Upload: $OutputMsixUpload" -ForegroundColor Green
257+
}
206258
Write-Host "============================================" -ForegroundColor Green
207259
Write-Host ""
208260

209-
if ($SkipSign -or -not $CertPath) {
210-
Write-Host " NOTE: Package is unsigned. For Store submission," -ForegroundColor Yellow
261+
if ($StoreUpload) {
262+
Write-Host " NEXT STEPS for Microsoft Store submission:" -ForegroundColor Cyan
263+
Write-Host " 1. Verify AppxManifest.xml Identity Name and Publisher" -ForegroundColor White
264+
Write-Host " match your Partner Center > Product Identity values." -ForegroundColor White
265+
Write-Host " 2. Replace placeholder store assets in installer\store-assets\" -ForegroundColor White
266+
Write-Host " with properly sized PNGs before final submission." -ForegroundColor White
267+
Write-Host " 3. Upload $OutputMsixUpload to Partner Center." -ForegroundColor White
268+
Write-Host " (Partner Center > Your App > Packages)" -ForegroundColor White
269+
Write-Host " 4. Microsoft will sign the package during certification." -ForegroundColor White
270+
Write-Host ""
271+
Write-Host " Partner Center App ID: 47955afa-afc7-46ee-abc1-02ab2632b4ad" -ForegroundColor DarkGray
272+
Write-Host ""
273+
} elseif ($SkipSign -or -not $CertPath) {
274+
Write-Host " NOTE: Package is unsigned. For sideloading," -ForegroundColor Yellow
211275
Write-Host " provide -CertPath and -CertPassword parameters." -ForegroundColor Yellow
212276
Write-Host ""
213277
}

internal/app/manager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func (a *AppManager) applyPosition(cfg *config.Config) {
155155
a.ui.SetPosition(*cfg.CustomX, *cfg.CustomY)
156156
log.Printf("positioned widget at custom coordinates (%d, %d)", *cfg.CustomX, *cfg.CustomY)
157157
} else {
158-
a.ui.SetCorner(cfg.CornerPosition)
158+
a.ui.SetCorner(cfg.CornerPosition, cfg.MonitorIndex)
159159
}
160160
opacity := cfg.Opacity
161161
if opacity == 0 {

internal/config/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Config struct {
1414
Cities []CityConfig `json:"cities"`
1515
RefreshInterval int `json:"refreshInterval"` // minutes, 1–60, default 10
1616
CornerPosition string `json:"cornerPosition"` // "top-left"|"top-right"|"bottom-left"|"bottom-right"
17+
MonitorIndex int `json:"monitorIndex"` // 0-based monitor index; 0 = primary
1718
CustomX *int `json:"customX,omitempty"`
1819
CustomY *int `json:"customY,omitempty"`
1920
Opacity int `json:"opacity"` // 25, 50, 75, or 100 (percent)

internal/config/validation.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ func Validate(cfg *Config) []ValidationError {
4141
})
4242
}
4343
case "easyweatherwidget":
44-
if cfg.RefreshInterval < 30 {
44+
if cfg.RefreshInterval < 10 {
4545
errs = append(errs, ValidationError{
4646
Field: "refreshInterval",
47-
Message: "must be at least 30 for easyweatherwidget",
47+
Message: "must be at least 10 for easyweatherwidget",
4848
})
4949
}
5050
}

0 commit comments

Comments
 (0)