diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 3fdc6ce..bfcdc28 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -434,6 +434,12 @@ private function getIconsNode(string $info): ArrayNodeDefinition ->treatTrueLike([]) ->treatNullLike([]) ->arrayPrototype() + ->beforeNormalization() + ->ifString() + ->then(static fn (string $v): array => [ + 'src' => $v, + ]) + ->end() ->children() ->scalarNode('src') ->isRequired() @@ -502,6 +508,12 @@ private function getScreenshotsNode(string $info): ArrayNodeDefinition ->treatTrueLike([]) ->treatNullLike([]) ->arrayPrototype() + ->beforeNormalization() + ->ifString() + ->then(static fn (string $v): array => [ + 'src' => $v, + ]) + ->end() ->children() ->scalarNode('src') ->info('The path to the screenshot. Can be served by Asset Mapper.') diff --git a/src/Normalizer/IconNormalizer.php b/src/Normalizer/IconNormalizer.php index 77bc4af..599e2d2 100644 --- a/src/Normalizer/IconNormalizer.php +++ b/src/Normalizer/IconNormalizer.php @@ -5,14 +5,18 @@ namespace SpomkyLabs\PwaBundle\Normalizer; use SpomkyLabs\PwaBundle\Dto\Icon; +use SpomkyLabs\PwaBundle\ImageProcessor\ImageProcessor; use Symfony\Component\AssetMapper\AssetMapperInterface; +use Symfony\Component\AssetMapper\MappedAsset; +use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use function assert; final readonly class IconNormalizer implements NormalizerInterface { public function __construct( - private AssetMapperInterface $assetMapper + private AssetMapperInterface $assetMapper, + private null|ImageProcessor $imageProcessor, ) { } @@ -20,17 +24,20 @@ public function normalize(mixed $object, string $format = null, array $context = { assert($object instanceof Icon); $url = null; + $asset = null; if (! str_starts_with($object->src, '/')) { - $url = $this->assetMapper->getAsset($object->src)?->publicPath; + $asset = $this->assetMapper->getAsset($object->src); + $url = $asset?->publicPath; } if ($url === null) { $url = $object->src; } + $format = $this->getFormat($object, $asset); $result = [ 'src' => $url, 'sizes' => $object->getSizeList(), - 'type' => $object->format, + 'type' => $format, 'purpose' => $object->purpose, ]; @@ -56,4 +63,18 @@ public function getSupportedTypes(?string $format): array Icon::class => true, ]; } + + private function getFormat(Icon $object, ?MappedAsset $asset): ?string + { + if ($object->format !== null) { + return $object->format; + } + + if ($this->imageProcessor === null || $asset === null || ! class_exists(MimeTypes::class)) { + return null; + } + + $mime = MimeTypes::getDefault(); + return $mime->guessMimeType($asset->sourcePath); + } } diff --git a/src/Twig/PwaRuntime.php b/src/Twig/PwaRuntime.php index 6d38a51..11b7d99 100644 --- a/src/Twig/PwaRuntime.php +++ b/src/Twig/PwaRuntime.php @@ -22,14 +22,40 @@ public function __construct( $this->manifestPublicUrl = '/' . trim($manifestPublicUrl, '/'); } - public function load(): string + public function load(bool $themeColor = true, bool $icons = true): string { $url = $this->assetMapper->getPublicPath($this->manifestPublicUrl) ?? $this->manifestPublicUrl; $output = sprintf('', $url); - if ($this->manifest->themeColor !== null) { + if ($this->manifest->icons !== [] && $icons === true) { + foreach ($this->manifest->icons as $icon) { + $iconUrl = $this->getIconPublicUrl($icon->src); + $output .= sprintf( + '%s', + PHP_EOL, + str_contains($icon->purpose ?? '', 'maskable') ? 'mask-icon' : 'icon', + $icon->getSizeList(), + $iconUrl + ); + } + } + if ($this->manifest->themeColor !== null && $themeColor === true) { $output .= sprintf('%s', PHP_EOL, $this->manifest->themeColor); } return $output; } + + private function getIconPublicUrl(string $source): ?string + { + $url = null; + if (! str_starts_with($source, '/')) { + $asset = $this->assetMapper->getAsset($source); + $url = $asset?->publicPath; + } + if ($url === null) { + $url = $source; + } + + return $url; + } } diff --git a/tests/config.php b/tests/config.php index ae83477..befd97e 100644 --- a/tests/config.php +++ b/tests/config.php @@ -114,16 +114,7 @@ 'scope' => '/app/', 'start_url' => 'https://example.com', 'theme_color' => 'red', - 'screenshots' => [ - [ - 'src' => 'pwa/screenshots/360x800.svg', - 'platform' => 'android', - 'format' => 'png', - 'label' => '360x800', - 'width' => 360, - 'height' => 800, - ], - ], + 'screenshots' => ['pwa/screenshots/360x800.svg'], 'share_target' => [ 'action' => 'shared_content_receiver', 'action_params' => [ @@ -154,21 +145,11 @@ 'name' => 'New reminder', 'url' => '/create/reminder', 'icons' => [ + 'pwa/1920x1920.svg', [ 'src' => 'pwa/1920x1920.svg', - 'sizes' => [48, 72, 96, 128, 256], - 'format' => 'webp', - ], - [ - 'src' => 'pwa/1920x1920.svg', - 'sizes' => [48, 72, 96, 128, 256], - 'format' => 'png', 'purpose' => 'maskable', ], - [ - 'src' => 'pwa/1920x1920.svg', - 'sizes' => [0], - ], ], ], ],