From 411a890df6d70cd8498f1685fbe230efe00ef528 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Sat, 2 Aug 2025 12:31:26 +0200 Subject: [PATCH] improved handling of absent or loading icons --- .../browser/presentation/widgets/tab_icon.dart | 12 +++++++++--- .../search_modules/history_suggestions.dart | 15 ++++++++++----- app/lib/presentation/widgets/url_icon.dart | 2 +- .../presentation/widgets/website_title_tile.dart | 15 +++++++++++---- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_icon.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_icon.dart index ba04564e..0db06a6f 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/tab_icon.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/tab_icon.dart @@ -18,7 +18,9 @@ * along with this program. If not, see . */ 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:nullability/nullability.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:weblibre/domain/services/generic_website.dart'; import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart'; @@ -46,12 +48,16 @@ class TabIcon extends HookConsumerWidget { }, [state.icon, state.url]); return Skeletonizer( - enabled: - icon.connectionState != ConnectionState.done && icon.data == null, + enabled: icon.connectionState != ConnectionState.done, child: Skeleton.replace( replacement: Bone.icon(size: iconSize), 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), ), ), ); diff --git a/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart b/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart index c650bc80..b4dbdd9d 100644 --- a/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart +++ b/app/lib/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart @@ -20,6 +20,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.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:hooks_riverpod/hooks_riverpod.dart'; import 'package:nullability/nullability.dart'; @@ -91,11 +92,15 @@ class HistorySuggestions extends HookConsumerWidget { return ListTile( leading: RepaintBoundary( - child: RawImage( - image: icon.data?.value, - height: 24, - width: 24, - ), + child: + icon.data?.value.mapNotNull( + (favicon) => RawImage( + image: favicon, + height: 24, + width: 24, + ), + ) ?? + const Icon(MdiIcons.web, size: 24), ), title: suggestion.title.mapNotNull( (title) => Text(title), diff --git a/app/lib/presentation/widgets/url_icon.dart b/app/lib/presentation/widgets/url_icon.dart index f1dd7fb6..142f1f24 100644 --- a/app/lib/presentation/widgets/url_icon.dart +++ b/app/lib/presentation/widgets/url_icon.dart @@ -40,7 +40,7 @@ class UrlIcon extends HookConsumerWidget { ); return Skeletonizer( - enabled: !icon.hasData, + enabled: icon.connectionState != ConnectionState.done, child: SizedBox.square( dimension: iconSize, child: (icon.data != null) diff --git a/app/lib/presentation/widgets/website_title_tile.dart b/app/lib/presentation/widgets/website_title_tile.dart index 1d151e49..a675259b 100644 --- a/app/lib/presentation/widgets/website_title_tile.dart +++ b/app/lib/presentation/widgets/website_title_tile.dart @@ -18,6 +18,7 @@ * along with this program. If not, see . */ 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:nullability/nullability.dart'; import 'package:skeletonizer/skeletonizer.dart'; @@ -40,10 +41,16 @@ class WebsiteTitleTile extends HookConsumerWidget { skipLoadingOnReload: true, data: (info) { return ListTile( - leading: RawImage( - image: info.favicon?.image.value, - height: 24, - width: 24, + leading: RepaintBoundary( + child: + info.favicon.mapNotNull( + (favicon) => RawImage( + image: favicon.image.value, + height: 24, + width: 24, + ), + ) ?? + const Icon(MdiIcons.web, size: 24), ), contentPadding: EdgeInsets.zero, title: Text(