Updates to add more ads and fix ad types.

This commit is contained in:
Courtney Arnold 2026-08-31 20:17:22 -05:00
parent ad850d2be6
commit ad2d932842
17 changed files with 552 additions and 59 deletions

View file

@ -65,7 +65,7 @@ class DatabaseService {
final dbPath = p.join(_rootDirectory.path, dbFileName);
_db = await openDatabase(
dbPath,
version: 5,
version: 6,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
@ -76,6 +76,7 @@ class DatabaseService {
await db.execute(createFuelEntriesTableSql);
await db.execute(createFuelEntriesIndexSql);
await db.execute(createAdFreeEntitlementTableSql);
await db.execute(createAppUsageTableSql);
}
/// Versions 2/3 (VIN as primary key, then dropping license plate) were
@ -94,6 +95,9 @@ class DatabaseService {
if (oldVersion < 5) {
await db.execute(createAdFreeEntitlementTableSql);
}
if (oldVersion < 6) {
await db.execute(createAppUsageTableSql);
}
}
Future<void> _migrateToVehicleIdSchema(Database db) async {
@ -188,6 +192,35 @@ class DatabaseService {
);
}
/// The earliest-known moment this app was ever used, across every device
/// this account has synced from — see [createAppUsageTableSql]. Recorded
/// once, the first time this is ever called with no existing row (a
/// fresh install with nothing to merge down yet); reinstalling *after*
/// cloud sync was connected instead pulls the original value back down
/// via [mergeAppUsageSql] before this is next called, so the new-user ad
/// grace period can't be replayed by reinstalling.
Future<DateTime> getOrCreateFirstUsedAt() async {
final rows = await _db.query('app_usage', where: 'id = 1', limit: 1);
if (rows.isNotEmpty) {
return DateTime.fromMillisecondsSinceEpoch(rows.single['first_used_at'] as int, isUtc: true);
}
final now = DateTime.now().toUtc();
await _db.insert('app_usage', {'id': 1, 'first_used_at': now.millisecondsSinceEpoch});
return now;
}
/// True if any vehicle or fuel entry row has local changes not yet
/// pushed to the cloud (see the `dirty` column note on this class).
/// Exposed only as this one yes/no signal, never the raw flag — it
/// drives [AppState.hasUnsyncedChanges], which the "not backed up" icon
/// reads.
Future<bool> hasDirtyRows() async {
final vehicleRows = await _db.query('vehicles', where: 'dirty = 1', limit: 1);
if (vehicleRows.isNotEmpty) return true;
final entryRows = await _db.query('fuel_entries', where: 'dirty = 1', limit: 1);
return entryRows.isNotEmpty;
}
/// True if an active (non-deleted) vehicle other than [excludeId] already
/// has this VIN. VIN must stay unique even though it's editable, so
/// callers adding a new vehicle (no [excludeId]) or changing an existing