improved handling of absent or loading icons

This commit is contained in:
Fabian Freund
2025-08-02 12:31:26 +02:00
parent 1f061d9b3d
commit 411a890df6
4 changed files with 31 additions and 13 deletions
@@ -18,7 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:nullability/nullability.dart';
import 'package:skeletonizer/skeletonizer.dart'; import 'package:skeletonizer/skeletonizer.dart';
import 'package:weblibre/domain/services/generic_website.dart'; import 'package:weblibre/domain/services/generic_website.dart';
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart'; import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
@@ -46,12 +48,16 @@ class TabIcon extends HookConsumerWidget {
}, [state.icon, state.url]); }, [state.icon, state.url]);
return Skeletonizer( return Skeletonizer(
enabled: enabled: icon.connectionState != ConnectionState.done,
icon.connectionState != ConnectionState.done && icon.data == null,
child: Skeleton.replace( child: Skeleton.replace(
replacement: Bone.icon(size: iconSize), replacement: Bone.icon(size: iconSize),
child: RepaintBoundary( child: RepaintBoundary(
child: RawImage(image: icon.data, height: iconSize, width: iconSize), child:
icon.data.mapNotNull(
(icon) =>
RawImage(image: icon, height: iconSize, width: iconSize),
) ??
Icon(MdiIcons.web, size: iconSize),
), ),
), ),
); );
@@ -20,6 +20,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:nullability/nullability.dart'; import 'package:nullability/nullability.dart';
@@ -91,11 +92,15 @@ class HistorySuggestions extends HookConsumerWidget {
return ListTile( return ListTile(
leading: RepaintBoundary( leading: RepaintBoundary(
child: RawImage( child:
image: icon.data?.value, icon.data?.value.mapNotNull(
(favicon) => RawImage(
image: favicon,
height: 24, height: 24,
width: 24, width: 24,
), ),
) ??
const Icon(MdiIcons.web, size: 24),
), ),
title: suggestion.title.mapNotNull( title: suggestion.title.mapNotNull(
(title) => Text(title), (title) => Text(title),
+1 -1
View File
@@ -40,7 +40,7 @@ class UrlIcon extends HookConsumerWidget {
); );
return Skeletonizer( return Skeletonizer(
enabled: !icon.hasData, enabled: icon.connectionState != ConnectionState.done,
child: SizedBox.square( child: SizedBox.square(
dimension: iconSize, dimension: iconSize,
child: (icon.data != null) child: (icon.data != null)
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:nullability/nullability.dart'; import 'package:nullability/nullability.dart';
import 'package:skeletonizer/skeletonizer.dart'; import 'package:skeletonizer/skeletonizer.dart';
@@ -40,11 +41,17 @@ class WebsiteTitleTile extends HookConsumerWidget {
skipLoadingOnReload: true, skipLoadingOnReload: true,
data: (info) { data: (info) {
return ListTile( return ListTile(
leading: RawImage( leading: RepaintBoundary(
image: info.favicon?.image.value, child:
info.favicon.mapNotNull(
(favicon) => RawImage(
image: favicon.image.value,
height: 24, height: 24,
width: 24, width: 24,
), ),
) ??
const Icon(MdiIcons.web, size: 24),
),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: Text( title: Text(
info.title.whenNotEmpty ?? 'Untitled', info.title.whenNotEmpty ?? 'Untitled',