mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-24 10:28:50 +01:00
Add new file property to store geocoded address
This commit is contained in:
parent
093bc6e327
commit
189f536f29
15 changed files with 644 additions and 5 deletions
|
@ -21,6 +21,81 @@ int compareFileDateTimeDescending(File x, File y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ImageLocation with EquatableMixin {
|
||||||
|
const ImageLocation({
|
||||||
|
this.version = appVersion,
|
||||||
|
required this.name,
|
||||||
|
required this.latitude,
|
||||||
|
required this.longitude,
|
||||||
|
required this.countryCode,
|
||||||
|
this.admin1,
|
||||||
|
this.admin2,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ImageLocation.empty() => const ImageLocation(
|
||||||
|
name: null, latitude: null, longitude: null, countryCode: null);
|
||||||
|
|
||||||
|
static ImageLocation fromJson(JsonObj json) {
|
||||||
|
return ImageLocation(
|
||||||
|
version: json["v"],
|
||||||
|
name: json["name"],
|
||||||
|
latitude: json["lat"] == null ? null : json["lat"] / 10000,
|
||||||
|
longitude: json["lng"] == null ? null : json["lng"] / 10000,
|
||||||
|
countryCode: json["cc"],
|
||||||
|
admin1: json["admin1"],
|
||||||
|
admin2: json["admin2"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObj toJson() => {
|
||||||
|
"v": version,
|
||||||
|
if (name != null) "name": name,
|
||||||
|
if (latitude != null) "lat": (latitude! * 10000).round(),
|
||||||
|
if (longitude != null) "lng": (longitude! * 10000).round(),
|
||||||
|
if (countryCode != null) "cc": countryCode,
|
||||||
|
if (admin1 != null) "admin1": admin1,
|
||||||
|
if (admin2 != null) "admin2": admin2,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isEmpty() => name == null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
toString() {
|
||||||
|
var product = "$runtimeType {"
|
||||||
|
"version: $version, ";
|
||||||
|
if (name != null) {
|
||||||
|
product += "name: $name, "
|
||||||
|
"latitude: $latitude, "
|
||||||
|
"longitude: $longitude, "
|
||||||
|
"countryCode: $countryCode, "
|
||||||
|
"admin1: $admin1, "
|
||||||
|
"admin2: $admin2, ";
|
||||||
|
}
|
||||||
|
return product + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
get props => [
|
||||||
|
version,
|
||||||
|
name,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
countryCode,
|
||||||
|
admin1,
|
||||||
|
admin2,
|
||||||
|
];
|
||||||
|
|
||||||
|
final int version;
|
||||||
|
final String? name;
|
||||||
|
final double? latitude;
|
||||||
|
final double? longitude;
|
||||||
|
final String? countryCode;
|
||||||
|
final String? admin1;
|
||||||
|
final String? admin2;
|
||||||
|
|
||||||
|
static const appVersion = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// Immutable object that hold metadata of a [File]
|
/// Immutable object that hold metadata of a [File]
|
||||||
class Metadata with EquatableMixin {
|
class Metadata with EquatableMixin {
|
||||||
Metadata({
|
Metadata({
|
||||||
|
@ -238,6 +313,7 @@ class File with EquatableMixin {
|
||||||
this.trashbinFilename,
|
this.trashbinFilename,
|
||||||
this.trashbinOriginalLocation,
|
this.trashbinOriginalLocation,
|
||||||
this.trashbinDeletionTime,
|
this.trashbinDeletionTime,
|
||||||
|
this.location,
|
||||||
}) : path = path.trimAny("/");
|
}) : path = path.trimAny("/");
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -292,6 +368,9 @@ class File with EquatableMixin {
|
||||||
overrideDateTime: json["overrideDateTime"] == null
|
overrideDateTime: json["overrideDateTime"] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json["overrideDateTime"]),
|
: DateTime.parse(json["overrideDateTime"]),
|
||||||
|
location: json["location"] == null
|
||||||
|
? null
|
||||||
|
: ImageLocation.fromJson(json["location"]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,6 +429,9 @@ class File with EquatableMixin {
|
||||||
if (overrideDateTime != null) {
|
if (overrideDateTime != null) {
|
||||||
product += "overrideDateTime: $overrideDateTime, ";
|
product += "overrideDateTime: $overrideDateTime, ";
|
||||||
}
|
}
|
||||||
|
if (location != null) {
|
||||||
|
product += "location: $location, ";
|
||||||
|
}
|
||||||
return product + "}";
|
return product + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +459,7 @@ class File with EquatableMixin {
|
||||||
if (isArchived != null) "isArchived": isArchived,
|
if (isArchived != null) "isArchived": isArchived,
|
||||||
if (overrideDateTime != null)
|
if (overrideDateTime != null)
|
||||||
"overrideDateTime": overrideDateTime!.toUtc().toIso8601String(),
|
"overrideDateTime": overrideDateTime!.toUtc().toIso8601String(),
|
||||||
|
if (location != null) "location": location!.toJson(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,6 +482,7 @@ class File with EquatableMixin {
|
||||||
OrNull<Metadata>? metadata,
|
OrNull<Metadata>? metadata,
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) {
|
}) {
|
||||||
return File(
|
return File(
|
||||||
path: path ?? this.path,
|
path: path ?? this.path,
|
||||||
|
@ -422,6 +506,7 @@ class File with EquatableMixin {
|
||||||
overrideDateTime: overrideDateTime == null
|
overrideDateTime: overrideDateTime == null
|
||||||
? this.overrideDateTime
|
? this.overrideDateTime
|
||||||
: overrideDateTime.obj,
|
: overrideDateTime.obj,
|
||||||
|
location: location == null ? this.location : location.obj,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,6 +530,7 @@ class File with EquatableMixin {
|
||||||
// metadata is handled separately, see [equals]
|
// metadata is handled separately, see [equals]
|
||||||
isArchived,
|
isArchived,
|
||||||
overrideDateTime,
|
overrideDateTime,
|
||||||
|
location,
|
||||||
];
|
];
|
||||||
|
|
||||||
final String path;
|
final String path;
|
||||||
|
@ -466,6 +552,7 @@ class File with EquatableMixin {
|
||||||
final Metadata? metadata;
|
final Metadata? metadata;
|
||||||
final bool? isArchived;
|
final bool? isArchived;
|
||||||
final DateTime? overrideDateTime;
|
final DateTime? overrideDateTime;
|
||||||
|
final ImageLocation? location;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FileExtension on File {
|
extension FileExtension on File {
|
||||||
|
@ -581,6 +668,7 @@ class FileRepo {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) =>
|
}) =>
|
||||||
dataSrc.updateProperty(
|
dataSrc.updateProperty(
|
||||||
account,
|
account,
|
||||||
|
@ -589,6 +677,7 @@ class FileRepo {
|
||||||
isArchived: isArchived,
|
isArchived: isArchived,
|
||||||
overrideDateTime: overrideDateTime,
|
overrideDateTime: overrideDateTime,
|
||||||
favorite: favorite,
|
favorite: favorite,
|
||||||
|
location: location,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// See [FileDataSource.copy]
|
/// See [FileDataSource.copy]
|
||||||
|
@ -660,6 +749,7 @@ abstract class FileDataSource {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Copy [f] to [destination]
|
/// Copy [f] to [destination]
|
||||||
|
|
|
@ -58,6 +58,7 @@ class FileWebdavDataSource implements FileDataSource {
|
||||||
"app:metadata",
|
"app:metadata",
|
||||||
"app:is-archived",
|
"app:is-archived",
|
||||||
"app:override-date-time",
|
"app:override-date-time",
|
||||||
|
"app:location",
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -135,6 +136,7 @@ class FileWebdavDataSource implements FileDataSource {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) async {
|
}) async {
|
||||||
_log.info("[updateProperty] ${f.path}");
|
_log.info("[updateProperty] ${f.path}");
|
||||||
if (metadata?.obj != null && metadata!.obj!.fileEtag != f.etag) {
|
if (metadata?.obj != null && metadata!.obj!.fileEtag != f.etag) {
|
||||||
|
@ -149,11 +151,14 @@ class FileWebdavDataSource implements FileDataSource {
|
||||||
"app:override-date-time":
|
"app:override-date-time":
|
||||||
overrideDateTime!.obj!.toUtc().toIso8601String(),
|
overrideDateTime!.obj!.toUtc().toIso8601String(),
|
||||||
if (favorite != null) "oc:favorite": favorite ? 1 : 0,
|
if (favorite != null) "oc:favorite": favorite ? 1 : 0,
|
||||||
|
if (location?.obj != null)
|
||||||
|
"app:location": jsonEncode(location!.obj!.toJson()),
|
||||||
};
|
};
|
||||||
final removeProps = [
|
final removeProps = [
|
||||||
if (OrNull.isSetNull(metadata)) "app:metadata",
|
if (OrNull.isSetNull(metadata)) "app:metadata",
|
||||||
if (OrNull.isSetNull(isArchived)) "app:is-archived",
|
if (OrNull.isSetNull(isArchived)) "app:is-archived",
|
||||||
if (OrNull.isSetNull(overrideDateTime)) "app:override-date-time",
|
if (OrNull.isSetNull(overrideDateTime)) "app:override-date-time",
|
||||||
|
if (OrNull.isSetNull(location)) "app:location",
|
||||||
];
|
];
|
||||||
final response = await Api(account).files().proppatch(
|
final response = await Api(account).files().proppatch(
|
||||||
path: f.path,
|
path: f.path,
|
||||||
|
@ -417,6 +422,7 @@ class FileSqliteDbDataSource implements FileDataSource {
|
||||||
r.readTable(db.files),
|
r.readTable(db.files),
|
||||||
r.readTable(db.accountFiles),
|
r.readTable(db.accountFiles),
|
||||||
r.readTableOrNull(db.images),
|
r.readTableOrNull(db.images),
|
||||||
|
r.readTableOrNull(db.imageLocations),
|
||||||
r.readTableOrNull(db.trashes),
|
r.readTableOrNull(db.trashes),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
@ -450,6 +456,7 @@ class FileSqliteDbDataSource implements FileDataSource {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) async {
|
}) async {
|
||||||
_log.info("[updateProperty] ${f.path}");
|
_log.info("[updateProperty] ${f.path}");
|
||||||
await _c.sqliteDb.use((db) async {
|
await _c.sqliteDb.use((db) async {
|
||||||
|
@ -490,6 +497,26 @@ class FileSqliteDbDataSource implements FileDataSource {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (location != null) {
|
||||||
|
if (location.obj == null) {
|
||||||
|
await (db.delete(db.imageLocations)
|
||||||
|
..where((t) => t.accountFile.equals(rowIds.accountFileRowId)))
|
||||||
|
.go();
|
||||||
|
} else {
|
||||||
|
await db
|
||||||
|
.into(db.imageLocations)
|
||||||
|
.insertOnConflictUpdate(sql.ImageLocationsCompanion.insert(
|
||||||
|
accountFile: sql.Value(rowIds.accountFileRowId),
|
||||||
|
version: location.obj!.version,
|
||||||
|
name: sql.Value(location.obj!.name),
|
||||||
|
latitude: sql.Value(location.obj!.latitude),
|
||||||
|
longitude: sql.Value(location.obj!.longitude),
|
||||||
|
countryCode: sql.Value(location.obj!.countryCode),
|
||||||
|
admin1: sql.Value(location.obj!.admin1),
|
||||||
|
admin2: sql.Value(location.obj!.admin2),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,6 +654,7 @@ class FileCachedDataSource implements FileDataSource {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) async {
|
}) async {
|
||||||
await _remoteSrc.updateProperty(
|
await _remoteSrc.updateProperty(
|
||||||
account,
|
account,
|
||||||
|
@ -635,6 +663,7 @@ class FileCachedDataSource implements FileDataSource {
|
||||||
isArchived: isArchived,
|
isArchived: isArchived,
|
||||||
overrideDateTime: overrideDateTime,
|
overrideDateTime: overrideDateTime,
|
||||||
favorite: favorite,
|
favorite: favorite,
|
||||||
|
location: location,
|
||||||
);
|
);
|
||||||
await _sqliteDbSrc.updateProperty(
|
await _sqliteDbSrc.updateProperty(
|
||||||
account,
|
account,
|
||||||
|
@ -643,6 +672,7 @@ class FileCachedDataSource implements FileDataSource {
|
||||||
isArchived: isArchived,
|
isArchived: isArchived,
|
||||||
overrideDateTime: overrideDateTime,
|
overrideDateTime: overrideDateTime,
|
||||||
favorite: favorite,
|
favorite: favorite,
|
||||||
|
location: location,
|
||||||
);
|
);
|
||||||
|
|
||||||
// generate a new random token
|
// generate a new random token
|
||||||
|
|
|
@ -226,6 +226,14 @@ class FileSqliteCacheUpdater {
|
||||||
t.accountFile.equals(thisRowIds.accountFileRowId),
|
t.accountFile.equals(thisRowIds.accountFileRowId),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (f.imageLocation != null) {
|
||||||
|
batch.update(
|
||||||
|
db.imageLocations,
|
||||||
|
f.imageLocation!,
|
||||||
|
where: (sql.$ImageLocationsTable t) =>
|
||||||
|
t.accountFile.equals(thisRowIds.accountFileRowId),
|
||||||
|
);
|
||||||
|
}
|
||||||
if (f.trash != null) {
|
if (f.trash != null) {
|
||||||
batch.update(
|
batch.update(
|
||||||
db.trashes,
|
db.trashes,
|
||||||
|
@ -289,6 +297,10 @@ class FileSqliteCacheUpdater {
|
||||||
await db.into(db.images).insert(
|
await db.into(db.images).insert(
|
||||||
f.image!.copyWith(accountFile: sql.Value(dbAccountFile.rowId)));
|
f.image!.copyWith(accountFile: sql.Value(dbAccountFile.rowId)));
|
||||||
}
|
}
|
||||||
|
if (f.imageLocation != null) {
|
||||||
|
await db.into(db.imageLocations).insert(f.imageLocation!
|
||||||
|
.copyWith(accountFile: sql.Value(dbAccountFile.rowId)));
|
||||||
|
}
|
||||||
if (f.trash != null) {
|
if (f.trash != null) {
|
||||||
await db
|
await db
|
||||||
.into(db.trashes)
|
.into(db.trashes)
|
||||||
|
|
|
@ -39,6 +39,7 @@ class SearchSqliteDbDataSource implements SearchDataSource {
|
||||||
r.readTable(db.files),
|
r.readTable(db.files),
|
||||||
r.readTable(db.accountFiles),
|
r.readTable(db.accountFiles),
|
||||||
r.readTableOrNull(db.images),
|
r.readTableOrNull(db.images),
|
||||||
|
r.readTableOrNull(db.imageLocations),
|
||||||
r.readTableOrNull(db.trashes),
|
r.readTableOrNull(db.trashes),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
|
|
@ -89,6 +89,22 @@ class Images extends Table {
|
||||||
get primaryKey => {accountFile};
|
get primaryKey => {accountFile};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Estimated locations for images
|
||||||
|
class ImageLocations extends Table {
|
||||||
|
IntColumn get accountFile =>
|
||||||
|
integer().references(AccountFiles, #rowId, onDelete: KeyAction.cascade)();
|
||||||
|
IntColumn get version => integer()();
|
||||||
|
TextColumn get name => text().nullable()();
|
||||||
|
RealColumn get latitude => real().nullable()();
|
||||||
|
RealColumn get longitude => real().nullable()();
|
||||||
|
TextColumn get countryCode => text().nullable()();
|
||||||
|
TextColumn get admin1 => text().nullable()();
|
||||||
|
TextColumn get admin2 => text().nullable()();
|
||||||
|
|
||||||
|
@override
|
||||||
|
get primaryKey => {accountFile};
|
||||||
|
}
|
||||||
|
|
||||||
/// A file inside trashbin
|
/// A file inside trashbin
|
||||||
@DataClassName("Trash")
|
@DataClassName("Trash")
|
||||||
class Trashes extends Table {
|
class Trashes extends Table {
|
||||||
|
@ -184,6 +200,7 @@ class Persons extends Table {
|
||||||
Accounts,
|
Accounts,
|
||||||
Files,
|
Files,
|
||||||
Images,
|
Images,
|
||||||
|
ImageLocations,
|
||||||
Trashes,
|
Trashes,
|
||||||
AccountFiles,
|
AccountFiles,
|
||||||
DirFiles,
|
DirFiles,
|
||||||
|
@ -201,7 +218,7 @@ class SqliteDb extends _$SqliteDb {
|
||||||
SqliteDb.connect(DatabaseConnection connection) : super.connect(connection);
|
SqliteDb.connect(DatabaseConnection connection) : super.connect(connection);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
get schemaVersion => 2;
|
get schemaVersion => 3;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
get migration => MigrationStrategy(
|
get migration => MigrationStrategy(
|
||||||
|
@ -242,6 +259,10 @@ class SqliteDb extends _$SqliteDb {
|
||||||
await m.createTable(persons);
|
await m.createTable(persons);
|
||||||
await _createIndexV2(m);
|
await _createIndexV2(m);
|
||||||
}
|
}
|
||||||
|
if (from < 3) {
|
||||||
|
await m.createTable(imageLocations);
|
||||||
|
await _createIndexV3(m);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
_log.shout("[onUpgrade] Failed upgrading sqlite db", e, stackTrace);
|
_log.shout("[onUpgrade] Failed upgrading sqlite db", e, stackTrace);
|
||||||
|
@ -265,6 +286,17 @@ class SqliteDb extends _$SqliteDb {
|
||||||
"CREATE INDEX persons_account_index ON persons(account);"));
|
"CREATE INDEX persons_account_index ON persons(account);"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _createIndexV3(Migrator m) async {
|
||||||
|
await m.createIndex(Index("image_locations_name_index",
|
||||||
|
"CREATE INDEX image_locations_name_index ON image_locations(name);"));
|
||||||
|
await m.createIndex(Index("image_locations_country_code_index",
|
||||||
|
"CREATE INDEX image_locations_country_code_index ON image_locations(country_code);"));
|
||||||
|
await m.createIndex(Index("image_locations_admin1_index",
|
||||||
|
"CREATE INDEX image_locations_admin1_index ON image_locations(admin1);"));
|
||||||
|
await m.createIndex(Index("image_locations_admin2_index",
|
||||||
|
"CREATE INDEX image_locations_admin2_index ON image_locations(admin2);"));
|
||||||
|
}
|
||||||
|
|
||||||
static final _log = Logger("entity.sqlite_table.SqliteDb");
|
static final _log = Logger("entity.sqlite_table.SqliteDb");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1820,6 +1820,416 @@ class $ImagesTable extends Images with TableInfo<$ImagesTable, Image> {
|
||||||
const _DateTimeConverter();
|
const _DateTimeConverter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ImageLocation extends DataClass implements Insertable<ImageLocation> {
|
||||||
|
final int accountFile;
|
||||||
|
final int version;
|
||||||
|
final String? name;
|
||||||
|
final double? latitude;
|
||||||
|
final double? longitude;
|
||||||
|
final String? countryCode;
|
||||||
|
final String? admin1;
|
||||||
|
final String? admin2;
|
||||||
|
ImageLocation(
|
||||||
|
{required this.accountFile,
|
||||||
|
required this.version,
|
||||||
|
this.name,
|
||||||
|
this.latitude,
|
||||||
|
this.longitude,
|
||||||
|
this.countryCode,
|
||||||
|
this.admin1,
|
||||||
|
this.admin2});
|
||||||
|
factory ImageLocation.fromData(Map<String, dynamic> data, {String? prefix}) {
|
||||||
|
final effectivePrefix = prefix ?? '';
|
||||||
|
return ImageLocation(
|
||||||
|
accountFile: const IntType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}account_file'])!,
|
||||||
|
version: const IntType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}version'])!,
|
||||||
|
name: const StringType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}name']),
|
||||||
|
latitude: const RealType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}latitude']),
|
||||||
|
longitude: const RealType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}longitude']),
|
||||||
|
countryCode: const StringType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}country_code']),
|
||||||
|
admin1: const StringType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}admin1']),
|
||||||
|
admin2: const StringType()
|
||||||
|
.mapFromDatabaseResponse(data['${effectivePrefix}admin2']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, Expression>{};
|
||||||
|
map['account_file'] = Variable<int>(accountFile);
|
||||||
|
map['version'] = Variable<int>(version);
|
||||||
|
if (!nullToAbsent || name != null) {
|
||||||
|
map['name'] = Variable<String?>(name);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || latitude != null) {
|
||||||
|
map['latitude'] = Variable<double?>(latitude);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || longitude != null) {
|
||||||
|
map['longitude'] = Variable<double?>(longitude);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || countryCode != null) {
|
||||||
|
map['country_code'] = Variable<String?>(countryCode);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || admin1 != null) {
|
||||||
|
map['admin1'] = Variable<String?>(admin1);
|
||||||
|
}
|
||||||
|
if (!nullToAbsent || admin2 != null) {
|
||||||
|
map['admin2'] = Variable<String?>(admin2);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageLocationsCompanion toCompanion(bool nullToAbsent) {
|
||||||
|
return ImageLocationsCompanion(
|
||||||
|
accountFile: Value(accountFile),
|
||||||
|
version: Value(version),
|
||||||
|
name: name == null && nullToAbsent ? const Value.absent() : Value(name),
|
||||||
|
latitude: latitude == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(latitude),
|
||||||
|
longitude: longitude == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(longitude),
|
||||||
|
countryCode: countryCode == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(countryCode),
|
||||||
|
admin1:
|
||||||
|
admin1 == null && nullToAbsent ? const Value.absent() : Value(admin1),
|
||||||
|
admin2:
|
||||||
|
admin2 == null && nullToAbsent ? const Value.absent() : Value(admin2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory ImageLocation.fromJson(Map<String, dynamic> json,
|
||||||
|
{ValueSerializer? serializer}) {
|
||||||
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
|
return ImageLocation(
|
||||||
|
accountFile: serializer.fromJson<int>(json['accountFile']),
|
||||||
|
version: serializer.fromJson<int>(json['version']),
|
||||||
|
name: serializer.fromJson<String?>(json['name']),
|
||||||
|
latitude: serializer.fromJson<double?>(json['latitude']),
|
||||||
|
longitude: serializer.fromJson<double?>(json['longitude']),
|
||||||
|
countryCode: serializer.fromJson<String?>(json['countryCode']),
|
||||||
|
admin1: serializer.fromJson<String?>(json['admin1']),
|
||||||
|
admin2: serializer.fromJson<String?>(json['admin2']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||||
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
|
return <String, dynamic>{
|
||||||
|
'accountFile': serializer.toJson<int>(accountFile),
|
||||||
|
'version': serializer.toJson<int>(version),
|
||||||
|
'name': serializer.toJson<String?>(name),
|
||||||
|
'latitude': serializer.toJson<double?>(latitude),
|
||||||
|
'longitude': serializer.toJson<double?>(longitude),
|
||||||
|
'countryCode': serializer.toJson<String?>(countryCode),
|
||||||
|
'admin1': serializer.toJson<String?>(admin1),
|
||||||
|
'admin2': serializer.toJson<String?>(admin2),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageLocation copyWith(
|
||||||
|
{int? accountFile,
|
||||||
|
int? version,
|
||||||
|
Value<String?> name = const Value.absent(),
|
||||||
|
Value<double?> latitude = const Value.absent(),
|
||||||
|
Value<double?> longitude = const Value.absent(),
|
||||||
|
Value<String?> countryCode = const Value.absent(),
|
||||||
|
Value<String?> admin1 = const Value.absent(),
|
||||||
|
Value<String?> admin2 = const Value.absent()}) =>
|
||||||
|
ImageLocation(
|
||||||
|
accountFile: accountFile ?? this.accountFile,
|
||||||
|
version: version ?? this.version,
|
||||||
|
name: name.present ? name.value : this.name,
|
||||||
|
latitude: latitude.present ? latitude.value : this.latitude,
|
||||||
|
longitude: longitude.present ? longitude.value : this.longitude,
|
||||||
|
countryCode: countryCode.present ? countryCode.value : this.countryCode,
|
||||||
|
admin1: admin1.present ? admin1.value : this.admin1,
|
||||||
|
admin2: admin2.present ? admin2.value : this.admin2,
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('ImageLocation(')
|
||||||
|
..write('accountFile: $accountFile, ')
|
||||||
|
..write('version: $version, ')
|
||||||
|
..write('name: $name, ')
|
||||||
|
..write('latitude: $latitude, ')
|
||||||
|
..write('longitude: $longitude, ')
|
||||||
|
..write('countryCode: $countryCode, ')
|
||||||
|
..write('admin1: $admin1, ')
|
||||||
|
..write('admin2: $admin2')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(accountFile, version, name, latitude,
|
||||||
|
longitude, countryCode, admin1, admin2);
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
(other is ImageLocation &&
|
||||||
|
other.accountFile == this.accountFile &&
|
||||||
|
other.version == this.version &&
|
||||||
|
other.name == this.name &&
|
||||||
|
other.latitude == this.latitude &&
|
||||||
|
other.longitude == this.longitude &&
|
||||||
|
other.countryCode == this.countryCode &&
|
||||||
|
other.admin1 == this.admin1 &&
|
||||||
|
other.admin2 == this.admin2);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImageLocationsCompanion extends UpdateCompanion<ImageLocation> {
|
||||||
|
final Value<int> accountFile;
|
||||||
|
final Value<int> version;
|
||||||
|
final Value<String?> name;
|
||||||
|
final Value<double?> latitude;
|
||||||
|
final Value<double?> longitude;
|
||||||
|
final Value<String?> countryCode;
|
||||||
|
final Value<String?> admin1;
|
||||||
|
final Value<String?> admin2;
|
||||||
|
const ImageLocationsCompanion({
|
||||||
|
this.accountFile = const Value.absent(),
|
||||||
|
this.version = const Value.absent(),
|
||||||
|
this.name = const Value.absent(),
|
||||||
|
this.latitude = const Value.absent(),
|
||||||
|
this.longitude = const Value.absent(),
|
||||||
|
this.countryCode = const Value.absent(),
|
||||||
|
this.admin1 = const Value.absent(),
|
||||||
|
this.admin2 = const Value.absent(),
|
||||||
|
});
|
||||||
|
ImageLocationsCompanion.insert({
|
||||||
|
this.accountFile = const Value.absent(),
|
||||||
|
required int version,
|
||||||
|
this.name = const Value.absent(),
|
||||||
|
this.latitude = const Value.absent(),
|
||||||
|
this.longitude = const Value.absent(),
|
||||||
|
this.countryCode = const Value.absent(),
|
||||||
|
this.admin1 = const Value.absent(),
|
||||||
|
this.admin2 = const Value.absent(),
|
||||||
|
}) : version = Value(version);
|
||||||
|
static Insertable<ImageLocation> custom({
|
||||||
|
Expression<int>? accountFile,
|
||||||
|
Expression<int>? version,
|
||||||
|
Expression<String?>? name,
|
||||||
|
Expression<double?>? latitude,
|
||||||
|
Expression<double?>? longitude,
|
||||||
|
Expression<String?>? countryCode,
|
||||||
|
Expression<String?>? admin1,
|
||||||
|
Expression<String?>? admin2,
|
||||||
|
}) {
|
||||||
|
return RawValuesInsertable({
|
||||||
|
if (accountFile != null) 'account_file': accountFile,
|
||||||
|
if (version != null) 'version': version,
|
||||||
|
if (name != null) 'name': name,
|
||||||
|
if (latitude != null) 'latitude': latitude,
|
||||||
|
if (longitude != null) 'longitude': longitude,
|
||||||
|
if (countryCode != null) 'country_code': countryCode,
|
||||||
|
if (admin1 != null) 'admin1': admin1,
|
||||||
|
if (admin2 != null) 'admin2': admin2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageLocationsCompanion copyWith(
|
||||||
|
{Value<int>? accountFile,
|
||||||
|
Value<int>? version,
|
||||||
|
Value<String?>? name,
|
||||||
|
Value<double?>? latitude,
|
||||||
|
Value<double?>? longitude,
|
||||||
|
Value<String?>? countryCode,
|
||||||
|
Value<String?>? admin1,
|
||||||
|
Value<String?>? admin2}) {
|
||||||
|
return ImageLocationsCompanion(
|
||||||
|
accountFile: accountFile ?? this.accountFile,
|
||||||
|
version: version ?? this.version,
|
||||||
|
name: name ?? this.name,
|
||||||
|
latitude: latitude ?? this.latitude,
|
||||||
|
longitude: longitude ?? this.longitude,
|
||||||
|
countryCode: countryCode ?? this.countryCode,
|
||||||
|
admin1: admin1 ?? this.admin1,
|
||||||
|
admin2: admin2 ?? this.admin2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
|
final map = <String, Expression>{};
|
||||||
|
if (accountFile.present) {
|
||||||
|
map['account_file'] = Variable<int>(accountFile.value);
|
||||||
|
}
|
||||||
|
if (version.present) {
|
||||||
|
map['version'] = Variable<int>(version.value);
|
||||||
|
}
|
||||||
|
if (name.present) {
|
||||||
|
map['name'] = Variable<String?>(name.value);
|
||||||
|
}
|
||||||
|
if (latitude.present) {
|
||||||
|
map['latitude'] = Variable<double?>(latitude.value);
|
||||||
|
}
|
||||||
|
if (longitude.present) {
|
||||||
|
map['longitude'] = Variable<double?>(longitude.value);
|
||||||
|
}
|
||||||
|
if (countryCode.present) {
|
||||||
|
map['country_code'] = Variable<String?>(countryCode.value);
|
||||||
|
}
|
||||||
|
if (admin1.present) {
|
||||||
|
map['admin1'] = Variable<String?>(admin1.value);
|
||||||
|
}
|
||||||
|
if (admin2.present) {
|
||||||
|
map['admin2'] = Variable<String?>(admin2.value);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return (StringBuffer('ImageLocationsCompanion(')
|
||||||
|
..write('accountFile: $accountFile, ')
|
||||||
|
..write('version: $version, ')
|
||||||
|
..write('name: $name, ')
|
||||||
|
..write('latitude: $latitude, ')
|
||||||
|
..write('longitude: $longitude, ')
|
||||||
|
..write('countryCode: $countryCode, ')
|
||||||
|
..write('admin1: $admin1, ')
|
||||||
|
..write('admin2: $admin2')
|
||||||
|
..write(')'))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class $ImageLocationsTable extends ImageLocations
|
||||||
|
with TableInfo<$ImageLocationsTable, ImageLocation> {
|
||||||
|
@override
|
||||||
|
final GeneratedDatabase attachedDatabase;
|
||||||
|
final String? _alias;
|
||||||
|
$ImageLocationsTable(this.attachedDatabase, [this._alias]);
|
||||||
|
final VerificationMeta _accountFileMeta =
|
||||||
|
const VerificationMeta('accountFile');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<int?> accountFile = GeneratedColumn<int?>(
|
||||||
|
'account_file', aliasedName, false,
|
||||||
|
type: const IntType(),
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
defaultConstraints:
|
||||||
|
'REFERENCES account_files (row_id) ON DELETE CASCADE');
|
||||||
|
final VerificationMeta _versionMeta = const VerificationMeta('version');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<int?> version = GeneratedColumn<int?>(
|
||||||
|
'version', aliasedName, false,
|
||||||
|
type: const IntType(), requiredDuringInsert: true);
|
||||||
|
final VerificationMeta _nameMeta = const VerificationMeta('name');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String?> name = GeneratedColumn<String?>(
|
||||||
|
'name', aliasedName, true,
|
||||||
|
type: const StringType(), requiredDuringInsert: false);
|
||||||
|
final VerificationMeta _latitudeMeta = const VerificationMeta('latitude');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<double?> latitude = GeneratedColumn<double?>(
|
||||||
|
'latitude', aliasedName, true,
|
||||||
|
type: const RealType(), requiredDuringInsert: false);
|
||||||
|
final VerificationMeta _longitudeMeta = const VerificationMeta('longitude');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<double?> longitude = GeneratedColumn<double?>(
|
||||||
|
'longitude', aliasedName, true,
|
||||||
|
type: const RealType(), requiredDuringInsert: false);
|
||||||
|
final VerificationMeta _countryCodeMeta =
|
||||||
|
const VerificationMeta('countryCode');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String?> countryCode = GeneratedColumn<String?>(
|
||||||
|
'country_code', aliasedName, true,
|
||||||
|
type: const StringType(), requiredDuringInsert: false);
|
||||||
|
final VerificationMeta _admin1Meta = const VerificationMeta('admin1');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String?> admin1 = GeneratedColumn<String?>(
|
||||||
|
'admin1', aliasedName, true,
|
||||||
|
type: const StringType(), requiredDuringInsert: false);
|
||||||
|
final VerificationMeta _admin2Meta = const VerificationMeta('admin2');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String?> admin2 = GeneratedColumn<String?>(
|
||||||
|
'admin2', aliasedName, true,
|
||||||
|
type: const StringType(), requiredDuringInsert: false);
|
||||||
|
@override
|
||||||
|
List<GeneratedColumn> get $columns => [
|
||||||
|
accountFile,
|
||||||
|
version,
|
||||||
|
name,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
countryCode,
|
||||||
|
admin1,
|
||||||
|
admin2
|
||||||
|
];
|
||||||
|
@override
|
||||||
|
String get aliasedName => _alias ?? 'image_locations';
|
||||||
|
@override
|
||||||
|
String get actualTableName => 'image_locations';
|
||||||
|
@override
|
||||||
|
VerificationContext validateIntegrity(Insertable<ImageLocation> instance,
|
||||||
|
{bool isInserting = false}) {
|
||||||
|
final context = VerificationContext();
|
||||||
|
final data = instance.toColumns(true);
|
||||||
|
if (data.containsKey('account_file')) {
|
||||||
|
context.handle(
|
||||||
|
_accountFileMeta,
|
||||||
|
accountFile.isAcceptableOrUnknown(
|
||||||
|
data['account_file']!, _accountFileMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('version')) {
|
||||||
|
context.handle(_versionMeta,
|
||||||
|
version.isAcceptableOrUnknown(data['version']!, _versionMeta));
|
||||||
|
} else if (isInserting) {
|
||||||
|
context.missing(_versionMeta);
|
||||||
|
}
|
||||||
|
if (data.containsKey('name')) {
|
||||||
|
context.handle(
|
||||||
|
_nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('latitude')) {
|
||||||
|
context.handle(_latitudeMeta,
|
||||||
|
latitude.isAcceptableOrUnknown(data['latitude']!, _latitudeMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('longitude')) {
|
||||||
|
context.handle(_longitudeMeta,
|
||||||
|
longitude.isAcceptableOrUnknown(data['longitude']!, _longitudeMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('country_code')) {
|
||||||
|
context.handle(
|
||||||
|
_countryCodeMeta,
|
||||||
|
countryCode.isAcceptableOrUnknown(
|
||||||
|
data['country_code']!, _countryCodeMeta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('admin1')) {
|
||||||
|
context.handle(_admin1Meta,
|
||||||
|
admin1.isAcceptableOrUnknown(data['admin1']!, _admin1Meta));
|
||||||
|
}
|
||||||
|
if (data.containsKey('admin2')) {
|
||||||
|
context.handle(_admin2Meta,
|
||||||
|
admin2.isAcceptableOrUnknown(data['admin2']!, _admin2Meta));
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<GeneratedColumn> get $primaryKey => {accountFile};
|
||||||
|
@override
|
||||||
|
ImageLocation map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||||
|
return ImageLocation.fromData(data,
|
||||||
|
prefix: tablePrefix != null ? '$tablePrefix.' : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
$ImageLocationsTable createAlias(String alias) {
|
||||||
|
return $ImageLocationsTable(attachedDatabase, alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Trash extends DataClass implements Insertable<Trash> {
|
class Trash extends DataClass implements Insertable<Trash> {
|
||||||
final int file;
|
final int file;
|
||||||
final String filename;
|
final String filename;
|
||||||
|
@ -3717,6 +4127,7 @@ abstract class _$SqliteDb extends GeneratedDatabase {
|
||||||
late final $FilesTable files = $FilesTable(this);
|
late final $FilesTable files = $FilesTable(this);
|
||||||
late final $AccountFilesTable accountFiles = $AccountFilesTable(this);
|
late final $AccountFilesTable accountFiles = $AccountFilesTable(this);
|
||||||
late final $ImagesTable images = $ImagesTable(this);
|
late final $ImagesTable images = $ImagesTable(this);
|
||||||
|
late final $ImageLocationsTable imageLocations = $ImageLocationsTable(this);
|
||||||
late final $TrashesTable trashes = $TrashesTable(this);
|
late final $TrashesTable trashes = $TrashesTable(this);
|
||||||
late final $DirFilesTable dirFiles = $DirFilesTable(this);
|
late final $DirFilesTable dirFiles = $DirFilesTable(this);
|
||||||
late final $AlbumsTable albums = $AlbumsTable(this);
|
late final $AlbumsTable albums = $AlbumsTable(this);
|
||||||
|
@ -3732,6 +4143,7 @@ abstract class _$SqliteDb extends GeneratedDatabase {
|
||||||
files,
|
files,
|
||||||
accountFiles,
|
accountFiles,
|
||||||
images,
|
images,
|
||||||
|
imageLocations,
|
||||||
trashes,
|
trashes,
|
||||||
dirFiles,
|
dirFiles,
|
||||||
albums,
|
albums,
|
||||||
|
|
|
@ -115,6 +115,15 @@ class SqliteFileConverter {
|
||||||
imageHeight: obj.height,
|
imageHeight: obj.height,
|
||||||
exif: obj.exifRaw?.run((e) => Exif.fromJson(jsonDecode(e))),
|
exif: obj.exifRaw?.run((e) => Exif.fromJson(jsonDecode(e))),
|
||||||
));
|
));
|
||||||
|
final location = f.imageLocation?.run((obj) => ImageLocation(
|
||||||
|
version: obj.version,
|
||||||
|
name: obj.name,
|
||||||
|
latitude: obj.latitude,
|
||||||
|
longitude: obj.longitude,
|
||||||
|
countryCode: obj.countryCode,
|
||||||
|
admin1: obj.admin1,
|
||||||
|
admin2: obj.admin2,
|
||||||
|
));
|
||||||
return File(
|
return File(
|
||||||
path: "remote.php/dav/files/$userId/${f.accountFile.relativePath}",
|
path: "remote.php/dav/files/$userId/${f.accountFile.relativePath}",
|
||||||
contentLength: f.file.contentLength,
|
contentLength: f.file.contentLength,
|
||||||
|
@ -134,6 +143,7 @@ class SqliteFileConverter {
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
isArchived: f.accountFile.isArchived,
|
isArchived: f.accountFile.isArchived,
|
||||||
overrideDateTime: f.accountFile.overrideDateTime,
|
overrideDateTime: f.accountFile.overrideDateTime,
|
||||||
|
location: location,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +177,16 @@ class SqliteFileConverter {
|
||||||
exifRaw: Value(m.exif?.toJson().run((j) => jsonEncode(j))),
|
exifRaw: Value(m.exif?.toJson().run((j) => jsonEncode(j))),
|
||||||
dateTimeOriginal: Value(m.exif?.dateTimeOriginal),
|
dateTimeOriginal: Value(m.exif?.dateTimeOriginal),
|
||||||
));
|
));
|
||||||
|
final dbImageLocation =
|
||||||
|
file.location?.run((l) => sql.ImageLocationsCompanion.insert(
|
||||||
|
version: l.version,
|
||||||
|
name: Value(l.name),
|
||||||
|
latitude: Value(l.latitude),
|
||||||
|
longitude: Value(l.longitude),
|
||||||
|
countryCode: Value(l.countryCode),
|
||||||
|
admin1: Value(l.admin1),
|
||||||
|
admin2: Value(l.admin2),
|
||||||
|
));
|
||||||
final dbTrash = file.trashbinDeletionTime == null
|
final dbTrash = file.trashbinDeletionTime == null
|
||||||
? null
|
? null
|
||||||
: sql.TrashesCompanion.insert(
|
: sql.TrashesCompanion.insert(
|
||||||
|
@ -174,7 +194,8 @@ class SqliteFileConverter {
|
||||||
originalLocation: file.trashbinOriginalLocation!,
|
originalLocation: file.trashbinOriginalLocation!,
|
||||||
deletionTime: file.trashbinDeletionTime!,
|
deletionTime: file.trashbinDeletionTime!,
|
||||||
);
|
);
|
||||||
return sql.CompleteFileCompanion(dbFile, dbAccountFile, dbImage, dbTrash);
|
return sql.CompleteFileCompanion(
|
||||||
|
dbFile, dbAccountFile, dbImage, dbImageLocation, dbTrash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,21 +16,24 @@ import 'package:nc_photos/platform/k.dart' as platform_k;
|
||||||
const maxByFileIdsSize = 30000;
|
const maxByFileIdsSize = 30000;
|
||||||
|
|
||||||
class CompleteFile {
|
class CompleteFile {
|
||||||
const CompleteFile(this.file, this.accountFile, this.image, this.trash);
|
const CompleteFile(
|
||||||
|
this.file, this.accountFile, this.image, this.imageLocation, this.trash);
|
||||||
|
|
||||||
final File file;
|
final File file;
|
||||||
final AccountFile accountFile;
|
final AccountFile accountFile;
|
||||||
final Image? image;
|
final Image? image;
|
||||||
|
final ImageLocation? imageLocation;
|
||||||
final Trash? trash;
|
final Trash? trash;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CompleteFileCompanion {
|
class CompleteFileCompanion {
|
||||||
const CompleteFileCompanion(
|
const CompleteFileCompanion(
|
||||||
this.file, this.accountFile, this.image, this.trash);
|
this.file, this.accountFile, this.image, this.imageLocation, this.trash);
|
||||||
|
|
||||||
final FilesCompanion file;
|
final FilesCompanion file;
|
||||||
final AccountFilesCompanion accountFile;
|
final AccountFilesCompanion accountFile;
|
||||||
final ImagesCompanion? image;
|
final ImagesCompanion? image;
|
||||||
|
final ImageLocationsCompanion? imageLocation;
|
||||||
final TrashesCompanion? trash;
|
final TrashesCompanion? trash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,6 +350,7 @@ extension SqliteDbExtension on SqliteDb {
|
||||||
r.readTable(files),
|
r.readTable(files),
|
||||||
r.readTable(accountFiles),
|
r.readTable(accountFiles),
|
||||||
r.readTableOrNull(images),
|
r.readTableOrNull(images),
|
||||||
|
r.readTableOrNull(imageLocations),
|
||||||
r.readTableOrNull(trashes),
|
r.readTableOrNull(trashes),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
@ -374,6 +378,7 @@ extension SqliteDbExtension on SqliteDb {
|
||||||
r.readTable(files),
|
r.readTable(files),
|
||||||
r.readTable(accountFiles),
|
r.readTable(accountFiles),
|
||||||
r.readTableOrNull(images),
|
r.readTableOrNull(images),
|
||||||
|
r.readTableOrNull(imageLocations),
|
||||||
r.readTableOrNull(trashes),
|
r.readTableOrNull(trashes),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
@ -400,6 +405,7 @@ extension SqliteDbExtension on SqliteDb {
|
||||||
r.readTable(files),
|
r.readTable(files),
|
||||||
r.readTable(accountFiles),
|
r.readTable(accountFiles),
|
||||||
r.readTableOrNull(images),
|
r.readTableOrNull(images),
|
||||||
|
r.readTableOrNull(imageLocations),
|
||||||
r.readTableOrNull(trashes),
|
r.readTableOrNull(trashes),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
@ -454,6 +460,7 @@ extension SqliteDbExtension on SqliteDb {
|
||||||
await delete(accounts).go();
|
await delete(accounts).go();
|
||||||
await delete(files).go();
|
await delete(files).go();
|
||||||
await delete(images).go();
|
await delete(images).go();
|
||||||
|
await delete(imageLocations).go();
|
||||||
await delete(trashes).go();
|
await delete(trashes).go();
|
||||||
await delete(accountFiles).go();
|
await delete(accountFiles).go();
|
||||||
await delete(dirFiles).go();
|
await delete(dirFiles).go();
|
||||||
|
@ -571,6 +578,8 @@ class FilesQueryBuilder {
|
||||||
if (_queryMode == FilesQueryMode.completeFile) ...[
|
if (_queryMode == FilesQueryMode.completeFile) ...[
|
||||||
leftOuterJoin(
|
leftOuterJoin(
|
||||||
db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)),
|
db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)),
|
||||||
|
leftOuterJoin(db.imageLocations,
|
||||||
|
db.imageLocations.accountFile.equalsExp(db.accountFiles.rowId)),
|
||||||
leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)),
|
leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)),
|
||||||
],
|
],
|
||||||
]) as JoinedSelectStatement;
|
]) as JoinedSelectStatement;
|
||||||
|
|
|
@ -101,6 +101,7 @@ class WebdavResponseParser {
|
||||||
String? trashbinFilename;
|
String? trashbinFilename;
|
||||||
String? trashbinOriginalLocation;
|
String? trashbinOriginalLocation;
|
||||||
DateTime? trashbinDeletionTime;
|
DateTime? trashbinDeletionTime;
|
||||||
|
ImageLocation? location;
|
||||||
|
|
||||||
for (final child in element.children.whereType<XmlElement>()) {
|
for (final child in element.children.whereType<XmlElement>()) {
|
||||||
if (child.matchQualifiedName("href",
|
if (child.matchQualifiedName("href",
|
||||||
|
@ -139,6 +140,7 @@ class WebdavResponseParser {
|
||||||
trashbinFilename = propParser.trashbinFilename;
|
trashbinFilename = propParser.trashbinFilename;
|
||||||
trashbinOriginalLocation = propParser.trashbinOriginalLocation;
|
trashbinOriginalLocation = propParser.trashbinOriginalLocation;
|
||||||
trashbinDeletionTime = propParser.trashbinDeletionTime;
|
trashbinDeletionTime = propParser.trashbinDeletionTime;
|
||||||
|
location = propParser.location;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +163,7 @@ class WebdavResponseParser {
|
||||||
trashbinFilename: trashbinFilename,
|
trashbinFilename: trashbinFilename,
|
||||||
trashbinOriginalLocation: trashbinOriginalLocation,
|
trashbinOriginalLocation: trashbinOriginalLocation,
|
||||||
trashbinDeletionTime: trashbinDeletionTime,
|
trashbinDeletionTime: trashbinDeletionTime,
|
||||||
|
location: location,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,6 +360,9 @@ class _FilePropParser {
|
||||||
} else if (child.matchQualifiedName("override-date-time",
|
} else if (child.matchQualifiedName("override-date-time",
|
||||||
prefix: "com.nkming.nc_photos", namespaces: namespaces)) {
|
prefix: "com.nkming.nc_photos", namespaces: namespaces)) {
|
||||||
_overrideDateTime = DateTime.parse(child.innerText);
|
_overrideDateTime = DateTime.parse(child.innerText);
|
||||||
|
} else if (child.matchQualifiedName("location",
|
||||||
|
prefix: "com.nkming.nc_photos", namespaces: namespaces)) {
|
||||||
|
_location = ImageLocation.fromJson(jsonDecode(child.innerText));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2nd pass that depends on data in 1st pass
|
// 2nd pass that depends on data in 1st pass
|
||||||
|
@ -395,6 +401,7 @@ class _FilePropParser {
|
||||||
String? get trashbinFilename => _trashbinFilename;
|
String? get trashbinFilename => _trashbinFilename;
|
||||||
String? get trashbinOriginalLocation => _trashbinOriginalLocation;
|
String? get trashbinOriginalLocation => _trashbinOriginalLocation;
|
||||||
DateTime? get trashbinDeletionTime => _trashbinDeletionTime;
|
DateTime? get trashbinDeletionTime => _trashbinDeletionTime;
|
||||||
|
ImageLocation? get location => _location;
|
||||||
|
|
||||||
final Map<String, String> namespaces;
|
final Map<String, String> namespaces;
|
||||||
|
|
||||||
|
@ -418,6 +425,7 @@ class _FilePropParser {
|
||||||
String? _trashbinFilename;
|
String? _trashbinFilename;
|
||||||
String? _trashbinOriginalLocation;
|
String? _trashbinOriginalLocation;
|
||||||
DateTime? _trashbinDeletionTime;
|
DateTime? _trashbinDeletionTime;
|
||||||
|
ImageLocation? _location;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FileIdPropParser {
|
class _FileIdPropParser {
|
||||||
|
|
|
@ -71,6 +71,7 @@ class FilePropertyUpdatedEvent {
|
||||||
static const propIsArchived = 0x02;
|
static const propIsArchived = 0x02;
|
||||||
static const propOverrideDateTime = 0x04;
|
static const propOverrideDateTime = 0x04;
|
||||||
static const propFavorite = 0x08;
|
static const propFavorite = 0x08;
|
||||||
|
static const propImageLocation = 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FileRemovedEvent {
|
class FileRemovedEvent {
|
||||||
|
|
|
@ -46,6 +46,7 @@ class ScanDirOffline {
|
||||||
r.readTable(db.files),
|
r.readTable(db.files),
|
||||||
r.readTable(db.accountFiles),
|
r.readTable(db.accountFiles),
|
||||||
r.readTableOrNull(db.images),
|
r.readTableOrNull(db.images),
|
||||||
|
r.readTableOrNull(db.imageLocations),
|
||||||
r.readTableOrNull(db.trashes),
|
r.readTableOrNull(db.trashes),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
@ -97,6 +98,7 @@ class ScanDirOfflineMini {
|
||||||
r.readTable(db.files),
|
r.readTable(db.files),
|
||||||
r.readTable(db.accountFiles),
|
r.readTable(db.accountFiles),
|
||||||
r.readTableOrNull(db.images),
|
r.readTableOrNull(db.images),
|
||||||
|
r.readTableOrNull(db.imageLocations),
|
||||||
r.readTableOrNull(db.trashes),
|
r.readTableOrNull(db.trashes),
|
||||||
))
|
))
|
||||||
.get();
|
.get();
|
||||||
|
|
|
@ -16,11 +16,13 @@ class UpdateProperty {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) async {
|
}) async {
|
||||||
if (metadata == null &&
|
if (metadata == null &&
|
||||||
isArchived == null &&
|
isArchived == null &&
|
||||||
overrideDateTime == null &&
|
overrideDateTime == null &&
|
||||||
favorite == null) {
|
favorite == null &&
|
||||||
|
location == null) {
|
||||||
// ?
|
// ?
|
||||||
_log.warning("[call] Nothing to update");
|
_log.warning("[call] Nothing to update");
|
||||||
return;
|
return;
|
||||||
|
@ -37,6 +39,7 @@ class UpdateProperty {
|
||||||
isArchived: isArchived,
|
isArchived: isArchived,
|
||||||
overrideDateTime: overrideDateTime,
|
overrideDateTime: overrideDateTime,
|
||||||
favorite: favorite,
|
favorite: favorite,
|
||||||
|
location: location,
|
||||||
);
|
);
|
||||||
|
|
||||||
int properties = 0;
|
int properties = 0;
|
||||||
|
@ -52,6 +55,9 @@ class UpdateProperty {
|
||||||
if (favorite != null) {
|
if (favorite != null) {
|
||||||
properties |= FilePropertyUpdatedEvent.propFavorite;
|
properties |= FilePropertyUpdatedEvent.propFavorite;
|
||||||
}
|
}
|
||||||
|
if (location != null) {
|
||||||
|
properties |= FilePropertyUpdatedEvent.propImageLocation;
|
||||||
|
}
|
||||||
assert(properties != 0);
|
assert(properties != 0);
|
||||||
KiwiContainer()
|
KiwiContainer()
|
||||||
.resolve<EventBus>()
|
.resolve<EventBus>()
|
||||||
|
|
|
@ -313,6 +313,7 @@ Future<void> _truncate() async {
|
||||||
"accounts",
|
"accounts",
|
||||||
"files",
|
"files",
|
||||||
"images",
|
"images",
|
||||||
|
"image_locations",
|
||||||
"trashes",
|
"trashes",
|
||||||
"account_files",
|
"account_files",
|
||||||
"dir_files",
|
"dir_files",
|
||||||
|
|
|
@ -181,6 +181,7 @@ class MockFileDataSource implements FileDataSource {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) {
|
}) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
@ -272,6 +273,7 @@ class MockFileWebdavDataSource implements FileWebdavDataSource {
|
||||||
OrNull<bool>? isArchived,
|
OrNull<bool>? isArchived,
|
||||||
OrNull<DateTime>? overrideDateTime,
|
OrNull<DateTime>? overrideDateTime,
|
||||||
bool? favorite,
|
bool? favorite,
|
||||||
|
OrNull<ImageLocation>? location,
|
||||||
}) =>
|
}) =>
|
||||||
src.updateProperty(
|
src.updateProperty(
|
||||||
account,
|
account,
|
||||||
|
@ -280,6 +282,7 @@ class MockFileWebdavDataSource implements FileWebdavDataSource {
|
||||||
isArchived: isArchived,
|
isArchived: isArchived,
|
||||||
overrideDateTime: overrideDateTime,
|
overrideDateTime: overrideDateTime,
|
||||||
favorite: favorite,
|
favorite: favorite,
|
||||||
|
location: location,
|
||||||
);
|
);
|
||||||
|
|
||||||
final MockFileMemoryDataSource src;
|
final MockFileMemoryDataSource src;
|
||||||
|
|
|
@ -447,6 +447,10 @@ Future<void> insertFiles(
|
||||||
await db.into(db.images).insert(
|
await db.into(db.images).insert(
|
||||||
insert.image!.copyWith(accountFile: sql.Value(dbAccountFile.rowId)));
|
insert.image!.copyWith(accountFile: sql.Value(dbAccountFile.rowId)));
|
||||||
}
|
}
|
||||||
|
if (insert.imageLocation != null) {
|
||||||
|
await db.into(db.imageLocations).insert(insert.imageLocation!
|
||||||
|
.copyWith(accountFile: sql.Value(dbAccountFile.rowId)));
|
||||||
|
}
|
||||||
if (insert.trash != null) {
|
if (insert.trash != null) {
|
||||||
await db
|
await db
|
||||||
.into(db.trashes)
|
.into(db.trashes)
|
||||||
|
@ -499,6 +503,8 @@ Future<Set<File>> listSqliteDbFiles(sql.SqliteDb db) async {
|
||||||
db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account)),
|
db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account)),
|
||||||
sql.leftOuterJoin(
|
sql.leftOuterJoin(
|
||||||
db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)),
|
db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)),
|
||||||
|
sql.leftOuterJoin(db.imageLocations,
|
||||||
|
db.imageLocations.accountFile.equalsExp(db.accountFiles.rowId)),
|
||||||
sql.leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)),
|
sql.leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)),
|
||||||
]);
|
]);
|
||||||
return (await query
|
return (await query
|
||||||
|
@ -508,6 +514,7 @@ Future<Set<File>> listSqliteDbFiles(sql.SqliteDb db) async {
|
||||||
r.readTable(db.files),
|
r.readTable(db.files),
|
||||||
r.readTable(db.accountFiles),
|
r.readTable(db.accountFiles),
|
||||||
r.readTableOrNull(db.images),
|
r.readTableOrNull(db.images),
|
||||||
|
r.readTableOrNull(db.imageLocations),
|
||||||
r.readTableOrNull(db.trashes),
|
r.readTableOrNull(db.trashes),
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
@ -523,6 +530,8 @@ Future<Map<File, Set<File>>> listSqliteDbDirs(sql.SqliteDb db) async {
|
||||||
db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account)),
|
db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account)),
|
||||||
sql.leftOuterJoin(
|
sql.leftOuterJoin(
|
||||||
db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)),
|
db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)),
|
||||||
|
sql.leftOuterJoin(db.imageLocations,
|
||||||
|
db.imageLocations.accountFile.equalsExp(db.accountFiles.rowId)),
|
||||||
sql.leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)),
|
sql.leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)),
|
||||||
]);
|
]);
|
||||||
final fileMap = Map.fromEntries(await query.map((r) {
|
final fileMap = Map.fromEntries(await query.map((r) {
|
||||||
|
@ -530,6 +539,7 @@ Future<Map<File, Set<File>>> listSqliteDbDirs(sql.SqliteDb db) async {
|
||||||
r.readTable(db.files),
|
r.readTable(db.files),
|
||||||
r.readTable(db.accountFiles),
|
r.readTable(db.accountFiles),
|
||||||
r.readTableOrNull(db.images),
|
r.readTableOrNull(db.images),
|
||||||
|
r.readTableOrNull(db.imageLocations),
|
||||||
r.readTableOrNull(db.trashes),
|
r.readTableOrNull(db.trashes),
|
||||||
);
|
);
|
||||||
return MapEntry(
|
return MapEntry(
|
||||||
|
@ -563,6 +573,7 @@ Future<Set<Album>> listSqliteDbAlbums(sql.SqliteDb db) async {
|
||||||
r.readTable(db.accountFiles),
|
r.readTable(db.accountFiles),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return Tuple2(
|
return Tuple2(
|
||||||
|
|
Loading…
Reference in a new issue