mirror of
https://github.com/photoprism/photoprism.git
synced 2026-07-17 16:49:04 +00:00
PWA: Only emit maskable icons when the variant exists #5696
This commit is contained in:
parent
4b33d3bd1a
commit
b7e758c607
8 changed files with 76 additions and 9 deletions
|
|
@ -98,6 +98,7 @@ func (c *Config) AppConfig() pwa.Config {
|
|||
BaseUri: c.BaseUri("/"),
|
||||
FrontendUri: c.FrontendUri(""),
|
||||
StaticUri: c.StaticUri(),
|
||||
StaticPath: c.StaticPath(),
|
||||
SiteUrl: c.SiteUrl(),
|
||||
CdnUrl: c.CdnUrl("/"),
|
||||
ThemeUri: ThemeUri,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ type Config struct {
|
|||
BaseUri string `json:"baseUri"`
|
||||
FrontendUri string `json:"frontendUri"`
|
||||
StaticUri string `json:"staticUri"`
|
||||
StaticPath string `json:"staticPath"`
|
||||
SiteUrl string `json:"siteUrl"`
|
||||
CdnUrl string `json:"cdnUrl"`
|
||||
ThemeUri string `json:"themeUri"`
|
||||
|
|
|
|||
|
|
@ -89,7 +89,14 @@ func NewIcons(c Config) Icons {
|
|||
|
||||
// Adaptive launcher icons generated from a safe-zone-padded source so Android
|
||||
// fills the home-screen mask shape instead of letterboxing the default icon.
|
||||
// Emitted only for sizes whose file exists on disk so the manifest never
|
||||
// advertises a maskable variant that resolves to a 404, e.g. for custom icon
|
||||
// sets without pre-rendered maskable images.
|
||||
for _, d := range MaskableIconSizes {
|
||||
if !maskableIconExists(c.StaticPath, appIcon, d) {
|
||||
continue
|
||||
}
|
||||
|
||||
icons = append(icons, Icon{
|
||||
Src: fmt.Sprintf("%s/icons/%s/maskable/%d.png", staticUri, appIcon, d),
|
||||
Sizes: fmt.Sprintf("%dx%d", d, d),
|
||||
|
|
@ -100,3 +107,16 @@ func NewIcons(c Config) Icons {
|
|||
|
||||
return icons
|
||||
}
|
||||
|
||||
// maskableIconExists reports whether a non-empty maskable icon file of the given
|
||||
// size exists on disk for the specified icon set. It returns false when staticPath
|
||||
// is unset, since the manifest must not reference variants that cannot be verified.
|
||||
func maskableIconExists(staticPath, appIcon string, size int) bool {
|
||||
if staticPath == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
fileName := filepath.Join(staticPath, fs.IconsDir, appIcon, "maskable", fmt.Sprintf("%d.png", size))
|
||||
|
||||
return fs.FileExistsNotEmpty(fileName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
func TestNewIcons(t *testing.T) {
|
||||
t.Run("Standard", func(t *testing.T) {
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", Icon: "test"}
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", StaticPath: fs.Abs("./testdata"), Icon: "test"}
|
||||
result := NewIcons(c)
|
||||
assert.NotEmpty(t, result)
|
||||
assert.Len(t, result, len(IconSizes)+len(MaskableIconSizes))
|
||||
|
|
@ -20,14 +20,9 @@ func TestNewIcons(t *testing.T) {
|
|||
assert.Equal(t, "", result[0].Purpose)
|
||||
})
|
||||
t.Run("Maskable", func(t *testing.T) {
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", Icon: "test"}
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", StaticPath: fs.Abs("./testdata"), Icon: "test"}
|
||||
result := NewIcons(c)
|
||||
maskable := make(Icons, 0, len(MaskableIconSizes))
|
||||
for _, icon := range result {
|
||||
if icon.Purpose == "maskable" {
|
||||
maskable = append(maskable, icon)
|
||||
}
|
||||
}
|
||||
maskable := maskableIcons(result)
|
||||
assert.Len(t, maskable, len(MaskableIconSizes))
|
||||
assert.Equal(t, "https://demo-cdn.photoprism.app/static/icons/test/maskable/192.png", maskable[0].Src)
|
||||
assert.Equal(t, "192x192", maskable[0].Sizes)
|
||||
|
|
@ -35,6 +30,26 @@ func TestNewIcons(t *testing.T) {
|
|||
assert.Equal(t, "https://demo-cdn.photoprism.app/static/icons/test/maskable/512.png", maskable[1].Src)
|
||||
assert.Equal(t, "512x512", maskable[1].Sizes)
|
||||
})
|
||||
t.Run("MaskablePartial", func(t *testing.T) {
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", StaticPath: fs.Abs("./testdata"), Icon: "partial"}
|
||||
result := NewIcons(c)
|
||||
maskable := maskableIcons(result)
|
||||
assert.Len(t, maskable, 1)
|
||||
assert.Equal(t, "https://demo-cdn.photoprism.app/static/icons/partial/maskable/192.png", maskable[0].Src)
|
||||
assert.Len(t, result, len(IconSizes)+1)
|
||||
})
|
||||
t.Run("MaskableMissing", func(t *testing.T) {
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", StaticPath: fs.Abs("./testdata"), Icon: "nomask"}
|
||||
result := NewIcons(c)
|
||||
assert.Empty(t, maskableIcons(result))
|
||||
assert.Len(t, result, len(IconSizes))
|
||||
})
|
||||
t.Run("StaticPathUnset", func(t *testing.T) {
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", Icon: "test"}
|
||||
result := NewIcons(c)
|
||||
assert.Empty(t, maskableIcons(result))
|
||||
assert.Len(t, result, len(IconSizes))
|
||||
})
|
||||
t.Run("Custom", func(t *testing.T) {
|
||||
c := Config{StaticUri: "https://demo-cdn.photoprism.app/static", Icon: "/test.png"}
|
||||
result := NewIcons(c)
|
||||
|
|
@ -56,3 +71,30 @@ func TestNewIcons(t *testing.T) {
|
|||
assert.Equal(t, "", result[0].Purpose)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMaskableIconExists(t *testing.T) {
|
||||
staticPath := fs.Abs("./testdata")
|
||||
t.Run("Exists", func(t *testing.T) {
|
||||
assert.True(t, maskableIconExists(staticPath, "test", 192))
|
||||
assert.True(t, maskableIconExists(staticPath, "test", 512))
|
||||
})
|
||||
t.Run("Missing", func(t *testing.T) {
|
||||
assert.False(t, maskableIconExists(staticPath, "test", 256))
|
||||
assert.False(t, maskableIconExists(staticPath, "partial", 512))
|
||||
assert.False(t, maskableIconExists(staticPath, "nomask", 192))
|
||||
})
|
||||
t.Run("StaticPathUnset", func(t *testing.T) {
|
||||
assert.False(t, maskableIconExists("", "test", 192))
|
||||
})
|
||||
}
|
||||
|
||||
// maskableIcons returns the subset of icons emitted with purpose "maskable".
|
||||
func maskableIcons(icons Icons) Icons {
|
||||
maskable := make(Icons, 0, len(MaskableIconSizes))
|
||||
for _, icon := range icons {
|
||||
if icon.Purpose == "maskable" {
|
||||
maskable = append(maskable, icon)
|
||||
}
|
||||
}
|
||||
return maskable
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
)
|
||||
|
||||
func TestNewManifest(t *testing.T) {
|
||||
c := Config{
|
||||
Icon: "logo",
|
||||
Icon: "test",
|
||||
Color: "#aaaaaa",
|
||||
Name: "TestPrism+",
|
||||
Description: "App's Description",
|
||||
|
|
@ -17,6 +19,7 @@ func TestNewManifest(t *testing.T) {
|
|||
BaseUri: "/",
|
||||
FrontendUri: "/library",
|
||||
StaticUri: "/static",
|
||||
StaticPath: fs.Abs("./testdata"),
|
||||
}
|
||||
|
||||
t.Run("Standard", func(t *testing.T) {
|
||||
|
|
|
|||
BIN
internal/config/pwa/testdata/icons/partial/maskable/192.png
vendored
Normal file
BIN
internal/config/pwa/testdata/icons/partial/maskable/192.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9 KiB |
BIN
internal/config/pwa/testdata/icons/test/maskable/192.png
vendored
Normal file
BIN
internal/config/pwa/testdata/icons/test/maskable/192.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9 KiB |
BIN
internal/config/pwa/testdata/icons/test/maskable/512.png
vendored
Normal file
BIN
internal/config/pwa/testdata/icons/test/maskable/512.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
Loading…
Add table
Add a link
Reference in a new issue