import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:umbrix/singbox/model/singbox_proxy_type.dart'; part 'proxy_entity.freezed.dart'; @freezed class ProxyGroupEntity with _$ProxyGroupEntity { const ProxyGroupEntity._(); const factory ProxyGroupEntity({ required String tag, required ProxyType type, required String selected, @Default([]) List items, }) = _ProxyGroupEntity; String get name => _sanitizedTag(tag); } @freezed class ProxyItemEntity with _$ProxyItemEntity { const ProxyItemEntity._(); const factory ProxyItemEntity({ required String tag, required ProxyType type, required int urlTestDelay, String? selectedTag, }) = _ProxyItemEntity; String get name => _sanitizedTag(tag); String? get selectedName => selectedTag == null ? null : _sanitizedTag(selectedTag!); bool get isVisible => !tag.contains("§hide§"); /// Извлекает код страны из названия прокси (emoji флаг или текст) String get countryCode { // Парсинг emoji флагов (🇩🇪 = U+1F1E6-1F1FF региональные индикаторы) final runes = name.runes.toList(); if (runes.length >= 2) { final first = runes[0]; final second = runes[1]; // Проверка Regional Indicator Symbols if (first >= 0x1F1E6 && first <= 0x1F1FF && second >= 0x1F1E6 && second <= 0x1F1FF) { final cc1 = String.fromCharCode(first - 0x1F1E6 + 65); // A-Z final cc2 = String.fromCharCode(second - 0x1F1E6 + 65); return cc1 + cc2; } } // Fallback: текстовые коды в начале или конце названия final match = RegExp(r'^([A-Z]{2})[-_\s]|[-_\s]([A-Z]{2})$|^\[([A-Z]{2})\]').firstMatch(name); if (match != null) { return match.group(1) ?? match.group(2) ?? match.group(3) ?? 'XX'; } return 'XX'; // Неизвестная страна } } String _sanitizedTag(String tag) => tag.replaceFirst(RegExp(r"\§[^]*"), "").trimRight();