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.
This commit is contained in:
@@ -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<dynamic, dynamic>? get userAgent => _userAgent;
|
||||
|
||||
List<CountryName>? _registrationCountries;
|
||||
|
||||
List<CountryName> get registrationCountries =>
|
||||
_registrationCountries ?? allCountries;
|
||||
|
||||
Stream<SessionState> 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<CountryName>? _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 = <String>[];
|
||||
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('Лимит попыток реконнекта');
|
||||
|
||||
@@ -33,6 +33,15 @@ final Map<String, CountryName> countriesByCode = {
|
||||
for (final country in allCountries) country.code: country,
|
||||
};
|
||||
|
||||
List<CountryName> countriesInServerOrder(Iterable<String> codes) {
|
||||
final out = <CountryName>[];
|
||||
for (final raw in codes) {
|
||||
final c = countriesByCode[raw.toUpperCase()];
|
||||
if (c != null) out.add(c);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Пример использования:
|
||||
/// ```dart
|
||||
/// final country = exampleCountryLookup('RU');
|
||||
|
||||
@@ -33,9 +33,19 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
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<LoginScreen> {
|
||||
final result = await Navigator.push<CountryName>(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
SelectCountryScreen(selectedCountry: _selectedCountry),
|
||||
builder: (context) => SelectCountryScreen(
|
||||
selectedCountry: _selectedCountry,
|
||||
countries: api.registrationCountries,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (result != null) {
|
||||
|
||||
@@ -6,8 +6,13 @@ import 'package:komet/l10n/app_localizations.dart';
|
||||
|
||||
class SelectCountryScreen extends StatefulWidget {
|
||||
final CountryName selectedCountry;
|
||||
final List<CountryName> countries;
|
||||
|
||||
const SelectCountryScreen({super.key, required this.selectedCountry});
|
||||
SelectCountryScreen({
|
||||
super.key,
|
||||
required this.selectedCountry,
|
||||
List<CountryName>? countries,
|
||||
}) : countries = countries ?? allCountries;
|
||||
|
||||
@override
|
||||
State<SelectCountryScreen> createState() => _SelectCountryScreenState();
|
||||
@@ -16,7 +21,13 @@ class SelectCountryScreen extends StatefulWidget {
|
||||
class _SelectCountryScreenState extends State<SelectCountryScreen> {
|
||||
bool _isSearching = false;
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
List<CountryName> _filteredCountries = allCountries;
|
||||
late List<CountryName> _filteredCountries;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_filteredCountries = widget.countries;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -27,10 +38,10 @@ class _SelectCountryScreenState extends State<SelectCountryScreen> {
|
||||
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<SelectCountryScreen> {
|
||||
_isSearching = !_isSearching;
|
||||
if (!_isSearching) {
|
||||
_searchController.clear();
|
||||
_filteredCountries = allCountries;
|
||||
_filteredCountries = widget.countries;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user