selectLiveTargets<T> function

LiveTargetSelection<T> selectLiveTargets<T>(
  1. List<T> apps, {
  2. required String deviceOf(
    1. T app
    ),
  3. String? device,
  4. bool all = false,
  5. String packageName = 'Nylo',
})

Picks the apps a live command runs on.

Precedence: all runs on every app; device matches a 1-based index from metro live:devices or a case-insensitive device name (an exact name wins over partial matches); otherwise the only running app is used. Metro never guesses: several apps and no target, or a name matching more than one app, is an error with exit code 2.

Implementation

LiveTargetSelection<T> selectLiveTargets<T>(
  List<T> apps, {
  required String Function(T app) deviceOf,
  String? device,
  bool all = false,
  String packageName = 'Nylo',
}) {
  if (apps.isEmpty) {
    return LiveTargetSelection<T>.error(
      'No running $packageName app found. Start it with `flutter run` '
      '(a debug build) and try again.',
      1,
    );
  }

  if (all) return LiveTargetSelection<T>.targets(apps);

  final String? wanted = device?.trim();
  if (wanted != null && wanted.isNotEmpty) {
    final int? index = int.tryParse(wanted);
    if (index != null) {
      if (index < 1 || index > apps.length) {
        return LiveTargetSelection<T>.error(
          'There is no app #$index. ${apps.length} '
          '${apps.length == 1 ? 'app is' : 'apps are'} running:',
          1,
          candidates: apps,
        );
      }
      return LiveTargetSelection<T>.targets([apps[index - 1]]);
    }

    final String needle = wanted.toLowerCase();
    final List<T> exact = apps
        .where((app) => deviceOf(app).toLowerCase() == needle)
        .toList();
    if (exact.length == 1) return LiveTargetSelection<T>.targets(exact);

    final List<T> matches = exact.isNotEmpty
        ? exact
        : apps
              .where((app) => deviceOf(app).toLowerCase().contains(needle))
              .toList();
    if (matches.isEmpty) {
      return LiveTargetSelection<T>.error(
        'No running app matches "$wanted". Running apps:',
        1,
        candidates: apps,
      );
    }
    if (matches.length > 1) {
      return LiveTargetSelection<T>.error(
        '"$wanted" matches ${matches.length} apps. Pass -d <#> or --all:',
        2,
        candidates: matches,
      );
    }
    return LiveTargetSelection<T>.targets(matches);
  }

  if (apps.length == 1) return LiveTargetSelection<T>.targets(apps);

  return LiveTargetSelection<T>.error(
    '${apps.length} apps are running. Pass -d <#|name> or --all:',
    2,
    candidates: apps,
  );
}