From 550aaf81e5a06a9ef0981e42ae5948d5e9133543 Mon Sep 17 00:00:00 2001 From: Nikolas Rimikis Date: Thu, 2 Nov 2023 15:09:24 +0100 Subject: [PATCH] perf(neon): do not use the spread operator for building lists Signed-off-by: Nikolas Rimikis --- packages/neon/neon/lib/src/app.dart | 6 +- packages/neon/neon/lib/src/pages/login.dart | 83 +++--- .../lib/src/pages/login_check_account.dart | 3 +- .../src/pages/login_check_server_status.dart | 3 +- .../neon/neon/lib/src/pages/login_flow.dart | 45 +-- .../lib/src/pages/nextcloud_app_settings.dart | 39 +-- .../neon/neon/lib/src/pages/settings.dart | 281 +++++++++--------- .../neon/lib/src/widgets/account_tile.dart | 7 +- .../neon/neon/lib/src/widgets/app_bar.dart | 118 ++++---- .../src/widgets/unified_search_results.dart | 6 +- 10 files changed, 303 insertions(+), 288 deletions(-) diff --git a/packages/neon/neon/lib/src/app.dart b/packages/neon/neon/lib/src/app.dart index 856eb204..fa071d50 100644 --- a/packages/neon/neon/lib/src/app.dart +++ b/packages/neon/neon/lib/src/app.dart @@ -120,13 +120,13 @@ class _NeonAppState extends State with WidgetsBindingObserver, tray.Tra await tray.trayManager.setContextMenu( tray.Menu( items: [ - for (final app in _appImplementations) ...[ - tray.MenuItem( + ..._appImplementations.map( + (final app) => tray.MenuItem( key: 'app_${app.id}', label: app.nameFromLocalization(localizations), // TODO: Add icons which should work on macOS and Windows ), - ], + ), tray.MenuItem.separator(), tray.MenuItem( key: 'show_hide', diff --git a/packages/neon/neon/lib/src/pages/login.dart b/packages/neon/neon/lib/src/pages/login.dart index 438c72b6..bfbbcd0a 100644 --- a/packages/neon/neon/lib/src/pages/login.dart +++ b/packages/neon/neon/lib/src/pages/login.dart @@ -67,56 +67,55 @@ class _LoginPageState extends State { branding.name, style: Theme.of(context).textTheme.titleLarge, ), - if (branding.showLoginWithNextcloud) ...[ - const SizedBox( - height: 10, + if (branding.showLoginWithNextcloud) + Padding( + padding: const EdgeInsets.only(top: 10), + child: Text(NeonLocalizations.of(context).loginWorksWith), ), - Text(NeonLocalizations.of(context).loginWorksWith), - const SizedBox( - height: 10, - ), - Semantics( - label: NeonLocalizations.of(context).nextcloud, - child: const NextcloudLogo(), + if (branding.showLoginWithNextcloud) + Padding( + padding: const EdgeInsets.only(top: 10), + child: Semantics( + label: NeonLocalizations.of(context).nextcloud, + child: const NextcloudLogo(), + ), ), - ], - const SizedBox( - height: 50, - ), - Form( - key: _formKey, - child: TextFormField( - focusNode: _focusNode, - controller: _controller, - decoration: InputDecoration( - hintText: 'https://...', - labelText: NeonLocalizations.of(context).loginUsingServerAddress, - suffixIcon: IconButton( - icon: const Icon(Icons.arrow_forward), - onPressed: () { - login(_controller.text); - }, + Padding( + padding: const EdgeInsets.only(top: 50), + child: Form( + key: _formKey, + child: TextFormField( + focusNode: _focusNode, + controller: _controller, + decoration: InputDecoration( + hintText: 'https://...', + labelText: NeonLocalizations.of(context).loginUsingServerAddress, + suffixIcon: IconButton( + icon: const Icon(Icons.arrow_forward), + onPressed: () { + login(_controller.text); + }, + ), ), + keyboardType: TextInputType.url, + validator: (final input) => validateHttpUrl(context, input), + onFieldSubmitted: login, + autofillHints: const [AutofillHints.url], ), - keyboardType: TextInputType.url, - validator: (final input) => validateHttpUrl(context, input), - onFieldSubmitted: login, - autofillHints: const [AutofillHints.url], ), ), - if (NeonPlatform.instance.canUseCamera) ...[ - const SizedBox( - height: 50, - ), - IconButton( - tooltip: NeonLocalizations.of(context).loginUsingQRcode, - icon: const Icon( - Icons.qr_code_scanner_rounded, - size: 60, + if (NeonPlatform.instance.canUseCamera) + Padding( + padding: const EdgeInsets.only(top: 50), + child: IconButton( + tooltip: NeonLocalizations.of(context).loginUsingQRcode, + icon: const Icon( + Icons.qr_code_scanner_rounded, + size: 60, + ), + onPressed: () => const LoginQRcodeRoute().go(context), ), - onPressed: () => const LoginQRcodeRoute().go(context), ), - ], ], ), ), diff --git a/packages/neon/neon/lib/src/pages/login_check_account.dart b/packages/neon/neon/lib/src/pages/login_check_account.dart index c1142bc1..df689ad1 100644 --- a/packages/neon/neon/lib/src/pages/login_check_account.dart +++ b/packages/neon/neon/lib/src/pages/login_check_account.dart @@ -65,7 +65,7 @@ class _LoginCheckAccountPageState extends State { builder: (final context, final state) => Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - if (state.hasError) ...[ + if (state.hasError) Builder( builder: (final context) { final details = NeonError.getDetails(state.error); @@ -77,7 +77,6 @@ class _LoginCheckAccountPageState extends State { ); }, ), - ], _buildAccountTile(state), Align( alignment: Alignment.bottomRight, diff --git a/packages/neon/neon/lib/src/pages/login_check_server_status.dart b/packages/neon/neon/lib/src/pages/login_check_server_status.dart index 042b024f..88e1fd79 100644 --- a/packages/neon/neon/lib/src/pages/login_check_server_status.dart +++ b/packages/neon/neon/lib/src/pages/login_check_server_status.dart @@ -65,12 +65,11 @@ class _LoginCheckServerStatusPageState extends State return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - if (state.hasError) ...[ + if (state.hasError) NeonValidationTile( title: NeonError.getDetails(state.error).getText(context), state: ValidationState.failure, ), - ], _buildServerVersionTile(state), _buildMaintenanceModeTile(state), Align( diff --git a/packages/neon/neon/lib/src/pages/login_flow.dart b/packages/neon/neon/lib/src/pages/login_flow.dart index ef50d6c7..2302e4ec 100644 --- a/packages/neon/neon/lib/src/pages/login_flow.dart +++ b/packages/neon/neon/lib/src/pages/login_flow.dart @@ -6,6 +6,7 @@ import 'package:neon/src/blocs/login_flow.dart'; import 'package:neon/src/router.dart'; import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; +import 'package:nextcloud/core.dart' as core; import 'package:url_launcher/url_launcher_string.dart'; @internal @@ -65,29 +66,35 @@ class _LoginFlowPageState extends State { subject: bloc.init, builder: (final context, final init) => Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ - NeonLinearProgressIndicator( - visible: init.isLoading, - ), - NeonError( - init.error, - onRetry: bloc.refresh, - ), - if (init.hasData) ...[ - Text(NeonLocalizations.of(context).loginSwitchToBrowserWindow), - const SizedBox( - height: 10, - ), - ElevatedButton( - onPressed: bloc.refresh, - child: Text(NeonLocalizations.of(context).loginOpenAgain), - ), - ], - ], + children: _buildChildren(init).toList(), ), ), ), ), ), ); + + Iterable _buildChildren(final Result init) sync* { + yield NeonLinearProgressIndicator( + visible: init.isLoading, + ); + + if (init.hasError) { + yield NeonError( + init.error, + onRetry: bloc.refresh, + ); + } + + if (init.hasData) { + yield Text(NeonLocalizations.of(context).loginSwitchToBrowserWindow); + yield Padding( + padding: const EdgeInsets.only(top: 10), + child: ElevatedButton( + onPressed: bloc.refresh, + child: Text(NeonLocalizations.of(context).loginOpenAgain), + ), + ); + } + } } diff --git a/packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart b/packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart index b26b5451..995aa977 100644 --- a/packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart +++ b/packages/neon/neon/lib/src/pages/nextcloud_app_settings.dart @@ -39,23 +39,7 @@ class NextcloudAppSettingsPage extends StatelessWidget { ); final body = SettingsList( - categories: [ - for (final category in [...appImplementation.options.categories, null]) ...[ - if (appImplementation.options.options.where((final option) => option.category == category).isNotEmpty) ...[ - SettingsCategory( - title: Text( - category != null ? category.name(context) : NeonLocalizations.of(context).optionsCategoryOther, - ), - tiles: [ - for (final option - in appImplementation.options.options.where((final option) => option.category == category)) ...[ - OptionSettingsTile(option: option), - ], - ], - ), - ], - ], - ], + categories: _buildCategories(context).toList(), ); return Scaffold( @@ -71,4 +55,25 @@ class NextcloudAppSettingsPage extends StatelessWidget { ), ); } + + Iterable _buildCategories(final BuildContext context) sync* { + final appOptions = appImplementation.options; + final categories = [...appOptions.categories, null]; + + for (final category in categories) { + final matchedOptions = appOptions.options.where((final option) => option.category == category); + if (matchedOptions.isNotEmpty) { + yield SettingsCategory( + title: Text( + category != null ? category.name(context) : NeonLocalizations.of(context).optionsCategoryOther, + ), + tiles: [ + ...matchedOptions.map( + (final option) => OptionSettingsTile(option: option), + ), + ], + ); + } + } + } } diff --git a/packages/neon/neon/lib/src/pages/settings.dart b/packages/neon/neon/lib/src/pages/settings.dart index c2eb3098..dd35087c 100644 --- a/packages/neon/neon/lib/src/pages/settings.dart +++ b/packages/neon/neon/lib/src/pages/settings.dart @@ -14,7 +14,6 @@ import 'package:neon/src/settings/widgets/custom_settings_tile.dart'; import 'package:neon/src/settings/widgets/option_settings_tile.dart'; import 'package:neon/src/settings/widgets/settings_category.dart'; import 'package:neon/src/settings/widgets/settings_list.dart'; -import 'package:neon/src/settings/widgets/settings_tile.dart'; import 'package:neon/src/settings/widgets/text_settings_tile.dart'; import 'package:neon/src/theme/branding.dart'; import 'package:neon/src/theme/dialog.dart'; @@ -89,7 +88,6 @@ class _SettingsPageState extends State { final globalOptions = NeonProvider.of(context); final accountsBloc = NeonProvider.of(context); final appImplementations = NeonProvider.of>(context); - final branding = Branding.of(context); final appBar = AppBar( title: Text(NeonLocalizations.of(context).settings), @@ -116,24 +114,7 @@ class _SettingsPageState extends State { final body = SettingsList( initialCategory: widget.initialCategory?.name, categories: [ - SettingsCategory( - hasLeading: true, - title: Text(NeonLocalizations.of(context).settingsApps), - key: ValueKey(SettingsCategories.apps.name), - tiles: [ - for (final appImplementation in appImplementations) ...[ - if (appImplementation.options.options.isNotEmpty) ...[ - CustomSettingsTile( - leading: appImplementation.buildIcon(), - title: Text(appImplementation.name(context)), - onTap: () { - NextcloudAppSettingsRoute(appid: appImplementation.id).go(context); - }, - ), - ], - ], - ], - ), + buildAppCategory(), SettingsCategory( title: Text(NeonLocalizations.of(context).optionsCategoryTheme), key: ValueKey(SettingsCategories.theme.name), @@ -159,7 +140,7 @@ class _SettingsPageState extends State { ], ), if (NeonPlatform.instance.canUsePushNotifications) buildNotificationsCategory(), - if (NeonPlatform.instance.canUseWindowManager) ...[ + if (NeonPlatform.instance.canUseWindowManager) SettingsCategory( title: Text(NeonLocalizations.of(context).optionsCategoryStartup), key: ValueKey(SettingsCategories.startup.name), @@ -172,8 +153,7 @@ class _SettingsPageState extends State { ), ], ), - ], - if (NeonPlatform.instance.canUseWindowManager && NeonPlatform.instance.canUseSystemTray) ...[ + if (NeonPlatform.instance.canUseWindowManager && NeonPlatform.instance.canUseSystemTray) SettingsCategory( title: Text(NeonLocalizations.of(context).optionsCategorySystemTray), key: ValueKey(SettingsCategories.systemTray.name), @@ -186,120 +166,8 @@ class _SettingsPageState extends State { ), ], ), - ], ...buildAccountCategory(), - SettingsCategory( - hasLeading: true, - title: Text(NeonLocalizations.of(context).optionsCategoryOther), - key: ValueKey(SettingsCategories.other.name), - tiles: [ - if (branding.sourceCodeURL != null) - CustomSettingsTile( - leading: Icon( - Icons.code, - color: Theme.of(context).colorScheme.primary, - ), - title: Text(NeonLocalizations.of(context).sourceCode), - onTap: () async { - await launchUrlString( - branding.sourceCodeURL!, - mode: LaunchMode.externalApplication, - ); - }, - ), - if (branding.issueTrackerURL != null) - CustomSettingsTile( - leading: Icon( - MdiIcons.textBoxEditOutline, - color: Theme.of(context).colorScheme.primary, - ), - title: Text(NeonLocalizations.of(context).issueTracker), - onTap: () async { - await launchUrlString( - branding.issueTrackerURL!, - mode: LaunchMode.externalApplication, - ); - }, - ), - CustomSettingsTile( - leading: Icon( - MdiIcons.scriptText, - color: Theme.of(context).colorScheme.primary, - ), - title: Text(NeonLocalizations.of(context).licenses), - onTap: () async { - showLicensePage( - context: context, - applicationName: branding.name, - applicationIcon: branding.logo, - applicationLegalese: branding.legalese, - applicationVersion: NeonProvider.of(context).version, - ); - }, - ), - CustomSettingsTile( - leading: Icon( - MdiIcons.export, - color: Theme.of(context).colorScheme.primary, - ), - title: Text(NeonLocalizations.of(context).settingsExport), - onTap: () async { - final settingsExportHelper = _buildSettingsExportHelper(context); - - try { - final fileName = 'nextcloud-neon-settings-${DateTime.now().millisecondsSinceEpoch ~/ 1000}.json'; - - final data = settingsExportHelper.exportToFile(); - await saveFileWithPickDialog(fileName, data); - } catch (e, s) { - debugPrint(e.toString()); - debugPrint(s.toString()); - if (mounted) { - NeonError.showSnackbar(context, e); - } - } - }, - ), - CustomSettingsTile( - leading: Icon( - MdiIcons.import, - color: Theme.of(context).colorScheme.primary, - ), - title: Text(NeonLocalizations.of(context).settingsImport), - onTap: () async { - final settingsExportHelper = _buildSettingsExportHelper(context); - - try { - final result = await FilePicker.platform.pickFiles( - withReadStream: true, - ); - - if (result == null) { - return; - } - - if (!result.files.single.path!.endsWith('.json')) { - if (mounted) { - NeonError.showSnackbar( - context, - NeonLocalizations.of(context).settingsImportWrongFileExtension, - ); - } - return; - } - - await settingsExportHelper.applyFromFile(result.files.single.readStream); - } catch (e, s) { - debugPrint(e.toString()); - debugPrint(s.toString()); - if (mounted) { - NeonError.showSnackbar(context, e); - } - } - }, - ), - ], - ), + buildOtherCategory(), ], ); @@ -317,6 +185,30 @@ class _SettingsPageState extends State { ); } + Widget buildAppCategory() { + final appImplementations = NeonProvider.of>(context); + final appsWithOptions = appImplementations.where( + (final app) => app.options.options.isNotEmpty, + ); + + final tiles = appsWithOptions.map( + (final appImplementation) => CustomSettingsTile( + leading: appImplementation.buildIcon(), + title: Text(appImplementation.name(context)), + onTap: () { + NextcloudAppSettingsRoute(appid: appImplementation.id).go(context); + }, + ), + ); + + return SettingsCategory( + hasLeading: true, + title: Text(NeonLocalizations.of(context).settingsApps), + key: ValueKey(SettingsCategories.apps.name), + tiles: tiles.toList(), + ); + } + Widget buildNotificationsCategory() { final globalOptions = NeonProvider.of(context); @@ -416,6 +308,123 @@ class _SettingsPageState extends State { } } + Widget buildOtherCategory() { + final branding = Branding.of(context); + + return SettingsCategory( + hasLeading: true, + title: Text(NeonLocalizations.of(context).optionsCategoryOther), + key: ValueKey(SettingsCategories.other.name), + tiles: [ + if (branding.sourceCodeURL != null) + CustomSettingsTile( + leading: Icon( + Icons.code, + color: Theme.of(context).colorScheme.primary, + ), + title: Text(NeonLocalizations.of(context).sourceCode), + onTap: () async { + await launchUrlString( + branding.sourceCodeURL!, + mode: LaunchMode.externalApplication, + ); + }, + ), + if (branding.issueTrackerURL != null) + CustomSettingsTile( + leading: Icon( + MdiIcons.textBoxEditOutline, + color: Theme.of(context).colorScheme.primary, + ), + title: Text(NeonLocalizations.of(context).issueTracker), + onTap: () async { + await launchUrlString( + branding.issueTrackerURL!, + mode: LaunchMode.externalApplication, + ); + }, + ), + CustomSettingsTile( + leading: Icon( + MdiIcons.scriptText, + color: Theme.of(context).colorScheme.primary, + ), + title: Text(NeonLocalizations.of(context).licenses), + onTap: () async { + showLicensePage( + context: context, + applicationName: branding.name, + applicationIcon: branding.logo, + applicationLegalese: branding.legalese, + applicationVersion: NeonProvider.of(context).version, + ); + }, + ), + CustomSettingsTile( + leading: Icon( + MdiIcons.export, + color: Theme.of(context).colorScheme.primary, + ), + title: Text(NeonLocalizations.of(context).settingsExport), + onTap: () async { + final settingsExportHelper = _buildSettingsExportHelper(context); + + try { + final fileName = 'nextcloud-neon-settings-${DateTime.now().millisecondsSinceEpoch ~/ 1000}.json'; + + final data = settingsExportHelper.exportToFile(); + await saveFileWithPickDialog(fileName, data); + } catch (e, s) { + debugPrint(e.toString()); + debugPrint(s.toString()); + if (mounted) { + NeonError.showSnackbar(context, e); + } + } + }, + ), + CustomSettingsTile( + leading: Icon( + MdiIcons.import, + color: Theme.of(context).colorScheme.primary, + ), + title: Text(NeonLocalizations.of(context).settingsImport), + onTap: () async { + final settingsExportHelper = _buildSettingsExportHelper(context); + + try { + final result = await FilePicker.platform.pickFiles( + withReadStream: true, + ); + + if (result == null) { + return; + } + + if (!result.files.single.path!.endsWith('.json')) { + if (mounted) { + NeonError.showSnackbar( + context, + NeonLocalizations.of(context).settingsImportWrongFileExtension, + ); + } + return; + } + + await settingsExportHelper.applyFromFile(result.files.single.readStream); + } catch (e, s) { + debugPrint(e.toString()); + debugPrint(s.toString()); + if (mounted) { + NeonError.showSnackbar(context, e); + } + } + }, + ), + ], + ); + } + SettingsExportHelper _buildSettingsExportHelper(final BuildContext context) { final globalOptions = NeonProvider.of(context); final accountsBloc = NeonProvider.of(context); diff --git a/packages/neon/neon/lib/src/widgets/account_tile.dart b/packages/neon/neon/lib/src/widgets/account_tile.dart index fec541f8..a3c8614f 100644 --- a/packages/neon/neon/lib/src/widgets/account_tile.dart +++ b/packages/neon/neon/lib/src/widgets/account_tile.dart @@ -64,10 +64,11 @@ class NeonAccountTile extends StatelessWidget { overflow: TextOverflow.ellipsis, ), ), - if (userDetails.isLoading) - const Expanded( - child: NeonLinearProgressIndicator(), + Expanded( + child: NeonLinearProgressIndicator( + visible: userDetails.isLoading, ), + ), if (userDetails.hasError) NeonError( userDetails.error, diff --git a/packages/neon/neon/lib/src/widgets/app_bar.dart b/packages/neon/neon/lib/src/widgets/app_bar.dart index ac06c62c..90ff34a9 100644 --- a/packages/neon/neon/lib/src/widgets/app_bar.dart +++ b/packages/neon/neon/lib/src/widgets/app_bar.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:intersperse/intersperse.dart'; import 'package:meta/meta.dart'; import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/bloc/result.dart'; @@ -72,53 +73,47 @@ class _NeonAppBarState extends State { stream: unifiedSearchBloc.enabled, builder: (final context, final unifiedSearchEnabledSnapshot) { final unifiedSearchEnabled = unifiedSearchEnabledSnapshot.data ?? false; - return AppBar( - title: unifiedSearchEnabled - ? null - : Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - if (activeAppSnapshot.hasData) ...[ - Flexible( - child: Text( - activeAppSnapshot.requireData.name(context), - ), - ), - ], - if (appImplementations.hasError) ...[ - const SizedBox( - width: 8, - ), - NeonError( - appImplementations.error, - onRetry: appsBloc.refresh, - type: NeonErrorType.iconOnly, - ), - ], - if (appImplementations.isLoading) ...[ - const SizedBox( - width: 8, - ), - Expanded( - child: NeonLinearProgressIndicator( - color: Theme.of(context).appBarTheme.foregroundColor, - ), - ), - ], - ], - ), - if (accounts.length > 1) ...[ - Text( - account.humanReadableID, - style: Theme.of(context).textTheme.bodySmall, - ), - ], - ], + + Widget header = Row( + children: [ + if (activeAppSnapshot.hasData) + Flexible( + child: Text( + activeAppSnapshot.requireData.name(context), ), + ), + if (appImplementations.hasError) + NeonError( + appImplementations.error, + onRetry: appsBloc.refresh, + type: NeonErrorType.iconOnly, + ), + if (appImplementations.isLoading) + Expanded( + child: NeonLinearProgressIndicator( + color: Theme.of(context).appBarTheme.foregroundColor, + ), + ), + ].intersperse(const SizedBox(width: 8)).toList(), + ); + + if (accounts.length > 1) { + header = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + header, + Text( + account.humanReadableID, + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ); + } + + return AppBar( + title: unifiedSearchEnabled ? null : header, actions: [ - if (unifiedSearchEnabled) ...[ + if (unifiedSearchEnabled) Flexible( child: SearchBar( focusNode: _searchBarFocusNode, @@ -137,10 +132,9 @@ class _NeonAppBarState extends State { ), ], ), - ), - ] else ...[ + ) + else const SearchIconButton(), - ], const NotificationIconButton(), const AccountSwitcherButton(), ], @@ -217,21 +211,25 @@ class _NotificationIconButtonState extends State { Future _openNotifications( final NotificationsAppInterface app, ) async { + Widget title = Text(app.name(context)); + + if (_accounts.length > 1) { + title = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + title, + Text( + _account.humanReadableID, + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ); + } + final page = Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(app.name(context)), - if (_accounts.length > 1) ...[ - Text( - _account.humanReadableID, - style: Theme.of(context).textTheme.bodySmall, - ), - ], - ], - ), + title: title, ), body: SafeArea( child: app.page, diff --git a/packages/neon/neon/lib/src/widgets/unified_search_results.dart b/packages/neon/neon/lib/src/widgets/unified_search_results.dart index 26949454..53d1a042 100644 --- a/packages/neon/neon/lib/src/widgets/unified_search_results.dart +++ b/packages/neon/neon/lib/src/widgets/unified_search_results.dart @@ -81,7 +81,7 @@ class NeonUnifiedSearchResults extends StatelessWidget { NeonLinearProgressIndicator( visible: result.isLoading, ), - if (entries.isEmpty) ...[ + if (entries.isEmpty) AdaptiveListTile( leading: const Icon( Icons.close, @@ -89,8 +89,7 @@ class NeonUnifiedSearchResults extends StatelessWidget { ), title: Text(NeonLocalizations.of(context).searchNoResults), ), - ], - for (final entry in entries) ...[ + for (final entry in entries) AdaptiveListTile( leading: NeonImageWrapper( size: const Size.square(largeIconSize), @@ -102,7 +101,6 @@ class NeonUnifiedSearchResults extends StatelessWidget { context.go(entry.resourceUrl); }, ), - ], ], ), ),