feat: locked view mobile (#18316)

* feat: locked/private view

* feat: locked/private view

* feat: mobile lock/private view

* feat: mobile lock/private view

* merge main

* pr feedback

* pr feedback

* bottom sheet sizing

* always lock when navigating away
This commit is contained in:
Alex
2025-05-20 08:35:22 -05:00
committed by GitHub
parent 397808dd1a
commit fe71894308
57 changed files with 1893 additions and 289 deletions
+25 -2
View File
@@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:io';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
@@ -45,7 +46,8 @@ class Asset {
: remote.stack?.primaryAssetId,
stackCount = remote.stack?.assetCount ?? 0,
stackId = remote.stack?.id,
thumbhash = remote.thumbhash;
thumbhash = remote.thumbhash,
visibility = getVisibility(remote.visibility);
Asset({
this.id = Isar.autoIncrement,
@@ -71,6 +73,7 @@ class Asset {
this.stackCount = 0,
this.isOffline = false,
this.thumbhash,
this.visibility = AssetVisibilityEnum.timeline,
});
@ignore
@@ -173,6 +176,9 @@ class Asset {
int stackCount;
@Enumerated(EnumType.ordinal)
AssetVisibilityEnum visibility;
/// Returns null if the asset has no sync access to the exif info
@ignore
double? get aspectRatio {
@@ -349,7 +355,8 @@ class Asset {
a.thumbhash != thumbhash ||
stackId != a.stackId ||
stackCount != a.stackCount ||
stackPrimaryAssetId == null && a.stackPrimaryAssetId != null;
stackPrimaryAssetId == null && a.stackPrimaryAssetId != null ||
visibility != a.visibility;
}
/// Returns a new [Asset] with values from this and merged & updated with [a]
@@ -452,6 +459,7 @@ class Asset {
String? stackPrimaryAssetId,
int? stackCount,
String? thumbhash,
AssetVisibilityEnum? visibility,
}) =>
Asset(
id: id ?? this.id,
@@ -477,6 +485,7 @@ class Asset {
stackPrimaryAssetId: stackPrimaryAssetId ?? this.stackPrimaryAssetId,
stackCount: stackCount ?? this.stackCount,
thumbhash: thumbhash ?? this.thumbhash,
visibility: visibility ?? this.visibility,
);
Future<void> put(Isar db) async {
@@ -541,8 +550,22 @@ class Asset {
"isArchived": $isArchived,
"isTrashed": $isTrashed,
"isOffline": $isOffline,
"visibility": "$visibility",
}""";
}
static getVisibility(AssetResponseDtoVisibilityEnum visibility) {
switch (visibility) {
case AssetResponseDtoVisibilityEnum.timeline:
return AssetVisibilityEnum.timeline;
case AssetResponseDtoVisibilityEnum.archive:
return AssetVisibilityEnum.archive;
case AssetResponseDtoVisibilityEnum.hidden:
return AssetVisibilityEnum.hidden;
case AssetResponseDtoVisibilityEnum.locked:
return AssetVisibilityEnum.locked;
}
}
}
enum AssetType {
+118 -3
View File
@@ -118,8 +118,14 @@ const AssetSchema = CollectionSchema(
name: r'updatedAt',
type: IsarType.dateTime,
),
r'width': PropertySchema(
r'visibility': PropertySchema(
id: 20,
name: r'visibility',
type: IsarType.byte,
enumMap: _AssetvisibilityEnumValueMap,
),
r'width': PropertySchema(
id: 21,
name: r'width',
type: IsarType.int,
)
@@ -256,7 +262,8 @@ void _assetSerialize(
writer.writeString(offsets[17], object.thumbhash);
writer.writeByte(offsets[18], object.type.index);
writer.writeDateTime(offsets[19], object.updatedAt);
writer.writeInt(offsets[20], object.width);
writer.writeByte(offsets[20], object.visibility.index);
writer.writeInt(offsets[21], object.width);
}
Asset _assetDeserialize(
@@ -288,7 +295,10 @@ Asset _assetDeserialize(
type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[18])] ??
AssetType.other,
updatedAt: reader.readDateTime(offsets[19]),
width: reader.readIntOrNull(offsets[20]),
visibility:
_AssetvisibilityValueEnumMap[reader.readByteOrNull(offsets[20])] ??
AssetVisibilityEnum.timeline,
width: reader.readIntOrNull(offsets[21]),
);
return object;
}
@@ -342,6 +352,9 @@ P _assetDeserializeProp<P>(
case 19:
return (reader.readDateTime(offset)) as P;
case 20:
return (_AssetvisibilityValueEnumMap[reader.readByteOrNull(offset)] ??
AssetVisibilityEnum.timeline) as P;
case 21:
return (reader.readIntOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@@ -360,6 +373,18 @@ const _AssettypeValueEnumMap = {
2: AssetType.video,
3: AssetType.audio,
};
const _AssetvisibilityEnumValueMap = {
'timeline': 0,
'hidden': 1,
'archive': 2,
'locked': 3,
};
const _AssetvisibilityValueEnumMap = {
0: AssetVisibilityEnum.timeline,
1: AssetVisibilityEnum.hidden,
2: AssetVisibilityEnum.archive,
3: AssetVisibilityEnum.locked,
};
Id _assetGetId(Asset object) {
return object.id;
@@ -2477,6 +2502,59 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> {
});
}
QueryBuilder<Asset, Asset, QAfterFilterCondition> visibilityEqualTo(
AssetVisibilityEnum value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'visibility',
value: value,
));
});
}
QueryBuilder<Asset, Asset, QAfterFilterCondition> visibilityGreaterThan(
AssetVisibilityEnum value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'visibility',
value: value,
));
});
}
QueryBuilder<Asset, Asset, QAfterFilterCondition> visibilityLessThan(
AssetVisibilityEnum value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'visibility',
value: value,
));
});
}
QueryBuilder<Asset, Asset, QAfterFilterCondition> visibilityBetween(
AssetVisibilityEnum lower,
AssetVisibilityEnum upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'visibility',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<Asset, Asset, QAfterFilterCondition> widthIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
@@ -2791,6 +2869,18 @@ extension AssetQuerySortBy on QueryBuilder<Asset, Asset, QSortBy> {
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> sortByVisibility() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'visibility', Sort.asc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> sortByVisibilityDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'visibility', Sort.desc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> sortByWidth() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'width', Sort.asc);
@@ -3057,6 +3147,18 @@ extension AssetQuerySortThenBy on QueryBuilder<Asset, Asset, QSortThenBy> {
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> thenByVisibility() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'visibility', Sort.asc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> thenByVisibilityDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'visibility', Sort.desc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> thenByWidth() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'width', Sort.asc);
@@ -3201,6 +3303,12 @@ extension AssetQueryWhereDistinct on QueryBuilder<Asset, Asset, QDistinct> {
});
}
QueryBuilder<Asset, Asset, QDistinct> distinctByVisibility() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'visibility');
});
}
QueryBuilder<Asset, Asset, QDistinct> distinctByWidth() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'width');
@@ -3335,6 +3443,13 @@ extension AssetQueryProperty on QueryBuilder<Asset, Asset, QQueryProperty> {
});
}
QueryBuilder<Asset, AssetVisibilityEnum, QQueryOperations>
visibilityProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'visibility');
});
}
QueryBuilder<Asset, int?, QQueryOperations> widthProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'width');