improve image lifecycle handling
This commit is contained in:
+6
-2
@@ -56,6 +56,7 @@ import 'package:weblibre/features/user/domain/repositories/general_settings.dart
|
||||
import 'package:weblibre/presentation/hooks/cached_future.dart';
|
||||
import 'package:weblibre/presentation/hooks/menu_controller.dart';
|
||||
import 'package:weblibre/presentation/icons/weblibre_icons.dart';
|
||||
import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
|
||||
import 'package:weblibre/presentation/widgets/selectable_chips.dart';
|
||||
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
||||
|
||||
@@ -537,8 +538,11 @@ class QuickTabSwitcher extends HookConsumerWidget {
|
||||
},
|
||||
itemAvatar: (item) =>
|
||||
item.tabState?.icon.mapNotNull(
|
||||
(icon) => icon.value.mapNotNull(
|
||||
(image) => RawImage(image: image, height: 24, width: 24),
|
||||
(icon) => SafeRawImage(
|
||||
image: icon,
|
||||
height: 24,
|
||||
width: 24,
|
||||
fallback: UrlIcon([item.url], iconSize: 24),
|
||||
),
|
||||
) ??
|
||||
UrlIcon([item.url], iconSize: 16),
|
||||
|
||||
+6
-5
@@ -20,6 +20,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/states/web_extension.dart';
|
||||
import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
|
||||
|
||||
class ExtensionBadgeIcon extends StatelessWidget {
|
||||
final WebExtensionState state;
|
||||
@@ -36,11 +37,11 @@ class ExtensionBadgeIcon extends StatelessWidget {
|
||||
textColor: state.badgeTextColor,
|
||||
backgroundColor: state.badgeBackgroundColor,
|
||||
child: RepaintBoundary(
|
||||
child:
|
||||
state.icon?.value.mapNotNull(
|
||||
(image) => RawImage(image: image, width: 24, height: 24),
|
||||
) ??
|
||||
const SizedBox(width: 24, height: 24),
|
||||
child: SafeRawImage(
|
||||
image: state.icon,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,11 @@ 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/entities/equatable_image.dart';
|
||||
import 'package:weblibre/domain/services/generic_website.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
|
||||
import 'package:weblibre/presentation/hooks/cached_future.dart';
|
||||
import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
|
||||
|
||||
class TabIcon extends HookConsumerWidget {
|
||||
final TabState tabState;
|
||||
@@ -36,17 +38,16 @@ class TabIcon extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final icon = useCachedFuture(() async {
|
||||
final faviconIcon = tabState.icon?.value;
|
||||
|
||||
if (faviconIcon != null) {
|
||||
return faviconIcon;
|
||||
if (tabState.icon case final EquatableImage tabIcon
|
||||
when !tabIcon.isDisposed) {
|
||||
return tabIcon;
|
||||
}
|
||||
|
||||
final icon = await ref
|
||||
final cachedIcon = await ref
|
||||
.read(genericWebsiteServiceProvider.notifier)
|
||||
.getCachedIcon(tabState.url);
|
||||
|
||||
return icon?.image.value;
|
||||
return cachedIcon?.image;
|
||||
}, [tabState.icon, tabState.url]);
|
||||
|
||||
return Skeletonizer(
|
||||
@@ -56,8 +57,12 @@ class TabIcon extends HookConsumerWidget {
|
||||
child: RepaintBoundary(
|
||||
child:
|
||||
icon.data.mapNotNull(
|
||||
(icon) =>
|
||||
RawImage(image: icon, height: iconSize, width: iconSize),
|
||||
(image) => SafeRawImage(
|
||||
image: image,
|
||||
height: iconSize,
|
||||
width: iconSize,
|
||||
fallback: Icon(MdiIcons.web, size: iconSize),
|
||||
),
|
||||
) ??
|
||||
Icon(MdiIcons.web, size: iconSize),
|
||||
),
|
||||
|
||||
+7
-6
@@ -33,6 +33,7 @@ import 'package:weblibre/features/geckoview/features/find_in_page/domain/entitie
|
||||
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/controllers/find_in_page.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
|
||||
import 'package:weblibre/presentation/hooks/menu_controller.dart';
|
||||
import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
|
||||
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
|
||||
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||
|
||||
@@ -210,7 +211,7 @@ class GridTabPreview extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
if (tabState.thumbnail?.value != null)
|
||||
if (tabState.thumbnail != null && !tabState.thumbnail!.isDisposed)
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
@@ -220,8 +221,8 @@ class GridTabPreview extends HookConsumerWidget {
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: RepaintBoundary(
|
||||
child: RawImage(
|
||||
image: tabState.thumbnail!.value,
|
||||
child: SafeRawImage(
|
||||
image: tabState.thumbnail,
|
||||
fit: BoxFit.fitWidth,
|
||||
),
|
||||
),
|
||||
@@ -290,10 +291,10 @@ class ListTabPreview extends HookConsumerWidget {
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
contentPadding: const EdgeInsets.only(left: 4),
|
||||
leading: (tabState.thumbnail?.value != null)
|
||||
leading: (tabState.thumbnail != null && !tabState.thumbnail!.isDisposed)
|
||||
? RepaintBoundary(
|
||||
child: RawImage(
|
||||
image: tabState.thumbnail!.value,
|
||||
child: SafeRawImage(
|
||||
image: tabState.thumbnail,
|
||||
fit: BoxFit.fitHeight,
|
||||
),
|
||||
)
|
||||
|
||||
+7
-9
@@ -29,6 +29,7 @@ import 'package:weblibre/features/geckoview/features/search/domain/providers/eng
|
||||
import 'package:weblibre/features/geckoview/utils/image_helper.dart';
|
||||
import 'package:weblibre/presentation/hooks/cached_future.dart';
|
||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||
import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
|
||||
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
|
||||
|
||||
class HistorySuggestions extends HookConsumerWidget {
|
||||
@@ -92,15 +93,12 @@ class HistorySuggestions extends HookConsumerWidget {
|
||||
|
||||
return ListTile(
|
||||
leading: RepaintBoundary(
|
||||
child:
|
||||
icon.data?.value.mapNotNull(
|
||||
(image) => RawImage(
|
||||
image: image,
|
||||
height: 24,
|
||||
width: 24,
|
||||
),
|
||||
) ??
|
||||
const Icon(MdiIcons.web, size: 24),
|
||||
child: SafeRawImage(
|
||||
image: icon.data,
|
||||
height: 24,
|
||||
width: 24,
|
||||
fallback: const Icon(MdiIcons.web, size: 24),
|
||||
),
|
||||
),
|
||||
title: suggestion.title.mapNotNull(
|
||||
(title) => Text(
|
||||
|
||||
+6
-3
@@ -39,6 +39,7 @@ import 'package:weblibre/features/geckoview/features/tabs/domain/providers/selec
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab_search.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/presentation/widgets/container_chips.dart';
|
||||
import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
|
||||
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
|
||||
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
||||
import 'package:weblibre/utils/text_highlight.dart';
|
||||
@@ -187,9 +188,11 @@ class TabSearch extends HookConsumerWidget {
|
||||
leading: RepaintBoundary(
|
||||
child:
|
||||
result.icon.mapNotNull(
|
||||
(icon) => icon.value.mapNotNull(
|
||||
(image) =>
|
||||
RawImage(image: image, height: 24, width: 24),
|
||||
(icon) => SafeRawImage(
|
||||
image: icon,
|
||||
height: 24,
|
||||
width: 24,
|
||||
fallback: UrlIcon([result.url], iconSize: 24),
|
||||
),
|
||||
) ??
|
||||
UrlIcon([result.url], iconSize: 24),
|
||||
|
||||
Reference in New Issue
Block a user