diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index b4f8327..5be26d7 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ diff --git a/example/aurora/desktop/ru.auroraos.flutter_example_packages.desktop b/example/aurora/desktop/ru.auroraos.flutter_example_packages.desktop index 37ffbea..c2d520f 100644 --- a/example/aurora/desktop/ru.auroraos.flutter_example_packages.desktop +++ b/example/aurora/desktop/ru.auroraos.flutter_example_packages.desktop @@ -7,6 +7,6 @@ Exec=/usr/bin/ru.auroraos.flutter_example_packages X-Nemo-Application-Type=silica-qt5 [X-Application] -Permissions= +Permissions=DeviceInfo,UserDirs OrganizationName=ru.auroraos ApplicationName=flutter_example_packages diff --git a/example/lib/packages/cached_network_image/model.dart b/example/lib/packages/cached_network_image/model.dart index e18db81..3a1be07 100644 --- a/example/lib/packages/cached_network_image/model.dart +++ b/example/lib/packages/cached_network_image/model.dart @@ -5,13 +5,4 @@ import 'package:scoped_model/scoped_model.dart'; class CachedNetworkImageModel extends Model { /// Get [ScopedModel] static CachedNetworkImageModel of(BuildContext context) => ScopedModel.of(context); - - /// Error - String? _error; - - /// Public error - String? get error => _error; - - /// Public is error - bool get isError => _error != null; -} \ No newline at end of file +} diff --git a/example/lib/packages/cached_network_image/page.dart b/example/lib/packages/cached_network_image/page.dart index c875060..59fd59e 100644 --- a/example/lib/packages/cached_network_image/page.dart +++ b/example/lib/packages/cached_network_image/page.dart @@ -1,3 +1,4 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_example_packages/base/di/app_di.dart'; import 'package:flutter_example_packages/base/package/package.dart'; @@ -6,7 +7,6 @@ import 'package:flutter_example_packages/packages/cached_network_image/package.d import 'package:flutter_example_packages/widgets/base/export.dart'; import 'package:flutter_example_packages/widgets/blocks/block_alert.dart'; import 'package:flutter_example_packages/widgets/blocks/block_info_package.dart'; -import 'package:flutter_example_packages/widgets/blocks/block_item.dart'; import 'package:flutter_example_packages/widgets/layouts/block_layout.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -39,18 +39,19 @@ class _CachedNetworkImagePageState extends AppState { crossAxisAlignment: CrossAxisAlignment.start, children: [ BlockInfoPackage(widget.package), - BlockAlert(model.error), - if (!model.isError) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BlockItem( - title: l10n.cachedNetworkImageTitle, - desc: l10n.cachedNetworkImageDesc, - value: null, - ), - ], + SizedBox( + width: double.infinity, + height: 150, + child: Center( + child: CachedNetworkImage( + imageUrl: "https://via.placeholder.com/350x150", + placeholder: (context, url) => + const CircularProgressIndicator(), + errorWidget: (context, url, error) => + const Icon(Icons.error), + ), ), + ), ], ), ), diff --git a/example/lib/packages/flutter_cache_manager/model.dart b/example/lib/packages/flutter_cache_manager/model.dart deleted file mode 100644 index a296151..0000000 --- a/example/lib/packages/flutter_cache_manager/model.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:scoped_model/scoped_model.dart'; - -/// Model for [FlutterCacheManagerPage] -class FlutterCacheManagerModel extends Model { - /// Get [ScopedModel] - static FlutterCacheManagerModel of(BuildContext context) => ScopedModel.of(context); - - /// Error - String? _error; - - /// Public error - String? get error => _error; - - /// Public is error - bool get isError => _error != null; -} \ No newline at end of file diff --git a/example/lib/packages/flutter_cache_manager/package.dart b/example/lib/packages/flutter_cache_manager/package.dart index 71452e8..fa6e8c5 100644 --- a/example/lib/packages/flutter_cache_manager/package.dart +++ b/example/lib/packages/flutter_cache_manager/package.dart @@ -1,11 +1,7 @@ -import 'package:flutter_example_packages/base/package/package_page.dart'; -import 'package:flutter_example_packages/packages/flutter_cache_manager/page.dart'; -import 'package:get_it/get_it.dart'; - -import 'model.dart'; +import 'package:flutter_example_packages/base/package/package_dialog.dart'; /// Package values -final packageFlutterCacheManager = PackagePage( +final packageFlutterCacheManager = PackageDialog( key: 'flutter_cache_manager', descEN: ''' CacheManager v2 introduced some breaking changes when configuring @@ -15,11 +11,14 @@ final packageFlutterCacheManager = PackagePage( В CacheManager v2 были внесены некоторые критические изменения при настройке пользовательского CacheManager. ''', + messageEN: ''' + This is a platform dependent plugin, used in a plugin + cached_network_image should work for you too. + ''', + messageRU: ''' + Это плагин зависимый от платформы, используется в плагине + cached_network_image, должен работать и у вас. + ''', version: '3.3.0', isPlatformDependent: true, - page: () => FlutterCacheManagerPage(), - init: () { - GetIt.instance.registerFactory( - () => FlutterCacheManagerModel()); - }, ); diff --git a/example/lib/packages/flutter_cache_manager/page.dart b/example/lib/packages/flutter_cache_manager/page.dart deleted file mode 100644 index 2c073e3..0000000 --- a/example/lib/packages/flutter_cache_manager/page.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_example_packages/base/di/app_di.dart'; -import 'package:flutter_example_packages/base/package/package.dart'; -import 'package:flutter_example_packages/packages/flutter_cache_manager/model.dart'; -import 'package:flutter_example_packages/packages/flutter_cache_manager/package.dart'; -import 'package:flutter_example_packages/widgets/base/export.dart'; -import 'package:flutter_example_packages/widgets/blocks/block_alert.dart'; -import 'package:flutter_example_packages/widgets/blocks/block_info_package.dart'; -import 'package:flutter_example_packages/widgets/blocks/block_item.dart'; -import 'package:flutter_example_packages/widgets/layouts/block_layout.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - -class FlutterCacheManagerPage extends AppStatefulWidget { - FlutterCacheManagerPage({ - super.key, - }); - - final Package package = packageFlutterCacheManager; - - @override - State createState() => - _FlutterCacheManagerPageState(); -} - -class _FlutterCacheManagerPageState extends AppState { - @override - Widget buildWide( - BuildContext context, - MediaQueryData media, - AppLocalizations l10n, - ) { - return BlockLayout( - model: getIt(), - title: widget.package.key, - builder: (context, child, model) { - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BlockInfoPackage(widget.package), - BlockAlert(model.error), - if (!model.isError) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BlockItem( - title: l10n.flutterCacheManagerTitle, - desc: l10n.flutterCacheManagerDesc, - value: null, - ), - ], - ), - ], - ), - ), - ); - }, - ); - } -} diff --git a/example/lib/pages/home/model.dart b/example/lib/pages/home/model.dart index 0e8460a..0b9be85 100644 --- a/example/lib/pages/home/model.dart +++ b/example/lib/pages/home/model.dart @@ -1,8 +1,71 @@ import 'package:flutter/widgets.dart'; +import 'package:flutter_example_packages/base/package/package.dart'; +import 'package:flutter_example_packages/base/package/package_page.dart'; +import 'package:flutter_example_packages/packages/packages.dart' as list; +import 'package:flutter_example_packages/pages/home/widgets/home_app_bar.dart'; import 'package:scoped_model/scoped_model.dart'; /// Model for [HomePage] class HomeModel extends Model { /// Get [ScopedModel] - static HomeModel of(BuildContext context) => ScopedModel.of(context); -} \ No newline at end of file + static HomeModel of(BuildContext context) => + ScopedModel.of(context); + + /// Get all list packages + final List packages = list.packages; + + /// Filtered list packages + List _filteredPackages = list.packages; + + /// Public filtered list packages + List get filteredPackages => _filteredPackages; + + /// Get count packages + int get fullSize => packages.length; + + /// Check is search + bool get isSearch => _search.isNotEmpty; + + /// Search text + String _search = ""; + + /// Filter list packages + PlatformFilter _filter = PlatformFilter.disable; + + /// Update state filtered + void updateFilterState( + String search, + PlatformFilter filter, + ) { + _search = search; + _filter = filter; + _filteredPackages = _filterPackages(); + notifyListeners(); + } + + /// Filter list packages + List _filterPackages() { + return packages.where((element) { + bool result = true; + switch (_filter) { + case PlatformFilter.dependent: + result = element.isPlatformDependent == true; + break; + case PlatformFilter.independent: + result = element.isPlatformDependent == false; + break; + case PlatformFilter.demo: + result = element is PackagePage; + break; + case PlatformFilter.disable: + break; + } + if (_search.isNotEmpty) { + if (!element.key.contains(_search)) { + result = false; + } + } + return result; + }).toList(); + } +} diff --git a/example/lib/pages/home/page.dart b/example/lib/pages/home/page.dart index a6d8892..701194a 100644 --- a/example/lib/pages/home/page.dart +++ b/example/lib/pages/home/page.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_example_packages/base/di/app_di.dart'; -import 'package:flutter_example_packages/base/package/package.dart'; import 'package:flutter_example_packages/extensions/keys_ext.dart'; -import 'package:flutter_example_packages/packages/packages.dart'; import 'package:flutter_example_packages/pages/home/model.dart'; import 'package:flutter_example_packages/pages/home/widgets/home_app_bar.dart'; import 'package:flutter_example_packages/pages/home/widgets/package_list_item.dart'; @@ -23,12 +21,17 @@ class HomePage extends AppStatefulWidget { } class _HomePageState extends AppState { - final _header = GlobalKey(); double _hH = 0; - String _search = ""; - PlatformFilter _filter = PlatformFilter.disable; + final _header = GlobalKey(); + final HomeModel _model = getIt(); final ScrollController _controllerListView = ScrollController(); + @override + void initState() { + super.initState(); + + } + @override void onDidChangeMetrics() { setState(() { @@ -36,59 +39,23 @@ class _HomePageState extends AppState { }); } - List filterPackages( - String search, - PlatformFilter filter, - ) { - return packages.where((element) { - bool result = true; - switch (_filter) { - case PlatformFilter.dependent: - result = element.isPlatformDependent == true; - break; - case PlatformFilter.independent: - result = element.isPlatformDependent == false; - break; - case PlatformFilter.disable: - break; - } - if (_search.isNotEmpty) { - if (!element.key.contains(_search)) { - result = false; - } - } - return result; - }).toList(); - } - @override Widget buildWide( BuildContext context, MediaQueryData media, AppLocalizations l10n, ) { - final packagesFilter = filterPackages(_search, _filter); return BlockLayout( - model: getIt(), + model: _model, builder: (context, child, model) { return Scaffold( backgroundColor: Colors.blueGrey, appBar: HomeAppBar( - onChangeSearch: (String text) { - if (packagesFilter.isNotEmpty) { - _controllerListView.jumpTo(0); - } - setState(() { - _search = text; - }); - }, - onChangeFilter: (PlatformFilter filter) { - if (packagesFilter.isNotEmpty) { + onChangeFiltered: (String search, PlatformFilter filter) { + if (model.filteredPackages.isNotEmpty) { _controllerListView.jumpTo(0); } - setState(() { - _filter = filter; - }); + model.updateFilterState(search, filter); }, ), body: GestureDetector( @@ -98,7 +65,7 @@ class _HomePageState extends AppState { child: Stack( children: [ Visibility( - visible: _search.isEmpty, + visible: !model.isSearch, child: Container( height: _hH > 0 ? _hH : 0, color: AppColors.primary, @@ -124,7 +91,7 @@ class _HomePageState extends AppState { ), ), Visibility( - visible: _search.isEmpty, + visible: !model.isSearch, child: Container( key: _header, width: double.infinity, @@ -150,29 +117,29 @@ class _HomePageState extends AppState { : 20, ), TextTitleMedium( - l10n.homeWelcomeText(packages.length), + l10n.homeWelcomeText(model.fullSize), color: Colors.white, ) ], ), ), ), - if (packagesFilter.isNotEmpty) + if (model.filteredPackages.isNotEmpty) ListView.builder( keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, controller: _controllerListView, padding: EdgeInsets.only( - top: _hH > 0 && _search.isEmpty ? _hH - 20 : 0), - itemCount: packagesFilter.length, + top: _hH > 0 && !model.isSearch ? _hH - 20 : 0), + itemCount: model.filteredPackages.length, itemBuilder: (context, index) { return PackageListItemWidget( index: index, - item: packagesFilter[index], + item: model.filteredPackages[index], ); }, ), - if (packagesFilter.isEmpty) + if (model.filteredPackages.isEmpty) Container( width: double.infinity, height: double.infinity, @@ -190,7 +157,7 @@ class _HomePageState extends AppState { child: Column( mainAxisSize: MainAxisSize.min, children: [ - TextTitleSmall( + TextTitleLarge( l10n.homeNotFoundTitle, textAlign: TextAlign.center, ), diff --git a/example/lib/pages/home/widgets/home_app_bar.dart b/example/lib/pages/home/widgets/home_app_bar.dart index c28d2a9..e0b03d6 100644 --- a/example/lib/pages/home/widgets/home_app_bar.dart +++ b/example/lib/pages/home/widgets/home_app_bar.dart @@ -6,17 +6,16 @@ enum PlatformFilter { disable, dependent, independent, + demo, } class HomeAppBar extends AppStatefulWidget implements PreferredSizeWidget { const HomeAppBar({ super.key, - required this.onChangeSearch, - required this.onChangeFilter, + required this.onChangeFiltered, }); - final void Function(String) onChangeSearch; - final void Function(PlatformFilter) onChangeFilter; + final void Function(String, PlatformFilter) onChangeFiltered; @override State createState() => _HomeAppBarState(); @@ -26,10 +25,11 @@ class HomeAppBar extends AppStatefulWidget implements PreferredSizeWidget { } class _HomeAppBarState extends AppState { - bool _enableSearch = false; + String? _search; PlatformFilter _filter = PlatformFilter.disable; - final TextEditingController _searchController = TextEditingController(); - final FocusNode _searchFocus = FocusNode(); + + final _searchController = TextEditingController(); + final _searchFocus = FocusNode(); @override Widget buildWide( @@ -41,7 +41,7 @@ class _HomeAppBarState extends AppState { return AppBar( centerTitle: true, shape: const Border(bottom: BorderSide(width: 0)), - leading: _enableSearch + leading: _search != null ? Padding( padding: const EdgeInsets.all(8.0), child: ClipOval( @@ -52,9 +52,9 @@ class _HomeAppBarState extends AppState { tooltip: l10n.homeSearch, onPressed: () { setState(() { - widget.onChangeSearch.call(""); + _search = null; + widget.onChangeFiltered.call("", _filter); _searchController.clear(); - _enableSearch = false; }); }, ), @@ -62,7 +62,7 @@ class _HomeAppBarState extends AppState { ), ) : null, - title: _enableSearch + title: _search != null ? TextField( focusNode: _searchFocus, controller: _searchController, @@ -76,12 +76,13 @@ class _HomeAppBarState extends AppState { contentPadding: const EdgeInsets.all(0), ), onChanged: (value) { - widget.onChangeSearch.call(value); + _search = value; + widget.onChangeFiltered.call(value, _filter); }, ) : null, actions: [ - if (!_enableSearch) + if (_search == null) Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( @@ -95,7 +96,7 @@ class _HomeAppBarState extends AppState { tooltip: l10n.homeSearch, onPressed: () { setState(() { - _enableSearch = true; + _search = ""; _searchFocus.requestFocus(); }); }, @@ -119,6 +120,8 @@ class _HomeAppBarState extends AppState { return Colors.deepOrangeAccent; case PlatformFilter.independent: return Colors.blueAccent; + case PlatformFilter.demo: + return Colors.green; } }.call(), child: IconButton( @@ -130,6 +133,8 @@ class _HomeAppBarState extends AppState { return const Icon(Icons.filter_list); case PlatformFilter.independent: return const Icon(Icons.filter_list); + case PlatformFilter.demo: + return const Icon(Icons.visibility); } }.call(), tooltip: l10n.homeFilter, @@ -138,17 +143,18 @@ class _HomeAppBarState extends AppState { switch (_filter) { case PlatformFilter.disable: _filter = PlatformFilter.dependent; - widget.onChangeFilter.call(_filter); break; case PlatformFilter.dependent: _filter = PlatformFilter.independent; - widget.onChangeFilter.call(_filter); break; case PlatformFilter.independent: + _filter = PlatformFilter.demo; + break; + case PlatformFilter.demo: _filter = PlatformFilter.disable; - widget.onChangeFilter.call(_filter); break; } + widget.onChangeFiltered.call(_search ?? "", _filter); }); }, ), diff --git a/example/lib/pages/home/widgets/package_list_item.dart b/example/lib/pages/home/widgets/package_list_item.dart index c4420b5..9afda07 100644 --- a/example/lib/pages/home/widgets/package_list_item.dart +++ b/example/lib/pages/home/widgets/package_list_item.dart @@ -79,9 +79,27 @@ class PackageListItemWidget extends AppStatelessWidget { color: AppColors.primary.withOpacity(0.2), ), const SizedBox(height: 12), - TextBodySmall( - l10n.homeListVersion(item.version), - color: AppColors.primary.withOpacity(0.7), + Row( + children: [ + Visibility( + visible: item is PackagePage, + child: Row( + children: const [ + Icon( + Icons.visibility, + size: 16, + color: Colors.green, + ), + SizedBox(width: 6), + ], + ), + ), + TextBodySmall( + l10n.homeListVersion(item.version), + color: AppColors.primary + .withOpacity(0.7), + ), + ], ), ], ), diff --git a/example/pubspec.lock b/example/pubspec.lock index fa23710..4750e56 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -120,6 +120,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "8.6.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.3" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" characters: dependency: transitive description: @@ -251,6 +272,20 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" + flutter_cache_manager: + dependency: "direct main" + description: + name: flutter_cache_manager + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.0" flutter_lints: dependency: "direct dev" description: @@ -476,6 +511,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" + octo_image: + dependency: transitive + description: + name: octo_image + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" package_config: dependency: transitive description: @@ -560,6 +602,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.7" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.1" petitparser: dependency: transitive description: @@ -616,6 +665,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.3" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.dartlang.org" + source: hosted + version: "0.27.7" scoped_model: dependency: "direct main" description: @@ -705,6 +761,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.9.0" + sqflite: + dependency: transitive + description: + name: sqflite + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.8+4" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.5+1" stack_trace: dependency: transitive description: @@ -733,6 +803,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" term_glyph: dependency: transitive description: @@ -782,6 +859,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.7.0" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.7" vector_math: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index efbe50f..074efcd 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -27,6 +27,10 @@ dependencies: universal_io: ^2.2.0 ## https://pub.dev/packages/crypto crypto: ^3.0.2 + ## https://pub.dev/packages/cached_network_image + cached_network_image: ^3.2.3 + ## https://pub.dev/packages/flutter_cache_manager + flutter_cache_manager: ^3.3.0 ## https://os-git.omprussia.ru/non-oss/flutter/flutter-plugins/-/tree/master/packages/xdga_directories xdga_directories: diff --git a/example/web/favicon.png b/example/web/favicon.png deleted file mode 100644 index 8aaa46a..0000000 Binary files a/example/web/favicon.png and /dev/null differ diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfe..0000000 Binary files a/example/web/icons/Icon-192.png and /dev/null differ diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48..0000000 Binary files a/example/web/icons/Icon-512.png and /dev/null differ diff --git a/example/web/icons/Icon-maskable-192.png b/example/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d7..0000000 Binary files a/example/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/example/web/icons/Icon-maskable-512.png b/example/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c566..0000000 Binary files a/example/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/example/web/index.html b/example/web/index.html deleted file mode 100644 index be172b7..0000000 --- a/example/web/index.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - flutter_example_packages - - - - - - - - - - diff --git a/example/web/manifest.json b/example/web/manifest.json deleted file mode 100644 index 090d9c0..0000000 --- a/example/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "flutter_example_packages", - "short_name": "flutter_example_packages", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -}