diff --git a/lib/src/features/user/presentation/pages/user_settings_block_page.dart b/lib/src/features/user/presentation/pages/user_settings_block_page.dart index 0cb5cc140..b09771757 100644 --- a/lib/src/features/user/presentation/pages/user_settings_block_page.dart +++ b/lib/src/features/user/presentation/pages/user_settings_block_page.dart @@ -209,7 +209,7 @@ class _UserSettingsBlockPageState extends State with Sing context, title: l10n.blockInstance, onInstanceSelected: (instanceWithFederationState) { - context.read().add(UnblockInstanceEvent(instanceId: instanceWithFederationState['id'], unblock: false)); + context.read().add(UnblockInstanceEvent(instanceId: instanceWithFederationState.id!, unblock: false)); }, ); break; diff --git a/lib/src/shared/input_dialogs.dart b/lib/src/shared/input_dialogs.dart index a2c2195db..d65e5a6ef 100644 --- a/lib/src/shared/input_dialogs.dart +++ b/lib/src/shared/input_dialogs.dart @@ -274,30 +274,31 @@ bool _getFavoriteStatus(BuildContext context, ThunderCommunity community) { return state.favorites.any((c) => c.id == community.id); } -/// Shows a dialog which allows typing/search for an instance +/// Shows a dialog which allows typing/search for an instance. Federated instances are loaded in the background; suggestions appear as they load. void showInstanceInputDialog( BuildContext context, { required String title, - required void Function(Map) onInstanceSelected, + required void Function(ThunderInstanceInfo) onInstanceSelected, Iterable>? emptySuggestions, }) async { - Account? account = await fetchActiveProfile(); + final account = await fetchActiveProfile(); + final linkedInstances = []; + unawaited(_loadLinkedInstances(account, linkedInstances)); - final federatedInstances = await InstanceRepositoryImpl(account: account).federated(); - final linkedInstances = federatedInstances['linked']; - - Future onSubmitted({Map? payload, String? value}) async { + Future onSubmitted({ThunderInstanceInfo? payload, String? value}) async { if (payload != null) { onInstanceSelected(payload); Navigator.of(context).pop(); - } else if (value != null) { - final Map? instance = linkedInstances.firstWhereOrNull((Map instance) => instance['domain'] == value); + } else if (value != null && value.trim().isNotEmpty) { + final trimmed = value.trim(); + final instance = linkedInstances.firstWhereOrNull((ThunderInstanceInfo i) => i.domain == trimmed); if (instance != null) { onInstanceSelected(instance); Navigator.of(context).pop(); } else { - return AppLocalizations.of(context)!.unableToFindInstance; + onInstanceSelected(ThunderInstanceInfo(domain: trimmed, name: trimmed)); + Navigator.of(context).pop(); } } @@ -305,7 +306,7 @@ void showInstanceInputDialog( } if (context.mounted) { - showThunderTypeaheadDialog>( + showThunderTypeaheadDialog( context: context, title: title, inputLabel: AppLocalizations.of(context)!.instance(1), @@ -318,20 +319,39 @@ void showInstanceInputDialog( } } -Future>> getInstanceSuggestions(String query, List>? emptySuggestions) async { +Future _loadLinkedInstances(Account? account, List out) async { + if (account == null) return; + + try { + final response = await InstanceRepositoryImpl(account: account).federated(); + final List parsed = List.from( + (response['federated_instances']['linked'] as List).map( + (instance) => ThunderInstanceInfo(id: instance['id'], domain: instance['domain'], name: instance['domain']), + ), + ); + + out + ..clear() + ..addAll(parsed); + } catch (_) { + // Dialog still works with empty list; user can type a domain and submit. + } +} + +Future> getInstanceSuggestions(String query, List? emptySuggestions) async { if (query.isEmpty) { return []; } - List> filteredInstances = emptySuggestions?.where((Map instance) => instance['domain'].contains(query)).toList() ?? []; + List filteredInstances = emptySuggestions?.where((ThunderInstanceInfo instance) => instance.domain.contains(query)).toList() ?? [] as List; return filteredInstances; } -Widget buildInstanceSuggestionWidget(Map payload, {void Function(Map)? onSelected, BuildContext? context}) { +Widget buildInstanceSuggestionWidget(ThunderInstanceInfo payload, {void Function(ThunderInstanceInfo)? onSelected, BuildContext? context}) { final theme = Theme.of(context!); return Tooltip( - message: '${payload['domain']}', + message: payload.domain, preferBelow: false, child: InkWell( onTap: onSelected == null ? null : () => onSelected(payload), @@ -340,7 +360,7 @@ Widget buildInstanceSuggestionWidget(Map payload, {void Functio backgroundColor: theme.colorScheme.secondaryContainer, maxRadius: 16.0, child: Text( - payload['domain'][0].toUpperCase(), + payload.domain[0].toUpperCase(), semanticsLabel: '', style: const TextStyle( fontWeight: FontWeight.bold, @@ -349,7 +369,7 @@ Widget buildInstanceSuggestionWidget(Map payload, {void Functio ), ), title: Text( - payload['domain'], + payload.domain, maxLines: 1, overflow: TextOverflow.ellipsis, ),