Compare commits
27 commits
main
...
feat/mobil
Author | SHA1 | Date | |
---|---|---|---|
|
fcfeb6dce1 | ||
|
2bc16ffe71 | ||
|
bb81c5a99a | ||
|
785fc2af90 | ||
|
f14880ba53 | ||
|
9e63554889 | ||
|
ce2ecbea40 | ||
|
c08d9a7001 | ||
|
b76b18fd2f | ||
|
3084c292d2 | ||
|
76c0d53b1d | ||
|
c9a0e73d87 | ||
|
67c7a5a2ff | ||
|
031e3592ee | ||
|
ceceedc138 | ||
|
2308a7fe04 | ||
|
f60d5e3bef | ||
|
d9a66663b8 | ||
|
38b945111c | ||
|
8f8b083a56 | ||
|
115fd62878 | ||
|
49fae9c4cc | ||
|
14df94fbb8 | ||
|
c35de5ad74 | ||
|
d1011f96ad | ||
|
4fab2bcf63 | ||
|
000c2bf43f |
9 changed files with 291 additions and 66 deletions
4
mobile/.gitignore
vendored
4
mobile/.gitignore
vendored
|
@ -53,4 +53,6 @@ ios/fastlane/report.xml
|
|||
# Isar
|
||||
default.isar
|
||||
default.isar.lock
|
||||
libisar.so
|
||||
libisar.so
|
||||
default.isar-lck
|
||||
isar.dll
|
|
@ -126,25 +126,27 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
|
|||
}
|
||||
|
||||
Widget _buildThumbnailOrPlaceholder(Asset asset, int index) {
|
||||
return ThumbnailImage(
|
||||
asset: asset,
|
||||
index: index,
|
||||
loadAsset: widget.renderList.loadAsset,
|
||||
totalAssets: widget.renderList.totalAssets,
|
||||
multiselectEnabled: widget.selectionActive,
|
||||
isSelected: widget.selectionActive && _selectedAssets.contains(asset),
|
||||
onSelect: () => _selectAssets([asset]),
|
||||
onDeselect: widget.canDeselect ||
|
||||
widget.preselectedAssets == null ||
|
||||
!widget.preselectedAssets!.contains(asset)
|
||||
? () => _deselectAssets([asset])
|
||||
: null,
|
||||
useGrayBoxPlaceholder: true,
|
||||
showStorageIndicator: widget.showStorageIndicator,
|
||||
heroOffset: widget.heroOffset,
|
||||
showStack: widget.showStack,
|
||||
isOwner: widget.isOwner,
|
||||
sharedAlbumId: widget.sharedAlbumId,
|
||||
return RepaintBoundary(
|
||||
child: ThumbnailImage(
|
||||
asset: asset,
|
||||
index: index,
|
||||
loadAsset: widget.renderList.loadAsset,
|
||||
totalAssets: widget.renderList.totalAssets,
|
||||
multiselectEnabled: widget.selectionActive,
|
||||
isSelected: widget.selectionActive && _selectedAssets.contains(asset),
|
||||
onSelect: () => _selectAssets([asset]),
|
||||
onDeselect: widget.canDeselect ||
|
||||
widget.preselectedAssets == null ||
|
||||
!widget.preselectedAssets!.contains(asset)
|
||||
? () => _deselectAssets([asset])
|
||||
: null,
|
||||
useGrayBoxPlaceholder: true,
|
||||
showStorageIndicator: widget.showStorageIndicator,
|
||||
heroOffset: widget.heroOffset,
|
||||
showStack: widget.showStack,
|
||||
isOwner: widget.isOwner,
|
||||
sharedAlbumId: widget.sharedAlbumId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ class Asset {
|
|||
remote.exifInfo != null ? ExifInfo.fromDto(remote.exifInfo!) : null,
|
||||
isFavorite = remote.isFavorite,
|
||||
isArchived = remote.isArchived,
|
||||
thumbhash =
|
||||
remote.thumbhash != null ? base64.decode(remote.thumbhash!) : null,
|
||||
isTrashed = remote.isTrashed,
|
||||
stackParentId = remote.stackParentId,
|
||||
stackCount = remote.stackCount;
|
||||
|
@ -79,6 +81,7 @@ class Asset {
|
|||
this.exifInfo,
|
||||
required this.isFavorite,
|
||||
required this.isArchived,
|
||||
required this.thumbhash,
|
||||
required this.isTrashed,
|
||||
this.stackParentId,
|
||||
required this.stackCount,
|
||||
|
@ -110,6 +113,8 @@ class Asset {
|
|||
/// because Isar cannot sort lists of byte arrays
|
||||
String checksum;
|
||||
|
||||
List<byte>? thumbhash;
|
||||
|
||||
@Index(unique: false, replace: false, type: IndexType.hash)
|
||||
String? remoteId;
|
||||
|
||||
|
@ -197,6 +202,7 @@ class Asset {
|
|||
if (identical(this, other)) return true;
|
||||
return id == other.id &&
|
||||
checksum == other.checksum &&
|
||||
thumbhash == other.thumbhash &&
|
||||
remoteId == other.remoteId &&
|
||||
localId == other.localId &&
|
||||
ownerId == other.ownerId &&
|
||||
|
@ -222,6 +228,7 @@ class Asset {
|
|||
int get hashCode =>
|
||||
id.hashCode ^
|
||||
checksum.hashCode ^
|
||||
thumbhash.hashCode ^
|
||||
remoteId.hashCode ^
|
||||
localId.hashCode ^
|
||||
ownerId.hashCode ^
|
||||
|
@ -251,6 +258,7 @@ class Asset {
|
|||
a.isLocal && !isLocal ||
|
||||
width == null && a.width != null ||
|
||||
height == null && a.height != null ||
|
||||
thumbhash == null && a.thumbhash != null ||
|
||||
livePhotoVideoId == null && a.livePhotoVideoId != null ||
|
||||
stackParentId == null && a.stackParentId != null ||
|
||||
isFavorite != a.isFavorite ||
|
||||
|
@ -295,6 +303,7 @@ class Asset {
|
|||
isFavorite: isFavorite,
|
||||
isArchived: isArchived,
|
||||
isTrashed: isTrashed,
|
||||
thumbhash: thumbhash,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -312,6 +321,7 @@ class Asset {
|
|||
isFavorite: a.isFavorite,
|
||||
isArchived: a.isArchived,
|
||||
isTrashed: a.isTrashed,
|
||||
thumbhash: a.thumbhash,
|
||||
exifInfo: a.exifInfo?.copyWith(id: id) ?? exifInfo,
|
||||
);
|
||||
} else {
|
||||
|
@ -329,6 +339,7 @@ class Asset {
|
|||
Asset _copyWith({
|
||||
Id? id,
|
||||
String? checksum,
|
||||
List<byte>? thumbhash,
|
||||
String? remoteId,
|
||||
String? localId,
|
||||
int? ownerId,
|
||||
|
@ -351,6 +362,7 @@ class Asset {
|
|||
Asset(
|
||||
id: id ?? this.id,
|
||||
checksum: checksum ?? this.checksum,
|
||||
thumbhash: thumbhash ?? this.thumbhash,
|
||||
remoteId: remoteId ?? this.remoteId,
|
||||
localId: localId ?? this.localId,
|
||||
ownerId: ownerId ?? this.ownerId,
|
||||
|
@ -406,6 +418,7 @@ class Asset {
|
|||
{
|
||||
"id": ${id == Isar.autoIncrement ? '"N/A"' : id},
|
||||
"remoteId": "${remoteId ?? "N/A"}",
|
||||
"thumbhash": "$thumbhash",
|
||||
"localId": "${localId ?? "N/A"}",
|
||||
"checksum": "$checksum",
|
||||
"ownerId": $ownerId,
|
||||
|
|
202
mobile/lib/shared/models/asset.g.dart
generated
202
mobile/lib/shared/models/asset.g.dart
generated
|
@ -92,19 +92,24 @@ const AssetSchema = CollectionSchema(
|
|||
name: r'stackParentId',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'type': PropertySchema(
|
||||
r'thumbhash': PropertySchema(
|
||||
id: 15,
|
||||
name: r'thumbhash',
|
||||
type: IsarType.byteList,
|
||||
),
|
||||
r'type': PropertySchema(
|
||||
id: 16,
|
||||
name: r'type',
|
||||
type: IsarType.byte,
|
||||
enumMap: _AssettypeEnumValueMap,
|
||||
),
|
||||
r'updatedAt': PropertySchema(
|
||||
id: 16,
|
||||
id: 17,
|
||||
name: r'updatedAt',
|
||||
type: IsarType.dateTime,
|
||||
),
|
||||
r'width': PropertySchema(
|
||||
id: 17,
|
||||
id: 18,
|
||||
name: r'width',
|
||||
type: IsarType.int,
|
||||
)
|
||||
|
@ -200,6 +205,12 @@ int _assetEstimateSize(
|
|||
bytesCount += 3 + value.length * 3;
|
||||
}
|
||||
}
|
||||
{
|
||||
final value = object.thumbhash;
|
||||
if (value != null) {
|
||||
bytesCount += 3 + value.length;
|
||||
}
|
||||
}
|
||||
return bytesCount;
|
||||
}
|
||||
|
||||
|
@ -224,9 +235,10 @@ void _assetSerialize(
|
|||
writer.writeString(offsets[12], object.remoteId);
|
||||
writer.writeLong(offsets[13], object.stackCount);
|
||||
writer.writeString(offsets[14], object.stackParentId);
|
||||
writer.writeByte(offsets[15], object.type.index);
|
||||
writer.writeDateTime(offsets[16], object.updatedAt);
|
||||
writer.writeInt(offsets[17], object.width);
|
||||
writer.writeByteList(offsets[15], object.thumbhash);
|
||||
writer.writeByte(offsets[16], object.type.index);
|
||||
writer.writeDateTime(offsets[17], object.updatedAt);
|
||||
writer.writeInt(offsets[18], object.width);
|
||||
}
|
||||
|
||||
Asset _assetDeserialize(
|
||||
|
@ -252,10 +264,11 @@ Asset _assetDeserialize(
|
|||
remoteId: reader.readStringOrNull(offsets[12]),
|
||||
stackCount: reader.readLongOrNull(offsets[13]),
|
||||
stackParentId: reader.readStringOrNull(offsets[14]),
|
||||
type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[15])] ??
|
||||
thumbhash: reader.readByteList(offsets[15]),
|
||||
type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[16])] ??
|
||||
AssetType.other,
|
||||
updatedAt: reader.readDateTime(offsets[16]),
|
||||
width: reader.readIntOrNull(offsets[17]),
|
||||
updatedAt: reader.readDateTime(offsets[17]),
|
||||
width: reader.readIntOrNull(offsets[18]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
@ -298,11 +311,13 @@ P _assetDeserializeProp<P>(
|
|||
case 14:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 15:
|
||||
return (reader.readByteList(offset)) as P;
|
||||
case 16:
|
||||
return (_AssettypeValueEnumMap[reader.readByteOrNull(offset)] ??
|
||||
AssetType.other) as P;
|
||||
case 16:
|
||||
return (reader.readDateTime(offset)) as P;
|
||||
case 17:
|
||||
return (reader.readDateTime(offset)) as P;
|
||||
case 18:
|
||||
return (reader.readIntOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
|
@ -2040,6 +2055,159 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'thumbhash',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'thumbhash',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashElementEqualTo(
|
||||
int value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'thumbhash',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashElementGreaterThan(
|
||||
int value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'thumbhash',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashElementLessThan(
|
||||
int value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'thumbhash',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashElementBetween(
|
||||
int lower,
|
||||
int upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'thumbhash',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashLengthEqualTo(
|
||||
int length) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.listLength(
|
||||
r'thumbhash',
|
||||
length,
|
||||
true,
|
||||
length,
|
||||
true,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.listLength(
|
||||
r'thumbhash',
|
||||
0,
|
||||
true,
|
||||
0,
|
||||
true,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.listLength(
|
||||
r'thumbhash',
|
||||
0,
|
||||
false,
|
||||
999999,
|
||||
true,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashLengthLessThan(
|
||||
int length, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.listLength(
|
||||
r'thumbhash',
|
||||
0,
|
||||
true,
|
||||
length,
|
||||
include,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashLengthGreaterThan(
|
||||
int length, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.listLength(
|
||||
r'thumbhash',
|
||||
length,
|
||||
include,
|
||||
999999,
|
||||
true,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> thumbhashLengthBetween(
|
||||
int lower,
|
||||
int upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.listLength(
|
||||
r'thumbhash',
|
||||
lower,
|
||||
includeLower,
|
||||
upper,
|
||||
includeUpper,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QAfterFilterCondition> typeEqualTo(
|
||||
AssetType value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
@ -2766,6 +2934,12 @@ extension AssetQueryWhereDistinct on QueryBuilder<Asset, Asset, QDistinct> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QDistinct> distinctByThumbhash() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'thumbhash');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, Asset, QDistinct> distinctByType() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'type');
|
||||
|
@ -2882,6 +3056,12 @@ extension AssetQueryProperty on QueryBuilder<Asset, Asset, QQueryProperty> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, List<int>?, QQueryOperations> thumbhashProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'thumbhash');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Asset, AssetType, QQueryOperations> typeProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'type');
|
||||
|
|
|
@ -2,6 +2,8 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:flutter_thumbhash/flutter_thumbhash.dart';
|
||||
import 'package:image_fade/image_fade.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
|
@ -94,47 +96,45 @@ class ImmichImage extends StatelessWidget {
|
|||
}
|
||||
final String? token = Store.get(StoreKey.accessToken);
|
||||
final String thumbnailRequestUrl = getThumbnailUrl(asset, type: type);
|
||||
return CachedNetworkImage(
|
||||
imageUrl: thumbnailRequestUrl,
|
||||
httpHeaders: {"Authorization": "Bearer $token"},
|
||||
cacheKey: getThumbnailCacheKey(asset, type: type),
|
||||
Widget placeholderWidget;
|
||||
if (asset.thumbhash != null) {
|
||||
placeholderWidget = FittedBox(
|
||||
fit: BoxFit.fill,
|
||||
child: Image(
|
||||
image: ThumbHash.fromIntList(asset.thumbhash!).toImage(),
|
||||
),
|
||||
);
|
||||
} else if (useGrayBoxPlaceholder) {
|
||||
placeholderWidget = const DecoratedBox(
|
||||
decoration: BoxDecoration(color: Colors.grey),
|
||||
);
|
||||
} else {
|
||||
placeholderWidget = Transform.scale(
|
||||
scale: 0.2,
|
||||
child: const CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
return ImageFade(
|
||||
width: width,
|
||||
height: height,
|
||||
// keeping memCacheWidth, memCacheHeight, maxWidthDiskCache and
|
||||
// maxHeightDiskCache = null allows to simply store the webp thumbnail
|
||||
// from the server and use it for all rendered thumbnail sizes
|
||||
image: CachedNetworkImageProvider(
|
||||
thumbnailRequestUrl,
|
||||
headers: {"Authorization": "Bearer $token"},
|
||||
cacheKey: getThumbnailCacheKey(asset, type: type),
|
||||
),
|
||||
fit: fit,
|
||||
fadeInDuration: const Duration(milliseconds: 250),
|
||||
progressIndicatorBuilder: (context, url, downloadProgress) {
|
||||
// Show loading if desired
|
||||
return Stack(
|
||||
children: [
|
||||
if (useGrayBoxPlaceholder)
|
||||
const SizedBox.square(
|
||||
dimension: 250,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
if (useProgressIndicator)
|
||||
Transform.scale(
|
||||
scale: 2,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 1,
|
||||
value: downloadProgress.progress,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
errorWidget: (context, url, error) {
|
||||
duration: const Duration(milliseconds: 300),
|
||||
syncDuration: const Duration(milliseconds: 0),
|
||||
placeholder: placeholderWidget,
|
||||
errorBuilder: (context, error) {
|
||||
if (error is HttpExceptionWithStatus &&
|
||||
error.statusCode >= 400 &&
|
||||
error.statusCode < 500) {
|
||||
debugPrint("Evicting thumbnail '$url' from cache: $error");
|
||||
CachedNetworkImage.evictFromCache(url);
|
||||
debugPrint(
|
||||
"Evicting thumbnail '$thumbnailRequestUrl' from cache: $error",
|
||||
);
|
||||
CachedNetworkImage.evictFromCache(thumbnailRequestUrl);
|
||||
}
|
||||
return Icon(
|
||||
Icons.image_not_supported_outlined,
|
||||
|
|
|
@ -597,6 +597,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_thumbhash:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_thumbhash
|
||||
sha256: "0a21f7fc4ffefe79f93b047780ad7d5af42a0f0a49b9ec5fb94005e6deebe4ad"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0+1"
|
||||
flutter_udid:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -767,6 +775,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.0"
|
||||
image_fade:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_fade
|
||||
sha256: "7296c9c53cd5de98e675ef1e27bdaa4035d6c3a45cf5b86094b2e545689b4ea6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.2"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1504,6 +1520,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
thumbhash:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: thumbhash
|
||||
sha256: "5f6d31c5279ca0b5caa81ec10aae8dcaab098d82cb699ea66ada4ed09c794a37"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0+1"
|
||||
time:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -58,6 +58,8 @@ dependencies:
|
|||
wakelock_plus: ^1.1.1
|
||||
flutter_local_notifications: ^15.1.0+1
|
||||
timezone: ^0.9.2
|
||||
flutter_thumbhash: 0.1.0+1
|
||||
image_fade: 0.6.2
|
||||
|
||||
openapi:
|
||||
path: openapi
|
||||
|
|
|
@ -26,6 +26,7 @@ void main() {
|
|||
isArchived: false,
|
||||
isTrashed: false,
|
||||
stackCount: 0,
|
||||
thumbhash: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ void main() {
|
|||
isArchived: false,
|
||||
isTrashed: false,
|
||||
stackCount: 0,
|
||||
thumbhash: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue