fix: скрытие удаленных аккаунтов с контактов, возможно фикс скрытия медиа дорожки в кружках на кастомных android прошивках версии android ниже 16
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_contacts/flutter_contacts.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../config/app_phonebook_names.dart';
|
||||
import '../utils/logger.dart';
|
||||
|
||||
class DeviceContactsService {
|
||||
DeviceContactsService._();
|
||||
|
||||
static const _grantedKey = 'phonebook_granted';
|
||||
static const _deniedKey = 'phonebook_denied';
|
||||
|
||||
static final Map<String, String> _byLast10 = {};
|
||||
@@ -16,6 +17,10 @@ class DeviceContactsService {
|
||||
|
||||
static bool get _supported => Platform.isAndroid || Platform.isIOS;
|
||||
|
||||
static bool get isLoaded => _loaded;
|
||||
|
||||
static int get knownNumbers => _byLast10.length;
|
||||
|
||||
static String? _last10(String raw) {
|
||||
final digits = raw.replaceAll(RegExp(r'[^\d]'), '');
|
||||
if (digits.length < 10) return null;
|
||||
@@ -32,28 +37,43 @@ class DeviceContactsService {
|
||||
return name.trim();
|
||||
}
|
||||
|
||||
static Future<bool> hasPermission() async {
|
||||
if (!_supported) return false;
|
||||
try {
|
||||
return await Permission.contacts.isGranted;
|
||||
} catch (e) {
|
||||
logger.w('Телефонная книга: не удалось прочитать статус разрешения: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> loadFromStartup() async {
|
||||
if (_loaded || !_supported) return;
|
||||
if (!AppPhonebookNames.current.value) return;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool(_grantedKey) != true) return;
|
||||
final granted = await FlutterContacts.requestPermission(readonly: true);
|
||||
if (!granted) return;
|
||||
if (!await hasPermission()) return;
|
||||
await _forgetDenial();
|
||||
await _readBook();
|
||||
}
|
||||
|
||||
static Future<bool> ensureLoadedInteractive({bool force = false}) async {
|
||||
if (_loaded || !_supported) return false;
|
||||
if (!_supported) return false;
|
||||
if (!AppPhonebookNames.current.value) return false;
|
||||
if (_loaded && !force) return false;
|
||||
|
||||
if (await hasPermission()) {
|
||||
await _forgetDenial();
|
||||
return _readBook();
|
||||
}
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (!force && prefs.getBool(_deniedKey) == true) return false;
|
||||
|
||||
final granted = await FlutterContacts.requestPermission(readonly: true);
|
||||
if (!granted) {
|
||||
await prefs.setBool(_deniedKey, true);
|
||||
return false;
|
||||
}
|
||||
await prefs.remove(_deniedKey);
|
||||
await prefs.setBool(_grantedKey, true);
|
||||
return _readBook();
|
||||
}
|
||||
|
||||
@@ -63,8 +83,14 @@ class DeviceContactsService {
|
||||
return ensureLoadedInteractive(force: true);
|
||||
}
|
||||
|
||||
static Future<void> _forgetDenial() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool(_deniedKey) == true) await prefs.remove(_deniedKey);
|
||||
}
|
||||
|
||||
static Future<bool> _readBook() async {
|
||||
try {
|
||||
FlutterContacts.config.includeNonVisibleOnAndroid = true;
|
||||
final contacts = await FlutterContacts.getContacts(withProperties: true);
|
||||
_byLast10.clear();
|
||||
for (final contact in contacts) {
|
||||
@@ -78,8 +104,13 @@ class DeviceContactsService {
|
||||
}
|
||||
}
|
||||
_loaded = true;
|
||||
return _byLast10.isNotEmpty;
|
||||
} catch (_) {
|
||||
logger.i(
|
||||
'Телефонная книга: прочитано ${contacts.length} записей, '
|
||||
'${_byLast10.length} номеров',
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
logger.w('Телефонная книга: не удалось прочитать: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import 'dart:ui';
|
||||
|
||||
Size videoNoteFrameSize(Size frame, double fallback) {
|
||||
final width = frame.width.isFinite && frame.width > 0
|
||||
? frame.width
|
||||
: fallback;
|
||||
final height = frame.height.isFinite && frame.height > 0
|
||||
? frame.height
|
||||
: fallback;
|
||||
return Size(width, height);
|
||||
}
|
||||
@@ -221,7 +221,7 @@ class AppDatabase {
|
||||
await _migrateLegacyDb(target);
|
||||
return openDatabase(
|
||||
target,
|
||||
version: 22,
|
||||
version: 23,
|
||||
onOpen: (db) => db.execute('PRAGMA foreign_keys = ON'),
|
||||
onCreate: (db, _) => _createTables(db),
|
||||
onUpgrade: (db, oldVersion, newVersion) async {
|
||||
@@ -353,6 +353,14 @@ class AppDatabase {
|
||||
await db.execute(_webAppStorageSchema);
|
||||
await db.execute(_webAppBiometrySchema);
|
||||
}
|
||||
if (oldVersion < 23) {
|
||||
await _addColumnIfMissing(
|
||||
db,
|
||||
'contacts',
|
||||
'account_status',
|
||||
'INTEGER NOT NULL DEFAULT 0',
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -465,7 +473,8 @@ class AppDatabase {
|
||||
base_url TEXT,
|
||||
base_raw_url TEXT,
|
||||
update_time INTEGER NOT NULL DEFAULT 0,
|
||||
options TEXT
|
||||
options TEXT,
|
||||
account_status INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
''';
|
||||
|
||||
@@ -798,6 +807,7 @@ class AppDatabase {
|
||||
static Future<void> close() async {
|
||||
await _db?.close();
|
||||
_db = null;
|
||||
_initCompleter = null;
|
||||
}
|
||||
|
||||
// Chats cache
|
||||
@@ -1045,11 +1055,16 @@ class AppDatabase {
|
||||
await batch.commit(noResult: true);
|
||||
}
|
||||
|
||||
static Future<List<Map<String, dynamic>>> loadContacts(int accountId) async {
|
||||
static Future<List<Map<String, dynamic>>> loadContacts(
|
||||
int accountId, {
|
||||
bool includeDeleted = false,
|
||||
}) async {
|
||||
final db = await _instance;
|
||||
return db.query(
|
||||
'contacts',
|
||||
where: 'account_id = ?',
|
||||
where: includeDeleted
|
||||
? 'account_id = ?'
|
||||
: 'account_id = ? AND account_status = 0',
|
||||
whereArgs: [accountId],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user