perf(inventory): lazy list, photo thumbnails, indexes, debounced reload
Scale the local inventory to 10k+ varieties: - Render the list with ListView.builder over a flattened header/item model instead of building every tile upfront. - Store a small regenerable JPEG thumbnail per photo (schema v14) and use it for the 48px list avatar; full bytes stay for offer image hosting. Existing photos are backfilled lazily at startup. Thumbnail is local-only (excluded from CRDT sync and backups by the JSON codec). - Add indexes on varieties(is_deleted,is_draft), attachments(parent_type, parent_id,kind), lots(variety_id) via @TableIndex. - Debounce watchInventoryView (~250ms) so a burst of table writes triggers one reload, not seven. - cacheWidth/cacheHeight on the list avatar decode. - Scale test raised 3k -> 10k; migration test v13 -> v14.
This commit is contained in:
parent
2884ddd3c7
commit
3de01bd948
12 changed files with 5114 additions and 34 deletions
|
|
@ -7975,6 +7975,17 @@ class $AttachmentsTable extends Attachments
|
|||
type: DriftSqlType.blob,
|
||||
requiredDuringInsert: false,
|
||||
);
|
||||
static const VerificationMeta _thumbnailMeta = const VerificationMeta(
|
||||
'thumbnail',
|
||||
);
|
||||
@override
|
||||
late final GeneratedColumn<Uint8List> thumbnail = GeneratedColumn<Uint8List>(
|
||||
'thumbnail',
|
||||
aliasedName,
|
||||
true,
|
||||
type: DriftSqlType.blob,
|
||||
requiredDuringInsert: false,
|
||||
);
|
||||
static const VerificationMeta _mimeTypeMeta = const VerificationMeta(
|
||||
'mimeType',
|
||||
);
|
||||
|
|
@ -8011,6 +8022,7 @@ class $AttachmentsTable extends Attachments
|
|||
kind,
|
||||
uri,
|
||||
bytes,
|
||||
thumbnail,
|
||||
mimeType,
|
||||
sortOrder,
|
||||
];
|
||||
|
|
@ -8090,6 +8102,12 @@ class $AttachmentsTable extends Attachments
|
|||
bytes.isAcceptableOrUnknown(data['bytes']!, _bytesMeta),
|
||||
);
|
||||
}
|
||||
if (data.containsKey('thumbnail')) {
|
||||
context.handle(
|
||||
_thumbnailMeta,
|
||||
thumbnail.isAcceptableOrUnknown(data['thumbnail']!, _thumbnailMeta),
|
||||
);
|
||||
}
|
||||
if (data.containsKey('mime_type')) {
|
||||
context.handle(
|
||||
_mimeTypeMeta,
|
||||
|
|
@ -8159,6 +8177,10 @@ class $AttachmentsTable extends Attachments
|
|||
DriftSqlType.blob,
|
||||
data['${effectivePrefix}bytes'],
|
||||
),
|
||||
thumbnail: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.blob,
|
||||
data['${effectivePrefix}thumbnail'],
|
||||
),
|
||||
mimeType: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}mime_type'],
|
||||
|
|
@ -8193,6 +8215,13 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
final AttachmentKind kind;
|
||||
final String? uri;
|
||||
final Uint8List? bytes;
|
||||
|
||||
/// A small JPEG thumbnail of [bytes] (photos only), decoded once on save so
|
||||
/// the inventory list never has to decode the full-resolution photo for a
|
||||
/// 48px avatar. Purely derived, local and regenerable — it is EXCLUDED from
|
||||
/// CRDT sync payloads and backups (see [SyncColumns] usage); a peer or a
|
||||
/// restored backup regenerates it lazily via `backfillThumbnails`.
|
||||
final Uint8List? thumbnail;
|
||||
final String? mimeType;
|
||||
|
||||
/// Display order among sibling attachments (lower first). The lowest-ordered
|
||||
|
|
@ -8212,6 +8241,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
required this.kind,
|
||||
this.uri,
|
||||
this.bytes,
|
||||
this.thumbnail,
|
||||
this.mimeType,
|
||||
required this.sortOrder,
|
||||
});
|
||||
|
|
@ -8241,6 +8271,9 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
if (!nullToAbsent || bytes != null) {
|
||||
map['bytes'] = Variable<Uint8List>(bytes);
|
||||
}
|
||||
if (!nullToAbsent || thumbnail != null) {
|
||||
map['thumbnail'] = Variable<Uint8List>(thumbnail);
|
||||
}
|
||||
if (!nullToAbsent || mimeType != null) {
|
||||
map['mime_type'] = Variable<String>(mimeType);
|
||||
}
|
||||
|
|
@ -8263,6 +8296,9 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
bytes: bytes == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(bytes),
|
||||
thumbnail: thumbnail == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(thumbnail),
|
||||
mimeType: mimeType == null && nullToAbsent
|
||||
? const Value.absent()
|
||||
: Value(mimeType),
|
||||
|
|
@ -8291,6 +8327,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
),
|
||||
uri: serializer.fromJson<String?>(json['uri']),
|
||||
bytes: serializer.fromJson<Uint8List?>(json['bytes']),
|
||||
thumbnail: serializer.fromJson<Uint8List?>(json['thumbnail']),
|
||||
mimeType: serializer.fromJson<String?>(json['mimeType']),
|
||||
sortOrder: serializer.fromJson<int>(json['sortOrder']),
|
||||
);
|
||||
|
|
@ -8314,6 +8351,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
),
|
||||
'uri': serializer.toJson<String?>(uri),
|
||||
'bytes': serializer.toJson<Uint8List?>(bytes),
|
||||
'thumbnail': serializer.toJson<Uint8List?>(thumbnail),
|
||||
'mimeType': serializer.toJson<String?>(mimeType),
|
||||
'sortOrder': serializer.toJson<int>(sortOrder),
|
||||
};
|
||||
|
|
@ -8331,6 +8369,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
AttachmentKind? kind,
|
||||
Value<String?> uri = const Value.absent(),
|
||||
Value<Uint8List?> bytes = const Value.absent(),
|
||||
Value<Uint8List?> thumbnail = const Value.absent(),
|
||||
Value<String?> mimeType = const Value.absent(),
|
||||
int? sortOrder,
|
||||
}) => Attachment(
|
||||
|
|
@ -8345,6 +8384,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
kind: kind ?? this.kind,
|
||||
uri: uri.present ? uri.value : this.uri,
|
||||
bytes: bytes.present ? bytes.value : this.bytes,
|
||||
thumbnail: thumbnail.present ? thumbnail.value : this.thumbnail,
|
||||
mimeType: mimeType.present ? mimeType.value : this.mimeType,
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
);
|
||||
|
|
@ -8367,6 +8407,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
kind: data.kind.present ? data.kind.value : this.kind,
|
||||
uri: data.uri.present ? data.uri.value : this.uri,
|
||||
bytes: data.bytes.present ? data.bytes.value : this.bytes,
|
||||
thumbnail: data.thumbnail.present ? data.thumbnail.value : this.thumbnail,
|
||||
mimeType: data.mimeType.present ? data.mimeType.value : this.mimeType,
|
||||
sortOrder: data.sortOrder.present ? data.sortOrder.value : this.sortOrder,
|
||||
);
|
||||
|
|
@ -8386,6 +8427,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
..write('kind: $kind, ')
|
||||
..write('uri: $uri, ')
|
||||
..write('bytes: $bytes, ')
|
||||
..write('thumbnail: $thumbnail, ')
|
||||
..write('mimeType: $mimeType, ')
|
||||
..write('sortOrder: $sortOrder')
|
||||
..write(')'))
|
||||
|
|
@ -8405,6 +8447,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
kind,
|
||||
uri,
|
||||
$driftBlobEquality.hash(bytes),
|
||||
$driftBlobEquality.hash(thumbnail),
|
||||
mimeType,
|
||||
sortOrder,
|
||||
);
|
||||
|
|
@ -8423,6 +8466,7 @@ class Attachment extends DataClass implements Insertable<Attachment> {
|
|||
other.kind == this.kind &&
|
||||
other.uri == this.uri &&
|
||||
$driftBlobEquality.equals(other.bytes, this.bytes) &&
|
||||
$driftBlobEquality.equals(other.thumbnail, this.thumbnail) &&
|
||||
other.mimeType == this.mimeType &&
|
||||
other.sortOrder == this.sortOrder);
|
||||
}
|
||||
|
|
@ -8439,6 +8483,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
final Value<AttachmentKind> kind;
|
||||
final Value<String?> uri;
|
||||
final Value<Uint8List?> bytes;
|
||||
final Value<Uint8List?> thumbnail;
|
||||
final Value<String?> mimeType;
|
||||
final Value<int> sortOrder;
|
||||
final Value<int> rowid;
|
||||
|
|
@ -8454,6 +8499,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
this.kind = const Value.absent(),
|
||||
this.uri = const Value.absent(),
|
||||
this.bytes = const Value.absent(),
|
||||
this.thumbnail = const Value.absent(),
|
||||
this.mimeType = const Value.absent(),
|
||||
this.sortOrder = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
|
|
@ -8470,6 +8516,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
required AttachmentKind kind,
|
||||
this.uri = const Value.absent(),
|
||||
this.bytes = const Value.absent(),
|
||||
this.thumbnail = const Value.absent(),
|
||||
this.mimeType = const Value.absent(),
|
||||
this.sortOrder = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
|
|
@ -8492,6 +8539,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
Expression<String>? kind,
|
||||
Expression<String>? uri,
|
||||
Expression<Uint8List>? bytes,
|
||||
Expression<Uint8List>? thumbnail,
|
||||
Expression<String>? mimeType,
|
||||
Expression<int>? sortOrder,
|
||||
Expression<int>? rowid,
|
||||
|
|
@ -8508,6 +8556,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
if (kind != null) 'kind': kind,
|
||||
if (uri != null) 'uri': uri,
|
||||
if (bytes != null) 'bytes': bytes,
|
||||
if (thumbnail != null) 'thumbnail': thumbnail,
|
||||
if (mimeType != null) 'mime_type': mimeType,
|
||||
if (sortOrder != null) 'sort_order': sortOrder,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
|
|
@ -8526,6 +8575,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
Value<AttachmentKind>? kind,
|
||||
Value<String?>? uri,
|
||||
Value<Uint8List?>? bytes,
|
||||
Value<Uint8List?>? thumbnail,
|
||||
Value<String?>? mimeType,
|
||||
Value<int>? sortOrder,
|
||||
Value<int>? rowid,
|
||||
|
|
@ -8542,6 +8592,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
kind: kind ?? this.kind,
|
||||
uri: uri ?? this.uri,
|
||||
bytes: bytes ?? this.bytes,
|
||||
thumbnail: thumbnail ?? this.thumbnail,
|
||||
mimeType: mimeType ?? this.mimeType,
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
rowid: rowid ?? this.rowid,
|
||||
|
|
@ -8588,6 +8639,9 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
if (bytes.present) {
|
||||
map['bytes'] = Variable<Uint8List>(bytes.value);
|
||||
}
|
||||
if (thumbnail.present) {
|
||||
map['thumbnail'] = Variable<Uint8List>(thumbnail.value);
|
||||
}
|
||||
if (mimeType.present) {
|
||||
map['mime_type'] = Variable<String>(mimeType.value);
|
||||
}
|
||||
|
|
@ -8614,6 +8668,7 @@ class AttachmentsCompanion extends UpdateCompanion<Attachment> {
|
|||
..write('kind: $kind, ')
|
||||
..write('uri: $uri, ')
|
||||
..write('bytes: $bytes, ')
|
||||
..write('thumbnail: $thumbnail, ')
|
||||
..write('mimeType: $mimeType, ')
|
||||
..write('sortOrder: $sortOrder, ')
|
||||
..write('rowid: $rowid')
|
||||
|
|
@ -11435,6 +11490,18 @@ abstract class _$AppDatabase extends GeneratedDatabase {
|
|||
late final $ExternalLinksTable externalLinks = $ExternalLinksTable(this);
|
||||
late final $PlantaresTable plantares = $PlantaresTable(this);
|
||||
late final $SalesTable sales = $SalesTable(this);
|
||||
late final Index idxVarietiesDeletedDraft = Index(
|
||||
'idx_varieties_deleted_draft',
|
||||
'CREATE INDEX idx_varieties_deleted_draft ON varieties (is_deleted, is_draft)',
|
||||
);
|
||||
late final Index idxLotsVariety = Index(
|
||||
'idx_lots_variety',
|
||||
'CREATE INDEX idx_lots_variety ON lots (variety_id)',
|
||||
);
|
||||
late final Index idxAttachmentsParent = Index(
|
||||
'idx_attachments_parent',
|
||||
'CREATE INDEX idx_attachments_parent ON attachments (parent_type, parent_id, kind)',
|
||||
);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
|
|
@ -11454,6 +11521,9 @@ abstract class _$AppDatabase extends GeneratedDatabase {
|
|||
externalLinks,
|
||||
plantares,
|
||||
sales,
|
||||
idxVarietiesDeletedDraft,
|
||||
idxLotsVariety,
|
||||
idxAttachmentsParent,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -15118,6 +15188,7 @@ typedef $$AttachmentsTableCreateCompanionBuilder =
|
|||
required AttachmentKind kind,
|
||||
Value<String?> uri,
|
||||
Value<Uint8List?> bytes,
|
||||
Value<Uint8List?> thumbnail,
|
||||
Value<String?> mimeType,
|
||||
Value<int> sortOrder,
|
||||
Value<int> rowid,
|
||||
|
|
@ -15135,6 +15206,7 @@ typedef $$AttachmentsTableUpdateCompanionBuilder =
|
|||
Value<AttachmentKind> kind,
|
||||
Value<String?> uri,
|
||||
Value<Uint8List?> bytes,
|
||||
Value<Uint8List?> thumbnail,
|
||||
Value<String?> mimeType,
|
||||
Value<int> sortOrder,
|
||||
Value<int> rowid,
|
||||
|
|
@ -15206,6 +15278,11 @@ class $$AttachmentsTableFilterComposer
|
|||
builder: (column) => ColumnFilters(column),
|
||||
);
|
||||
|
||||
ColumnFilters<Uint8List> get thumbnail => $composableBuilder(
|
||||
column: $table.thumbnail,
|
||||
builder: (column) => ColumnFilters(column),
|
||||
);
|
||||
|
||||
ColumnFilters<String> get mimeType => $composableBuilder(
|
||||
column: $table.mimeType,
|
||||
builder: (column) => ColumnFilters(column),
|
||||
|
|
@ -15281,6 +15358,11 @@ class $$AttachmentsTableOrderingComposer
|
|||
builder: (column) => ColumnOrderings(column),
|
||||
);
|
||||
|
||||
ColumnOrderings<Uint8List> get thumbnail => $composableBuilder(
|
||||
column: $table.thumbnail,
|
||||
builder: (column) => ColumnOrderings(column),
|
||||
);
|
||||
|
||||
ColumnOrderings<String> get mimeType => $composableBuilder(
|
||||
column: $table.mimeType,
|
||||
builder: (column) => ColumnOrderings(column),
|
||||
|
|
@ -15341,6 +15423,9 @@ class $$AttachmentsTableAnnotationComposer
|
|||
GeneratedColumn<Uint8List> get bytes =>
|
||||
$composableBuilder(column: $table.bytes, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<Uint8List> get thumbnail =>
|
||||
$composableBuilder(column: $table.thumbnail, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get mimeType =>
|
||||
$composableBuilder(column: $table.mimeType, builder: (column) => column);
|
||||
|
||||
|
|
@ -15390,6 +15475,7 @@ class $$AttachmentsTableTableManager
|
|||
Value<AttachmentKind> kind = const Value.absent(),
|
||||
Value<String?> uri = const Value.absent(),
|
||||
Value<Uint8List?> bytes = const Value.absent(),
|
||||
Value<Uint8List?> thumbnail = const Value.absent(),
|
||||
Value<String?> mimeType = const Value.absent(),
|
||||
Value<int> sortOrder = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
|
|
@ -15405,6 +15491,7 @@ class $$AttachmentsTableTableManager
|
|||
kind: kind,
|
||||
uri: uri,
|
||||
bytes: bytes,
|
||||
thumbnail: thumbnail,
|
||||
mimeType: mimeType,
|
||||
sortOrder: sortOrder,
|
||||
rowid: rowid,
|
||||
|
|
@ -15422,6 +15509,7 @@ class $$AttachmentsTableTableManager
|
|||
required AttachmentKind kind,
|
||||
Value<String?> uri = const Value.absent(),
|
||||
Value<Uint8List?> bytes = const Value.absent(),
|
||||
Value<Uint8List?> thumbnail = const Value.absent(),
|
||||
Value<String?> mimeType = const Value.absent(),
|
||||
Value<int> sortOrder = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
|
|
@ -15437,6 +15525,7 @@ class $$AttachmentsTableTableManager
|
|||
kind: kind,
|
||||
uri: uri,
|
||||
bytes: bytes,
|
||||
thumbnail: thumbnail,
|
||||
mimeType: mimeType,
|
||||
sortOrder: sortOrder,
|
||||
rowid: rowid,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue