From 7fefb71de62ca5189dd638dbdf4d5497d84623f1 Mon Sep 17 00:00:00 2001 From: klockky Date: Fri, 3 Apr 2026 21:38:59 +0300 Subject: [PATCH] Implemented country registration handling in the API, allowing for dynamic country selection in the login and country selection screens. Added parsing logic for registration countries and updated the UI to reflect allowed countries based on the API response. --- lib/backend/api.dart | 29 +++++++++++++++++++ lib/core/config/countries.dart | 9 ++++++ lib/frontend/screens/auth/login_screen.dart | 16 ++++++++-- .../screens/auth/select_country_screen.dart | 21 ++++++++++---- 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/lib/backend/api.dart b/lib/backend/api.dart index 1eeb9dd..aedf00d 100644 --- a/lib/backend/api.dart +++ b/lib/backend/api.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:typed_data'; import '../core/config/config.dart'; +import '../core/config/countries.dart'; import '../core/protocol/opcode_map.dart'; import '../core/protocol/packet.dart'; import '../core/transport/connection.dart'; @@ -33,6 +34,11 @@ class Api { Map? get userAgent => _userAgent; + List? _registrationCountries; + + List get registrationCountries => + _registrationCountries ?? allCountries; + Stream get stateStream => _stateController.stream; SessionState get state => _sessionState; @@ -76,6 +82,7 @@ class Api { try { final response = await sendHandshake(); if (response.isOk) { + _registrationCountries = _parseRegistrationCountries(response.payload); _setSessionState(SessionState.online); _startPinging(); logger.i('Сессия онлайн, хэндшейк ок'); @@ -230,6 +237,28 @@ class Api { }); } + static List? _parseRegistrationCountries(dynamic payload) { + if (payload is! Map) return null; + final raw = payload['reg-country-code']; + if (raw is! List || raw.isEmpty) return null; + final codes = []; + for (final e in raw) { + if (e is String && e.isNotEmpty) codes.add(e.toUpperCase()); + } + if (codes.isEmpty) return null; + var list = countriesInServerOrder(codes); + if (list.isEmpty) return null; + + final loc = payload['location']; + if (loc is String && loc.length == 2) { + final home = countriesByCode[loc.toUpperCase()]; + if (home != null && !list.any((c) => c.code == home.code)) { + list = [home, ...list]; + } + } + return list; + } + void _scheduleReconnect() { if (_reconnectAttempts >= ServerConfig.maxReconnectAttempts) { logger.e('Лимит попыток реконнекта'); diff --git a/lib/core/config/countries.dart b/lib/core/config/countries.dart index d19d055..e87262e 100644 --- a/lib/core/config/countries.dart +++ b/lib/core/config/countries.dart @@ -33,6 +33,15 @@ final Map countriesByCode = { for (final country in allCountries) country.code: country, }; +List countriesInServerOrder(Iterable codes) { + final out = []; + for (final raw in codes) { + final c = countriesByCode[raw.toUpperCase()]; + if (c != null) out.add(c); + } + return out; +} + /// Пример использования: /// ```dart /// final country = exampleCountryLookup('RU'); diff --git a/lib/frontend/screens/auth/login_screen.dart b/lib/frontend/screens/auth/login_screen.dart index 6da104c..579f250 100644 --- a/lib/frontend/screens/auth/login_screen.dart +++ b/lib/frontend/screens/auth/login_screen.dart @@ -33,9 +33,19 @@ class _LoginScreenState extends State { void initState() { super.initState(); _selectedCountry = countriesByCode['RU'] ?? allCountries.first; + _clampCountryToAllowed(); _checkTOS(); } + void _clampCountryToAllowed() { + final allowed = api.registrationCountries; + if (allowed.any((c) => c.code == _selectedCountry.code)) return; + _selectedCountry = allowed.firstWhere( + (c) => c.code == 'RU', + orElse: () => allowed.first, + ); + } + @override void dispose() { _phoneErrorTimer?.cancel(); @@ -66,8 +76,10 @@ class _LoginScreenState extends State { final result = await Navigator.push( context, MaterialPageRoute( - builder: (context) => - SelectCountryScreen(selectedCountry: _selectedCountry), + builder: (context) => SelectCountryScreen( + selectedCountry: _selectedCountry, + countries: api.registrationCountries, + ), ), ); if (result != null) { diff --git a/lib/frontend/screens/auth/select_country_screen.dart b/lib/frontend/screens/auth/select_country_screen.dart index 3c5f5de..bf4bd03 100644 --- a/lib/frontend/screens/auth/select_country_screen.dart +++ b/lib/frontend/screens/auth/select_country_screen.dart @@ -6,8 +6,13 @@ import 'package:komet/l10n/app_localizations.dart'; class SelectCountryScreen extends StatefulWidget { final CountryName selectedCountry; + final List countries; - const SelectCountryScreen({super.key, required this.selectedCountry}); + SelectCountryScreen({ + super.key, + required this.selectedCountry, + List? countries, + }) : countries = countries ?? allCountries; @override State createState() => _SelectCountryScreenState(); @@ -16,7 +21,13 @@ class SelectCountryScreen extends StatefulWidget { class _SelectCountryScreenState extends State { bool _isSearching = false; final TextEditingController _searchController = TextEditingController(); - List _filteredCountries = allCountries; + late List _filteredCountries; + + @override + void initState() { + super.initState(); + _filteredCountries = widget.countries; + } @override void dispose() { @@ -27,10 +38,10 @@ class _SelectCountryScreenState extends State { void _filterCountries(String query) { setState(() { if (query.isEmpty) { - _filteredCountries = allCountries; + _filteredCountries = widget.countries; } else { final q = query.toLowerCase(); - _filteredCountries = allCountries.where((c) { + _filteredCountries = widget.countries.where((c) { return c.ru.toLowerCase().contains(q) || c.en.toLowerCase().contains(q) || c.phoneCode.contains(q); @@ -90,7 +101,7 @@ class _SelectCountryScreenState extends State { _isSearching = !_isSearching; if (!_isSearching) { _searchController.clear(); - _filteredCountries = allCountries; + _filteredCountries = widget.countries; } }); },