import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; import 'package:login_vault_app/constants.dart'; import 'package:login_vault_app/encryptor.dart'; /// A single saved login/private entry. class VaultEntry { final String id; // unique string final String content; // decrypted plaintext VaultEntry({required this.id, required this.content}); /// Build from a DB row (content is stored encrypted). factory VaultEntry.fromDbRow(Map row) => VaultEntry( id: row['id'] as String, content: Encryptor.decrypt(row['content'] as String), ); /// Build a DB row map (content encrypted). Map toDbRow() => { 'id': id, 'content': Encryptor.encrypt(content), }; } class DatabaseHelper { static final DatabaseHelper _instance = DatabaseHelper._internal(); factory DatabaseHelper() => _instance; DatabaseHelper._internal(); Database? _db; Future get db async { _db ??= await _initDb(); return _db!; } Future _initDb() async { final path = join(await getDatabasesPath(), AppConstants.dbName); return openDatabase( path, version: 1, onCreate: (db, version) async { await db.execute(''' CREATE TABLE vault ( id TEXT PRIMARY KEY, content TEXT NOT NULL ) '''); }, ); } /// Insert a new entry (throws if [id] already exists -> uniqueness). Future insert(VaultEntry entry) async { final d = await db; await d.insert('vault', entry.toDbRow(), conflictAlgorithm: ConflictAlgorithm.fail); } /// Update content for an existing [id]. Future update(String id, String newContent) async { final d = await db; await d.update( 'vault', {'content': Encryptor.encrypt(newContent)}, where: 'id = ?', whereArgs: [id], ); } /// Delete by [id]. Future delete(String id) async { final d = await db; await d.delete('vault', where: 'id = ?', whereArgs: [id]); } /// Get all entries (used for full list / search). Future> getAll() async { final d = await db; final rows = await d.query('vault', orderBy: 'id COLLATE NOCASE ASC'); return rows.map(VaultEntry.fromDbRow).toList(); } /// Search ids containing [query] (case-insensitive). Returns matching entries. Future> search(String query) async { if (query.trim().isEmpty) return getAll(); final d = await db; final rows = await d.query( 'vault', where: 'id LIKE ?', whereArgs: ['%${query.trim()}%'], orderBy: 'id COLLATE NOCASE ASC', ); return rows.map(VaultEntry.fromDbRow).toList(); } }