Adds SMS handler settings to Hive

Adds the necessary classes and configurations to store and retrieve SMS handler settings using Hive database.

This includes registering the `SmsHandlerSettings` model, its adapter, and related enum adapters with Hive, opening a new box for storing settings and making it accessible via `HiveService`. Additionally, this change registers a new repository for accessing sms handler settings data.
This commit is contained in:
2025-07-09 22:30:26 +03:00
parent d19f58d65e
commit 8040839ba3
7 changed files with 287 additions and 0 deletions
+5
View File
@@ -1,6 +1,7 @@
import 'package:budget_app/hive/hive_registrar.g.dart';
import 'package:budget_app/models/app_settings.dart'; // Добавлен импорт AppSettings
import 'package:budget_app/models/global_settings.dart';
import 'package:budget_app/models/sms_handler_settings.dart';
import 'package:hive_ce_flutter/hive_flutter.dart';
import 'package:logger/logger.dart';
@@ -21,6 +22,7 @@ class HiveService {
static const String _userBox = 'users';
static const String _smsMessageBox = 'smsMessages';
static const String _globalSettings = 'global_settings';
static const String _smsHandlerSettingsBox = 'sms_handler_settings';
static Future<void> init() async {
_logger.i('Initializing Hive database');
@@ -39,6 +41,7 @@ class HiveService {
Hive.openBox<User>(_userBox),
Hive.openBox<SmsMessage>(_smsMessageBox),
Hive.openBox<GlobalSettings>(_globalSettings),
Hive.openBox<SmsHandlerSettings>(_smsHandlerSettingsBox),
]);
// Проверка и заполнение начальными данными
@@ -56,6 +59,8 @@ class HiveService {
Hive.box<SmsMessage>(_smsMessageBox);
static Box<GlobalSettings> get globalSettings =>
Hive.box<GlobalSettings>(_globalSettings);
static Box<SmsHandlerSettings> get smsHandlerSettings =>
Hive.box<SmsHandlerSettings>(_smsHandlerSettingsBox);
/// Проверяет и заполняет боксы начальными данными при первом запуске
static void _checkAndFillInitialData() {
@@ -0,0 +1,57 @@
import 'package:hive_ce/hive.dart';
import '../../models/sms_handler_settings.dart';
import 'interfaces/isms_handler_repository.dart';
/// Реализация репозитория для настроек обработки СМС с использованием Hive.
class HiveSmsHandlerRepository implements ISmsHandlerRepository {
final Box<SmsHandlerSettings> _smsHandlerBox;
HiveSmsHandlerRepository(this._smsHandlerBox);
@override
Future<SmsHandlerSettings?> getSmsHandlerSettings(String userId) async {
// В Hive мы будем использовать ID пользователя как ключ для его настроек.
return _smsHandlerBox.get(userId);
}
@override
Future<void> saveSmsHandlerSettings(SmsHandlerSettings settings) async {
// Сохраняем объект настроек по ключу, равному ID пользователя.
await _smsHandlerBox.put(settings.userId, settings);
}
@override
Future<void> saveRuleForSender(String userId, String sender, SmsProcessingRule rule) async {
// 1. Получаем текущие настройки.
SmsHandlerSettings? settings = await getSmsHandlerSettings(userId);
if (settings == null) {
// 2. Если настроек нет, создаем новый объект.
settings = SmsHandlerSettings(
userId: userId,
rulesBySender: {sender: rule}, // Создаем карту с первым правилом
);
} else {
// 3. Если настройки есть, обновляем или добавляем правило.
settings.rulesBySender[sender] = rule;
}
// 4. Сохраняем обновленный объект настроек.
await saveSmsHandlerSettings(settings);
}
@override
Future<void> deleteRuleForSender(String userId, String sender) async {
// 1. Получаем текущие настройки.
final settings = await getSmsHandlerSettings(userId);
if (settings != null) {
// 2. Если настройки существуют, удаляем правило для отправителя.
settings.rulesBySender.remove(sender);
// 3. Сохраняем измененный объект.
await saveSmsHandlerSettings(settings);
}
// Если настроек нет, ничего не делаем.
}
}
@@ -0,0 +1,30 @@
import '../../../models/sms_handler_settings.dart';
/// Абстрактный класс (интерфейс) для репозитория настроек обработки СМС.
/// Определяет контракт, по которому UI и бизнес-логика будут взаимодействовать
/// с данными о настройках, не зная деталей их реализации (Hive, Firebase, etc).
abstract class ISmsHandlerRepository {
/// Получает настройки обработки СМС для указанного пользователя.
///
/// [userId] - Уникальный идентификатор пользователя.
/// Возвращает [SmsHandlerSettings] или null, если настроек нет.
Future<SmsHandlerSettings?> getSmsHandlerSettings(String userId);
/// Сохраняет или обновляет настройки обработки СМС для пользователя.
///
/// [settings] - Объект с настройками, который нужно сохранить.
Future<void> saveSmsHandlerSettings(SmsHandlerSettings settings);
/// Добавляет или обновляет правило для конкретного отправителя.
///
/// [userId] - ID пользователя.
/// [sender] - Идентификатор отправителя (например, 'SBERBANK').
/// [rule] - Правило обработки.
Future<void> saveRuleForSender(String userId, String sender, SmsProcessingRule rule);
/// Удаляет правило для конкретного отправителя.
///
/// [userId] - ID пользователя.
/// [sender] - Идентификатор отправителя, чье правило нужно удалить.
Future<void> deleteRuleForSender(String userId, String sender);
}
+7
View File
@@ -7,6 +7,7 @@ import 'package:budget_app/hive/hive_adapters.dart';
import 'package:budget_app/models/app_settings.dart';
import 'package:budget_app/models/category.dart';
import 'package:budget_app/models/global_settings.dart';
import 'package:budget_app/models/sms_handler_settings.dart';
import 'package:budget_app/models/sms_message.dart';
import 'package:budget_app/models/tag.dart';
import 'package:budget_app/models/transaction_record.dart';
@@ -19,7 +20,10 @@ extension HiveRegistrar on HiveInterface {
registerAdapter(ColorAdapter());
registerAdapter(GlobalSettingsAdapter());
registerAdapter(IconDataAdapter());
registerAdapter(SmsHandlerSettingsAdapter());
registerAdapter(SmsMessageAdapter());
registerAdapter(SmsProcessingRuleAdapter());
registerAdapter(SmsProcessingTypeAdapter());
registerAdapter(TagAdapter());
registerAdapter(TransactionRecordAdapter());
registerAdapter(UserAdapter());
@@ -33,7 +37,10 @@ extension IsolatedHiveRegistrar on IsolatedHiveInterface {
registerAdapter(ColorAdapter());
registerAdapter(GlobalSettingsAdapter());
registerAdapter(IconDataAdapter());
registerAdapter(SmsHandlerSettingsAdapter());
registerAdapter(SmsMessageAdapter());
registerAdapter(SmsProcessingRuleAdapter());
registerAdapter(SmsProcessingTypeAdapter());
registerAdapter(TagAdapter());
registerAdapter(TransactionRecordAdapter());
registerAdapter(UserAdapter());
+6
View File
@@ -1,4 +1,6 @@
import 'package:budget_app/data/repositories/hive_sms_handler_repository.dart';
import 'package:budget_app/data/repositories/hive_sms_message_repository.dart';
import 'package:budget_app/data/repositories/interfaces/isms_handler_repository.dart';
import 'package:budget_app/data/repositories/interfaces/isms_message_repository.dart';
import 'package:get_it/get_it.dart';
@@ -54,6 +56,10 @@ Future<void> initDependencies() async {
HiveGlobalSettingsRepository(HiveService.globalSettings),
);
getIt.registerSingleton<ISmsHandlerRepository>(
HiveSmsHandlerRepository(HiveService.smsHandlerSettings),
);
// Services
getIt.registerSingleton<SmsService>(SmsService());
+61
View File
@@ -0,0 +1,61 @@
import 'package:hive_ce/hive.dart';
part 'sms_handler_settings.g.dart';
/// Перечисление для определения типа обработки СМС.
@HiveType(typeId: 10)
enum SmsProcessingType {
/// Обработка с использованием регулярного выражения.
@HiveField(0)
regexp,
/// Обработка с использованием кастомной функции.
@HiveField(1)
customFunction,
}
/// Модель для хранения правила обработки СМС от конкретного отправителя.
@HiveType(typeId: 11)
class SmsProcessingRule extends HiveObject {
/// Тип обработки (regexp или кастомная функция).
@HiveField(0)
final SmsProcessingType type;
/// Шаблон регулярного выражения (используется, если type == SmsProcessingType.regexp).
@HiveField(1)
final String? pattern;
/// Идентификатор кастомной функции (используется, если type == SmsProcessingType.customFunction).
/// В коде этот ID будет сопоставляться с реальной функцией.
@HiveField(2)
final String? customFunctionId;
SmsProcessingRule({
required this.type,
this.pattern,
this.customFunctionId,
}) : assert(
(type == SmsProcessingType.regexp && pattern != null) ||
(type == SmsProcessingType.customFunction && customFunctionId != null),
'Pattern must be provided for regexp type, and customFunctionId for customFunction type.',
);
}
/// Модель для хранения всех настроек обработки СМС для одного пользователя.
@HiveType(typeId: 12)
class SmsHandlerSettings extends HiveObject {
/// Уникальный идентификатор пользователя, к которому относятся эти настройки.
@HiveField(0)
final String userId;
/// Карта правил обработки, где ключ - это идентификатор отправителя (например, 'SBERBANK' или номер телефона),
/// а значение - правило обработки для этого отправителя.
@HiveField(1)
final Map<String, SmsProcessingRule> rulesBySender;
SmsHandlerSettings({
required this.userId,
required this.rulesBySender,
});
}
+121
View File
@@ -0,0 +1,121 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'sms_handler_settings.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class SmsProcessingRuleAdapter extends TypeAdapter<SmsProcessingRule> {
@override
final typeId = 11;
@override
SmsProcessingRule read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return SmsProcessingRule(
type: fields[0] as SmsProcessingType,
pattern: fields[1] as String?,
customFunctionId: fields[2] as String?,
);
}
@override
void write(BinaryWriter writer, SmsProcessingRule obj) {
writer
..writeByte(3)
..writeByte(0)
..write(obj.type)
..writeByte(1)
..write(obj.pattern)
..writeByte(2)
..write(obj.customFunctionId);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is SmsProcessingRuleAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
class SmsHandlerSettingsAdapter extends TypeAdapter<SmsHandlerSettings> {
@override
final typeId = 12;
@override
SmsHandlerSettings read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return SmsHandlerSettings(
userId: fields[0] as String,
rulesBySender: (fields[1] as Map).cast<String, SmsProcessingRule>(),
);
}
@override
void write(BinaryWriter writer, SmsHandlerSettings obj) {
writer
..writeByte(2)
..writeByte(0)
..write(obj.userId)
..writeByte(1)
..write(obj.rulesBySender);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is SmsHandlerSettingsAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
class SmsProcessingTypeAdapter extends TypeAdapter<SmsProcessingType> {
@override
final typeId = 10;
@override
SmsProcessingType read(BinaryReader reader) {
switch (reader.readByte()) {
case 0:
return SmsProcessingType.regexp;
case 1:
return SmsProcessingType.customFunction;
default:
return SmsProcessingType.regexp;
}
}
@override
void write(BinaryWriter writer, SmsProcessingType obj) {
switch (obj) {
case SmsProcessingType.regexp:
writer.writeByte(0);
case SmsProcessingType.customFunction:
writer.writeByte(1);
}
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is SmsProcessingTypeAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}