From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 7A5871FF141 for ; Tue, 02 Jun 2026 10:57:47 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 09C0CB268; Tue, 2 Jun 2026 10:55:29 +0200 (CEST) Message-ID: Date: Tue, 2 Jun 2026 10:54:37 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Beta Subject: Re: [PATCH pve_flutter_frontend 2/4] fix: breaking changes due to the upgrade of font_awesome_flutter to v11 To: Shan Shaji , pve-devel@lists.proxmox.com References: <20260410150935.25870-1-s.shaji@proxmox.com> <20260410150935.25870-3-s.shaji@proxmox.com> Content-Language: en-US From: Dominik Csapak In-Reply-To: <20260410150935.25870-3-s.shaji@proxmox.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1780390442638 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.049 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [colors.red,colors.green,pub.dev] Message-ID-Hash: N2CNGJ5FWXFRMCBEYONXFOWYYUYPZ5JV X-Message-ID-Hash: N2CNGJ5FWXFRMCBEYONXFOWYYUYPZ5JV X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: LGTM Reviewed-by: Dominik Csapak On 4/10/26 5:09 PM, Shan Shaji wrote: > Previously, `FaIconData` extended `IconData`, but starting from > `v11.0.0`, `FaIconData` no longer implements `IconData` to prevent > rendering issues and to anticipate `IconData` being marked `final` > in an upcoming Flutter release, which will prevent subtyping outside > of its library. > > Due to this change, the `Icon` widget can no longer directly accept > `FontAwesomeIcons`. To fix this, replace the `Icon` widget with > `FaIcon` wherever `FontAwesomeIcons` is used. > > Signed-off-by: Shan Shaji > --- > lib/pages/main_layout_slim.dart | 4 +- > lib/utils/renderers.dart | 5 +-- > lib/widgets/pve_action_card_widget.dart | 17 +++++++++ > lib/widgets/pve_file_selector_widget.dart | 6 +-- > lib/widgets/pve_guest_backup_widget.dart | 2 +- > lib/widgets/pve_guest_migrate_widget.dart | 4 +- > lib/widgets/pve_guest_os_selector_widget.dart | 4 +- > lib/widgets/pve_guest_overview_header.dart | 4 +- > lib/widgets/pve_lxc_overview.dart | 32 +++++----------- > lib/widgets/pve_node_overview.dart | 6 +-- > lib/widgets/pve_qemu_overview.dart | 38 +++++++------------ > .../pve_qemu_power_settings_widget.dart | 4 +- > pubspec.lock | 4 +- > pubspec.yaml | 2 +- > 14 files changed, 63 insertions(+), 69 deletions(-) > > diff --git a/lib/pages/main_layout_slim.dart b/lib/pages/main_layout_slim.dart > index 4229ef4..c8ab607 100644 > --- a/lib/pages/main_layout_slim.dart > +++ b/lib/pages/main_layout_slim.dart > @@ -861,11 +861,11 @@ class AppBarFilterIconButton extends StatelessWidget { > builder: (context, state) { > return IconButton( > icon: rBloc.isFiltered > - ? const Icon( > + ? const FaIcon( > FontAwesomeIcons.filter, > color: Colors.black, > ) > - : const Icon( > + : const FaIcon( > FontAwesomeIcons.filter, > color: Colors.grey, > ), > diff --git a/lib/utils/renderers.dart b/lib/utils/renderers.dart > index b139a87..5c73539 100644 > --- a/lib/utils/renderers.dart > +++ b/lib/utils/renderers.dart > @@ -35,13 +35,12 @@ class Renderers { > return Icons.storage; > case "qemu": > return Icons.desktop_windows; > - > case "lxc": > - return FontAwesomeIcons.cube; > + return FontAwesomeIcons.cube.data; > case "storage": > return (shared ?? false) > ? Icons.folder_shared > - : FontAwesomeIcons.database; > + : FontAwesomeIcons.database.data; > case "pool": > return Icons.label; > default: > diff --git a/lib/widgets/pve_action_card_widget.dart b/lib/widgets/pve_action_card_widget.dart > index 019a584..9fca232 100644 > --- a/lib/widgets/pve_action_card_widget.dart > +++ b/lib/widgets/pve_action_card_widget.dart > @@ -1,4 +1,5 @@ > import 'package:flutter/material.dart'; > +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; > > class ActionCard extends StatelessWidget { > final Function? onTap; > @@ -14,6 +15,22 @@ class ActionCard extends StatelessWidget { > this.color, > }); > > + factory ActionCard.withIcon(String title, IconData icon, Function onTap) { > + return ActionCard( > + title: title, > + icon: Icon(icon, size: 55, color: Colors.white24), > + onTap: onTap, > + ); > + } > + > + factory ActionCard.withFaIcon(String title, FaIconData icon, Function onTap) { > + return ActionCard( > + title: title, > + icon: FaIcon(icon, size: 55, color: Colors.white24), > + onTap: onTap, > + ); > + } > + > @override > Widget build(BuildContext context) { > return Card( > diff --git a/lib/widgets/pve_file_selector_widget.dart b/lib/widgets/pve_file_selector_widget.dart > index 59964dd..1722e50 100644 > --- a/lib/widgets/pve_file_selector_widget.dart > +++ b/lib/widgets/pve_file_selector_widget.dart > @@ -373,7 +373,7 @@ class FileSelectorContentView extends StatelessWidget { > child: Column( > mainAxisAlignment: MainAxisAlignment.center, > children: [ > - Icon( > + FaIcon( > getContentIcon(content![index].content), > color: Theme.of(context).colorScheme.secondary, > ), > @@ -401,7 +401,7 @@ class FileSelectorContentView extends StatelessWidget { > itemCount: content!.length, > itemBuilder: (context, index) => Card( > child: ListTile( > - leading: Icon( > + leading: FaIcon( > getContentIcon(content![index].content), > color: Theme.of(context).colorScheme.secondary, > ), > @@ -418,7 +418,7 @@ class FileSelectorContentView extends StatelessWidget { > ); > } > > - IconData getContentIcon(PveStorageContentType? content) { > + FaIconData getContentIcon(PveStorageContentType? content) { > switch (content) { > case PveStorageContentType.iso: > return FontAwesomeIcons.compactDisc; > diff --git a/lib/widgets/pve_guest_backup_widget.dart b/lib/widgets/pve_guest_backup_widget.dart > index 4966e9d..119348b 100644 > --- a/lib/widgets/pve_guest_backup_widget.dart > +++ b/lib/widgets/pve_guest_backup_widget.dart > @@ -205,7 +205,7 @@ class PveGuestBackupContent extends StatelessWidget { > itemCount: content!.length, > itemBuilder: (context, index) => Card( > child: ListTile( > - leading: Icon( > + leading: FaIcon( > FontAwesomeIcons.floppyDisk, > color: Theme.of(context).colorScheme.onSurface, > ), > diff --git a/lib/widgets/pve_guest_migrate_widget.dart b/lib/widgets/pve_guest_migrate_widget.dart > index cb6cd38..c65f6fe 100644 > --- a/lib/widgets/pve_guest_migrate_widget.dart > +++ b/lib/widgets/pve_guest_migrate_widget.dart > @@ -55,7 +55,7 @@ class PveGuestMigrate extends StatelessWidget { > crossAxisAlignment: CrossAxisAlignment.start, > children: [ > ListTile( > - leading: const Icon(FontAwesomeIcons.globe), > + leading: const FaIcon(FontAwesomeIcons.globe), > title: Text( > 'Mode', > style: TextStyle(color: colorScheme.onPrimary), > @@ -68,7 +68,7 @@ class PveGuestMigrate extends StatelessWidget { > ), > ), > ListTile( > - leading: const Icon(FontAwesomeIcons.mapPin), > + leading: const FaIcon(FontAwesomeIcons.mapPin), > title: Text( > 'Source', > style: TextStyle(color: colorScheme.onPrimary), > diff --git a/lib/widgets/pve_guest_os_selector_widget.dart b/lib/widgets/pve_guest_os_selector_widget.dart > index 2b3bd82..3a89143 100644 > --- a/lib/widgets/pve_guest_os_selector_widget.dart > +++ b/lib/widgets/pve_guest_os_selector_widget.dart > @@ -40,11 +40,11 @@ class PveGuestOsSelector extends StatelessWidget { > > Widget getIcon(String? osGroup) { > if (osGroup == "Microsoft Windows") { > - return const Icon(FontAwesomeIcons.windows); > + return const FaIcon(FontAwesomeIcons.windows); > } > > if (osGroup == "Linux") { > - return const Icon(FontAwesomeIcons.linux); > + return const FaIcon(FontAwesomeIcons.linux); > } > > return Text(osGroup!); > diff --git a/lib/widgets/pve_guest_overview_header.dart b/lib/widgets/pve_guest_overview_header.dart > index e4b5756..addb888 100644 > --- a/lib/widgets/pve_guest_overview_header.dart > +++ b/lib/widgets/pve_guest_overview_header.dart > @@ -122,7 +122,7 @@ class PveGuestOverviewHeader extends StatelessWidget { > padding: const EdgeInsets.symmetric(horizontal: 20.0), > child: Row( > children: [ > - Icon( > + FaIcon( > FontAwesomeIcons.heartPulse, > color: haError ? Colors.red : Colors.green[400], > ), > @@ -219,7 +219,7 @@ class _PveGuestHeaderRRDPageViewState extends State { > subtitle: Renderers.formatSize(rrdData.last.mem ?? 0), > data: rrdData.where((e) => e.mem != null).map( > (e) => Point(e.time!.millisecondsSinceEpoch, e.mem!)), > - icon: Icon(FontAwesomeIcons.memory, color: fgColor), > + icon: FaIcon(FontAwesomeIcons.memory, color: fgColor), > bottomRight: pageIndicator, > dataRenderer: (data) => Renderers.formatSize(data), > ), > diff --git a/lib/widgets/pve_lxc_overview.dart b/lib/widgets/pve_lxc_overview.dart > index 78ad853..7caa5cf 100644 > --- a/lib/widgets/pve_lxc_overview.dart > +++ b/lib/widgets/pve_lxc_overview.dart > @@ -38,18 +38,6 @@ class PveLxcOverview extends StatelessWidget { > static final routeName = RegExp(r"\/nodes\/(\S+)\/lxc\/(\d+)"); > final String guestID; > > - ActionCard createActionCard(String title, IconData icon, Function onTap) { > - return ActionCard( > - icon: Icon( > - icon, > - size: 55, > - color: Colors.white24, > - ), > - title: title, > - onTap: onTap, > - ); > - } > - > const PveLxcOverview({super.key, required this.guestID}); > @override > Widget build(BuildContext context) { > @@ -139,13 +127,13 @@ class PveLxcOverview extends StatelessWidget { > mainAxisAlignment: MainAxisAlignment.spaceEvenly, > children: [ > if (!(status?.template ?? false)) > - createActionCard( > + ActionCard.withIcon( > 'Power Settings', > Icons.power_settings_new, > () => showPowerMenuBottomSheet( > context, lxcBloc)), > if (!(status?.template ?? false)) > - createActionCard( > + ActionCard.withIcon( > 'Console', > Icons.queue_play_next, > () => showConsoleMenuBottomSheet( > @@ -154,7 +142,7 @@ class PveLxcOverview extends StatelessWidget { > guestID, > state.nodeID, > 'lxc')), > - createActionCard( > + ActionCard.withIcon( > 'Options', > Icons.settings, > () => Navigator.of(context) > @@ -164,7 +152,7 @@ class PveLxcOverview extends StatelessWidget { > ), > fullscreenDialog: true))), > if (!resourceBloc.latestState.isStandalone) > - createActionCard( > + ActionCard.withFaIcon( > 'Migrate', > FontAwesomeIcons.paperPlane, > () => Navigator.of(context).push( > @@ -172,7 +160,7 @@ class PveLxcOverview extends StatelessWidget { > guestID, > state.nodeID, > resourceBloc.apiClient!))), > - createActionCard( > + ActionCard.withFaIcon( > 'Backup', > FontAwesomeIcons.floppyDisk, > () => Navigator.of(context).push( > @@ -193,7 +181,7 @@ class PveLxcOverview extends StatelessWidget { > ), > children: [ > ListTile( > - leading: const Icon(FontAwesomeIcons.memory), > + leading: const FaIcon(FontAwesomeIcons.memory), > title: Text('${config.memory}'), > subtitle: const Text('Memory'), > dense: true, > @@ -211,7 +199,7 @@ class PveLxcOverview extends StatelessWidget { > dense: true, > ), > ListTile( > - leading: const Icon(FontAwesomeIcons.hardDrive), > + leading: const FaIcon(FontAwesomeIcons.hardDrive), > dense: true, > title: Text('${config.rootfs}'), > ), > @@ -229,7 +217,7 @@ class PveLxcOverview extends StatelessWidget { > for (var net in config.net!) > ListTile( > leading: > - const Icon(FontAwesomeIcons.ethernet), > + const FaIcon(FontAwesomeIcons.ethernet), > dense: true, > title: Text(net), > ), > @@ -244,14 +232,14 @@ class PveLxcOverview extends StatelessWidget { > ), > children: [ > ListTile( > - leading: const Icon(FontAwesomeIcons.globe), > + leading: const FaIcon(FontAwesomeIcons.globe), > dense: true, > title: Text( > config.searchdomain ?? 'Use host settings'), > subtitle: const Text('DNS Domain'), > ), > ListTile( > - leading: const Icon( > + leading: const FaIcon( > FontAwesomeIcons.magnifyingGlass), > dense: true, > title: Text( > diff --git a/lib/widgets/pve_node_overview.dart b/lib/widgets/pve_node_overview.dart > index 7236cf4..092bb54 100644 > --- a/lib/widgets/pve_node_overview.dart > +++ b/lib/widgets/pve_node_overview.dart > @@ -115,7 +115,7 @@ class PveNodeOverview extends StatelessWidget { > data: rrd.map((e) => Point( > e.time!.millisecondsSinceEpoch, > e.memused ?? 0)), > - icon: Icon(FontAwesomeIcons.memory, > + icon: FaIcon(FontAwesomeIcons.memory, > color: fgColor), > bottomRight: pageIndicator, > dataRenderer: (data) => > @@ -259,7 +259,7 @@ class PveNodeOverview extends StatelessWidget { > child: ListTile( > title: const Text('HD space (root)'), > subtitle: ProxmoxCapacityIndicator( > - icon: Icon( > + icon: FaIcon( > FontAwesomeIcons.solidHardDrive, > color: Colors.blueGrey[300], > ), > @@ -385,7 +385,7 @@ class PveNodeOverview extends StatelessWidget { > .map( > (d) => ListTile( > dense: true, > - leading: Icon(FontAwesomeIcons.solidHardDrive, > + leading: FaIcon(FontAwesomeIcons.solidHardDrive, > color: state.isDiskHealthy(d) > ? Colors.grey > : Colors.red), > diff --git a/lib/widgets/pve_qemu_overview.dart b/lib/widgets/pve_qemu_overview.dart > index 3fb25ba..12e3b30 100644 > --- a/lib/widgets/pve_qemu_overview.dart > +++ b/lib/widgets/pve_qemu_overview.dart > @@ -40,18 +40,6 @@ class PveQemuOverview extends StatelessWidget { > > const PveQemuOverview({super.key, required this.guestID}); > > - ActionCard createActionCard(String title, IconData icon, Function onTap) { > - return ActionCard( > - icon: Icon( > - icon, > - size: 55, > - color: Colors.white24, > - ), > - title: title, > - onTap: onTap, > - ); > - } > - > @override > Widget build(BuildContext context) { > final bloc = Provider.of(context); > @@ -140,13 +128,13 @@ class PveQemuOverview extends StatelessWidget { > mainAxisAlignment: MainAxisAlignment.spaceEvenly, > children: [ > if (!(status?.template ?? false)) > - createActionCard( > + ActionCard.withIcon( > 'Power Settings', > Icons.power_settings_new, > () => > showPowerMenuBottomSheet(context, bloc)), > if (!(status?.template ?? false)) > - createActionCard( > + ActionCard.withIcon( > 'Console', > Icons.queue_play_next, > () => showConsoleMenuBottomSheet( > @@ -157,19 +145,19 @@ class PveQemuOverview extends StatelessWidget { > 'qemu', > allowSpice: status?.spice ?? false, > )), > - createActionCard( > + ActionCard.withIcon( > 'Options', > Icons.settings, > () => Navigator.of(context) > .push(_createOptionsRoute(bloc))), > if (!rBloc.latestState.isStandalone) > - createActionCard( > + ActionCard.withFaIcon( > 'Migrate', > FontAwesomeIcons.paperPlane, > () => Navigator.of(context).push( > _createMigrationRoute(guestID, > state.nodeID, bloc.apiClient))), > - createActionCard( > + ActionCard.withFaIcon( > 'Backup', > FontAwesomeIcons.floppyDisk, > () => Navigator.of(context).push( > @@ -191,7 +179,7 @@ class PveQemuOverview extends StatelessWidget { > ), > children: [ > ListTile( > - leading: const Icon(FontAwesomeIcons.memory), > + leading: const FaIcon(FontAwesomeIcons.memory), > title: Text('${config.memory}'), > subtitle: const Text('Memory'), > dense: true, > @@ -204,20 +192,20 @@ class PveQemuOverview extends StatelessWidget { > dense: true, > ), > ListTile( > - leading: const Icon(FontAwesomeIcons.microchip), > + leading: const FaIcon(FontAwesomeIcons.microchip), > title: Text( > config.bios?.name ?? 'Default (SeaBIOS)'), > subtitle: const Text('BIOS'), > dense: true, > ), > ListTile( > - leading: const Icon(FontAwesomeIcons.gears), > + leading: const FaIcon(FontAwesomeIcons.gears), > dense: true, > title: Text(config.machine ?? 'Default (i440fx)'), > subtitle: const Text('Machine Type'), > ), > ListTile( > - leading: const Icon(FontAwesomeIcons.database), > + leading: const FaIcon(FontAwesomeIcons.database), > title: Text( > config.scsihw?.name ?? 'Default (i440fx)'), > subtitle: const Text('SCSI Controller'), > @@ -226,21 +214,23 @@ class PveQemuOverview extends StatelessWidget { > for (var ide in config.ide!) > ListTile( > leading: > - const Icon(FontAwesomeIcons.compactDisc), > + const FaIcon(FontAwesomeIcons.compactDisc), > title: Text(ide), > subtitle: const Text('CD/DVD Drive'), > dense: true, > ), > for (var scsi in config.scsi!) > ListTile( > - leading: const Icon(FontAwesomeIcons.hardDrive), > + leading: > + const FaIcon(FontAwesomeIcons.hardDrive), > title: Text(scsi), > subtitle: const Text('Hard Disk'), > dense: true, > ), > for (var net in config.net!) > ListTile( > - leading: const Icon(FontAwesomeIcons.ethernet), > + leading: > + const FaIcon(FontAwesomeIcons.ethernet), > dense: true, > subtitle: const Text('Network Device'), > title: Text(net), > diff --git a/lib/widgets/pve_qemu_power_settings_widget.dart b/lib/widgets/pve_qemu_power_settings_widget.dart > index b4c3c0a..84c3b83 100644 > --- a/lib/widgets/pve_qemu_power_settings_widget.dart > +++ b/lib/widgets/pve_qemu_power_settings_widget.dart > @@ -86,7 +86,7 @@ class PveQemuPowerSettings extends StatelessWidget { > context, PveClusterResourceAction.suspend, bloc), > ), > ListTile( > - leading: const Icon(FontAwesomeIcons.download), > + leading: const FaIcon(FontAwesomeIcons.download), > title: const Text( > "Hibernate", > style: TextStyle(fontWeight: FontWeight.bold), > @@ -106,7 +106,7 @@ class PveQemuPowerSettings extends StatelessWidget { > context, PveClusterResourceAction.stop, bloc), > ), > ListTile( > - leading: const Icon(FontAwesomeIcons.bolt), > + leading: const FaIcon(FontAwesomeIcons.bolt), > title: const Text( > "Reset", > style: TextStyle(fontWeight: FontWeight.bold), > diff --git a/pubspec.lock b/pubspec.lock > index ecaab97..def499d 100644 > --- a/pubspec.lock > +++ b/pubspec.lock > @@ -324,10 +324,10 @@ packages: > dependency: "direct main" > description: > name: font_awesome_flutter > - sha256: b9011df3a1fa02993630b8fb83526368cf2206a711259830325bab2f1d2a4eb0 > + sha256: "09dcde8ab90ffae1a7d65ff2ef96fc62a17ad9d0ce7c127b317ded676b0d5935" > url: "https://pub.dev" > source: hosted > - version: "10.12.0" > + version: "11.0.0" > glob: > dependency: transitive > description: > diff --git a/pubspec.yaml b/pubspec.yaml > index e15d57b..04c56a4 100644 > --- a/pubspec.yaml > +++ b/pubspec.yaml > @@ -30,7 +30,7 @@ dependencies: > path: ^1.8.0 > provider: ^6.0.1 > meta: ^1.1.7 > - font_awesome_flutter: ^10.0.0 > + font_awesome_flutter: ^11.0.0 > url_launcher: ^6.0.17 > intl: ^0.20.1 > path_provider: ^2.0.8