import '../../api.dart'; import '../../../core/protocol/opcode_map.dart'; import '../../../core/protocol/packet.dart'; import '../../../core/storage/app_database.dart'; import '../../../core/storage/token_storage.dart'; import 'account_base.dart'; import 'account_models.dart'; // #***! приватность и уведомления class PrivacyModule extends AccountApiBase { PrivacyModule(super.api); static const String _defaultPushSound = 'oki.aiff'; // #***! приватность из базы, приходит в login и живёт локально Future getPrivacyConfig() async { final accountId = await TokenStorage.getActiveAccountId(); if (accountId != null) { final saved = await AppDatabase.getPrivacyConfig(accountId); if (saved != null) return PrivacyConfig.fromJson(saved); } return PrivacyConfig.empty(); } // #***! список заблокированных Future> getBlockedContacts() async { ensureOnline(); final packet = await api.sendRequest(Opcode.contactList, { 'status': 'BLOCKED', 'count': 100, 'from': 0, }); final data = requireMapPayload(packet, 'getBlockedContacts'); final contacts = data['contacts'] as List?; if (contacts == null) return []; return contacts .whereType() .map((c) => BlockedContact.fromMap(c.cast())) .toList(); } // #***! обновление одним config, ответ в базу Future updatePrivacyConfig( Map settings, ) async { ensureOnline(); final payload = { 'settings': {'user': settings}, }; final packet = await api.sendRequest(Opcode.config, payload); final data = requireMapPayload(packet, 'updatePrivacyConfig'); final user = data['user']; if (user is! Map) { throw Exception('updatePrivacyConfig: отсутствует user в payload'); } final config = PrivacyConfig.fromMap(user.cast()); final accountId = await TokenStorage.getActiveAccountId(); if (accountId != null) { await AppDatabase.savePrivacyConfig(accountId, config.toJson()); } return config; } // #***! безопасный режим это пачка настроек разом Future setSafeMode(bool value) => updatePrivacyConfig( value ? { 'INCOMING_CALL': 'CONTACTS', 'SEARCH_BY_PHONE': 'CONTACTS', 'SAFE_MODE_NO_PIN': true, 'CONTENT_LEVEL_ACCESS': true, 'CHATS_INVITE': 'CONTACTS', 'SAFE_MODE': true, } : {'SAFE_MODE_NO_PIN': false, 'SAFE_MODE': false}, ); // #***! дальше по методу на каждый переключатель Future setChatsPushNotification(bool value) => updatePrivacyConfig({'CHATS_PUSH_NOTIFICATION': value ? 'ON' : 'OFF'}); Future setMessagePreview(bool value) => updatePrivacyConfig({'PUSH_DETAILS': value}); Future setNotificationSound(bool value) => updatePrivacyConfig({ 'PUSH_SOUND': value ? _defaultPushSound : '', 'CHATS_PUSH_SOUND': value ? _defaultPushSound : '', }); Future setCallNotifications(bool value) => updatePrivacyConfig({'M_CALL_PUSH_NOTIFICATION': value ? 'ON' : 'OFF'}); Future setNewContacts(bool value) => updatePrivacyConfig({'PUSH_NEW_CONTACTS': value}); // #***! регистрация push токена, ловим протухший FCM Future registerPushToken(String pushToken) async { ensureOnline(); final packet = await api.sendRequest(Opcode.config, { 'pushToken': pushToken, 'pushOptions': 0, }); if (packet.isError) { final msg = messageFromErrorPayload(packet.payload).toUpperCase(); if (msg.contains('WRONG_DEVICE_TOKEN') || msg.contains('WRONG.DEVICE.TOKEN')) { throw const WrongDeviceTokenException(); } throw PacketError(messageFromErrorPayload(packet.payload)); } } Future unregisterPushToken(String _) async { if (api.state != SessionState.online) return; final packet = await api.sendRequest(Opcode.logout, {}); throwIfPacketError(packet); } }