Flutter Android login vault: local DB (id+base64 content), email/Google auth, dashboard search/edit/swipe-delete, dark/system theme, minSdk 29

This commit is contained in:
cania
2026-08-12 11:41:20 +02:00
commit a8791a5b10
138 changed files with 6285 additions and 0 deletions

97
lib/database_helper.dart Normal file
View File

@@ -0,0 +1,97 @@
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<String, dynamic> row) => VaultEntry(
id: row['id'] as String,
content: Encryptor.decrypt(row['content'] as String),
);
/// Build a DB row map (content encrypted).
Map<String, dynamic> toDbRow() => {
'id': id,
'content': Encryptor.encrypt(content),
};
}
class DatabaseHelper {
static final DatabaseHelper _instance = DatabaseHelper._internal();
factory DatabaseHelper() => _instance;
DatabaseHelper._internal();
Database? _db;
Future<Database> get db async {
_db ??= await _initDb();
return _db!;
}
Future<Database> _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<void> insert(VaultEntry entry) async {
final d = await db;
await d.insert('vault', entry.toDbRow(),
conflictAlgorithm: ConflictAlgorithm.fail);
}
/// Update content for an existing [id].
Future<void> 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<void> 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<List<VaultEntry>> 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<List<VaultEntry>> 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();
}
}