fix: handle remote asset orientation

This commit is contained in:
shenlong-tanwen 2024-10-02 00:12:54 +05:30
parent be40d15725
commit ac3d71eee8
6 changed files with 393 additions and 74 deletions

View File

@ -57,64 +57,69 @@ const AssetSchema = CollectionSchema(
name: r'isFavorite', name: r'isFavorite',
type: IsarType.bool, type: IsarType.bool,
), ),
r'isTrashed': PropertySchema( r'isOffline': PropertySchema(
id: 8, id: 8,
name: r'isOffline',
type: IsarType.bool,
),
r'isTrashed': PropertySchema(
id: 9,
name: r'isTrashed', name: r'isTrashed',
type: IsarType.bool, type: IsarType.bool,
), ),
r'livePhotoVideoId': PropertySchema( r'livePhotoVideoId': PropertySchema(
id: 9, id: 10,
name: r'livePhotoVideoId', name: r'livePhotoVideoId',
type: IsarType.string, type: IsarType.string,
), ),
r'localId': PropertySchema( r'localId': PropertySchema(
id: 10, id: 11,
name: r'localId', name: r'localId',
type: IsarType.string, type: IsarType.string,
), ),
r'ownerId': PropertySchema( r'ownerId': PropertySchema(
id: 11, id: 12,
name: r'ownerId', name: r'ownerId',
type: IsarType.long, type: IsarType.long,
), ),
r'remoteId': PropertySchema( r'remoteId': PropertySchema(
id: 12, id: 13,
name: r'remoteId', name: r'remoteId',
type: IsarType.string, type: IsarType.string,
), ),
r'stackCount': PropertySchema( r'stackCount': PropertySchema(
id: 13, id: 14,
name: r'stackCount', name: r'stackCount',
type: IsarType.long, type: IsarType.long,
), ),
r'stackId': PropertySchema( r'stackId': PropertySchema(
id: 14, id: 15,
name: r'stackId', name: r'stackId',
type: IsarType.string, type: IsarType.string,
), ),
r'stackPrimaryAssetId': PropertySchema( r'stackPrimaryAssetId': PropertySchema(
id: 15, id: 16,
name: r'stackPrimaryAssetId', name: r'stackPrimaryAssetId',
type: IsarType.string, type: IsarType.string,
), ),
r'thumbhash': PropertySchema( r'thumbhash': PropertySchema(
id: 16, id: 17,
name: r'thumbhash', name: r'thumbhash',
type: IsarType.string, type: IsarType.string,
), ),
r'type': PropertySchema( r'type': PropertySchema(
id: 17, id: 18,
name: r'type', name: r'type',
type: IsarType.byte, type: IsarType.byte,
enumMap: _AssettypeEnumValueMap, enumMap: _AssettypeEnumValueMap,
), ),
r'updatedAt': PropertySchema( r'updatedAt': PropertySchema(
id: 18, id: 19,
name: r'updatedAt', name: r'updatedAt',
type: IsarType.dateTime, type: IsarType.dateTime,
), ),
r'width': PropertySchema( r'width': PropertySchema(
id: 19, id: 20,
name: r'width', name: r'width',
type: IsarType.int, type: IsarType.int,
) )
@ -239,18 +244,19 @@ void _assetSerialize(
writer.writeInt(offsets[5], object.height); writer.writeInt(offsets[5], object.height);
writer.writeBool(offsets[6], object.isArchived); writer.writeBool(offsets[6], object.isArchived);
writer.writeBool(offsets[7], object.isFavorite); writer.writeBool(offsets[7], object.isFavorite);
writer.writeBool(offsets[8], object.isTrashed); writer.writeBool(offsets[8], object.isOffline);
writer.writeString(offsets[9], object.livePhotoVideoId); writer.writeBool(offsets[9], object.isTrashed);
writer.writeString(offsets[10], object.localId); writer.writeString(offsets[10], object.livePhotoVideoId);
writer.writeLong(offsets[11], object.ownerId); writer.writeString(offsets[11], object.localId);
writer.writeString(offsets[12], object.remoteId); writer.writeLong(offsets[12], object.ownerId);
writer.writeLong(offsets[13], object.stackCount); writer.writeString(offsets[13], object.remoteId);
writer.writeString(offsets[14], object.stackId); writer.writeLong(offsets[14], object.stackCount);
writer.writeString(offsets[15], object.stackPrimaryAssetId); writer.writeString(offsets[15], object.stackId);
writer.writeString(offsets[16], object.thumbhash); writer.writeString(offsets[16], object.stackPrimaryAssetId);
writer.writeByte(offsets[17], object.type.index); writer.writeString(offsets[17], object.thumbhash);
writer.writeDateTime(offsets[18], object.updatedAt); writer.writeByte(offsets[18], object.type.index);
writer.writeInt(offsets[19], object.width); writer.writeDateTime(offsets[19], object.updatedAt);
writer.writeInt(offsets[20], object.width);
} }
Asset _assetDeserialize( Asset _assetDeserialize(
@ -269,19 +275,20 @@ Asset _assetDeserialize(
id: id, id: id,
isArchived: reader.readBoolOrNull(offsets[6]) ?? false, isArchived: reader.readBoolOrNull(offsets[6]) ?? false,
isFavorite: reader.readBoolOrNull(offsets[7]) ?? false, isFavorite: reader.readBoolOrNull(offsets[7]) ?? false,
isTrashed: reader.readBoolOrNull(offsets[8]) ?? false, isOffline: reader.readBoolOrNull(offsets[8]) ?? false,
livePhotoVideoId: reader.readStringOrNull(offsets[9]), isTrashed: reader.readBoolOrNull(offsets[9]) ?? false,
localId: reader.readStringOrNull(offsets[10]), livePhotoVideoId: reader.readStringOrNull(offsets[10]),
ownerId: reader.readLong(offsets[11]), localId: reader.readStringOrNull(offsets[11]),
remoteId: reader.readStringOrNull(offsets[12]), ownerId: reader.readLong(offsets[12]),
stackCount: reader.readLongOrNull(offsets[13]) ?? 0, remoteId: reader.readStringOrNull(offsets[13]),
stackId: reader.readStringOrNull(offsets[14]), stackCount: reader.readLongOrNull(offsets[14]) ?? 0,
stackPrimaryAssetId: reader.readStringOrNull(offsets[15]), stackId: reader.readStringOrNull(offsets[15]),
thumbhash: reader.readStringOrNull(offsets[16]), stackPrimaryAssetId: reader.readStringOrNull(offsets[16]),
type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[17])] ?? thumbhash: reader.readStringOrNull(offsets[17]),
type: _AssettypeValueEnumMap[reader.readByteOrNull(offsets[18])] ??
AssetType.other, AssetType.other,
updatedAt: reader.readDateTime(offsets[18]), updatedAt: reader.readDateTime(offsets[19]),
width: reader.readIntOrNull(offsets[19]), width: reader.readIntOrNull(offsets[20]),
); );
return object; return object;
} }
@ -312,27 +319,29 @@ P _assetDeserializeProp<P>(
case 8: case 8:
return (reader.readBoolOrNull(offset) ?? false) as P; return (reader.readBoolOrNull(offset) ?? false) as P;
case 9: case 9:
return (reader.readStringOrNull(offset)) as P; return (reader.readBoolOrNull(offset) ?? false) as P;
case 10: case 10:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 11: case 11:
return (reader.readLong(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 12: case 12:
return (reader.readStringOrNull(offset)) as P; return (reader.readLong(offset)) as P;
case 13: case 13:
return (reader.readLongOrNull(offset) ?? 0) as P;
case 14:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 14:
return (reader.readLongOrNull(offset) ?? 0) as P;
case 15: case 15:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 16: case 16:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 17: case 17:
return (reader.readStringOrNull(offset)) as P;
case 18:
return (_AssettypeValueEnumMap[reader.readByteOrNull(offset)] ?? return (_AssettypeValueEnumMap[reader.readByteOrNull(offset)] ??
AssetType.other) as P; AssetType.other) as P;
case 18:
return (reader.readDateTime(offset)) as P;
case 19: case 19:
return (reader.readDateTime(offset)) as P;
case 20:
return (reader.readIntOrNull(offset)) as P; return (reader.readIntOrNull(offset)) as P;
default: default:
throw IsarError('Unknown property with id $propertyId'); throw IsarError('Unknown property with id $propertyId');
@ -1353,6 +1362,16 @@ extension AssetQueryFilter on QueryBuilder<Asset, Asset, QFilterCondition> {
}); });
} }
QueryBuilder<Asset, Asset, QAfterFilterCondition> isOfflineEqualTo(
bool value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'isOffline',
value: value,
));
});
}
QueryBuilder<Asset, Asset, QAfterFilterCondition> isTrashedEqualTo( QueryBuilder<Asset, Asset, QAfterFilterCondition> isTrashedEqualTo(
bool value) { bool value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -2628,6 +2647,18 @@ extension AssetQuerySortBy on QueryBuilder<Asset, Asset, QSortBy> {
}); });
} }
QueryBuilder<Asset, Asset, QAfterSortBy> sortByIsOffline() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isOffline', Sort.asc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> sortByIsOfflineDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isOffline', Sort.desc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> sortByIsTrashed() { QueryBuilder<Asset, Asset, QAfterSortBy> sortByIsTrashed() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isTrashed', Sort.asc); return query.addSortBy(r'isTrashed', Sort.asc);
@ -2882,6 +2913,18 @@ extension AssetQuerySortThenBy on QueryBuilder<Asset, Asset, QSortThenBy> {
}); });
} }
QueryBuilder<Asset, Asset, QAfterSortBy> thenByIsOffline() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isOffline', Sort.asc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> thenByIsOfflineDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isOffline', Sort.desc);
});
}
QueryBuilder<Asset, Asset, QAfterSortBy> thenByIsTrashed() { QueryBuilder<Asset, Asset, QAfterSortBy> thenByIsTrashed() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'isTrashed', Sort.asc); return query.addSortBy(r'isTrashed', Sort.asc);
@ -3078,6 +3121,12 @@ extension AssetQueryWhereDistinct on QueryBuilder<Asset, Asset, QDistinct> {
}); });
} }
QueryBuilder<Asset, Asset, QDistinct> distinctByIsOffline() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isOffline');
});
}
QueryBuilder<Asset, Asset, QDistinct> distinctByIsTrashed() { QueryBuilder<Asset, Asset, QDistinct> distinctByIsTrashed() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'isTrashed'); return query.addDistinctBy(r'isTrashed');
@ -3214,6 +3263,12 @@ extension AssetQueryProperty on QueryBuilder<Asset, Asset, QQueryProperty> {
}); });
} }
QueryBuilder<Asset, bool, QQueryOperations> isOfflineProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isOffline');
});
}
QueryBuilder<Asset, bool, QQueryOperations> isTrashedProperty() { QueryBuilder<Asset, bool, QQueryOperations> isTrashedProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'isTrashed'); return query.addPropertyName(r'isTrashed');

View File

@ -23,6 +23,7 @@ class ExifInfo {
String? state; String? state;
String? country; String? country;
String? description; String? description;
String? orientation;
@ignore @ignore
bool get hasCoordinates => bool get hasCoordinates =>
@ -45,6 +46,9 @@ class ExifInfo {
@ignore @ignore
String get focalLength => mm != null ? mm!.toStringAsFixed(1) : ""; String get focalLength => mm != null ? mm!.toStringAsFixed(1) : "";
@ignore
bool get isFlipped => _isOrientationFlipped(orientation);
@ignore @ignore
double? get latitude => lat; double? get latitude => lat;
@ -67,7 +71,8 @@ class ExifInfo {
city = dto.city, city = dto.city,
state = dto.state, state = dto.state,
country = dto.country, country = dto.country,
description = dto.description; description = dto.description,
orientation = dto.orientation;
ExifInfo({ ExifInfo({
this.id, this.id,
@ -87,6 +92,7 @@ class ExifInfo {
this.state, this.state,
this.country, this.country,
this.description, this.description,
this.orientation,
}); });
ExifInfo copyWith({ ExifInfo copyWith({
@ -107,6 +113,7 @@ class ExifInfo {
String? state, String? state,
String? country, String? country,
String? description, String? description,
String? orientation,
}) => }) =>
ExifInfo( ExifInfo(
id: id ?? this.id, id: id ?? this.id,
@ -126,6 +133,7 @@ class ExifInfo {
state: state ?? this.state, state: state ?? this.state,
country: country ?? this.country, country: country ?? this.country,
description: description ?? this.description, description: description ?? this.description,
orientation: orientation ?? this.orientation,
); );
@override @override
@ -147,7 +155,8 @@ class ExifInfo {
city == other.city && city == other.city &&
state == other.state && state == other.state &&
country == other.country && country == other.country &&
description == other.description; description == other.description &&
orientation == other.orientation;
} }
@override @override
@ -169,7 +178,8 @@ class ExifInfo {
city.hashCode ^ city.hashCode ^
state.hashCode ^ state.hashCode ^
country.hashCode ^ country.hashCode ^
description.hashCode; description.hashCode ^
orientation.hashCode;
@override @override
String toString() { String toString() {
@ -192,10 +202,21 @@ class ExifInfo {
state: $state, state: $state,
country: $country, country: $country,
description: $description, description: $description,
orientation: $orientation
}"""; }""";
} }
} }
bool _isOrientationFlipped(String? orientation) {
final value = orientation != null ? int.tryParse(orientation) : null;
if (value == null) {
return false;
}
final isRotated90CW = value == 5 || value == 6 || value == 90;
final isRotated270CW = value == 7 || value == 8 || value == -90;
return isRotated90CW || isRotated270CW;
}
double? _exposureTimeToSeconds(String? s) { double? _exposureTimeToSeconds(String? s) {
if (s == null) { if (s == null) {
return null; return null;

View File

@ -87,13 +87,18 @@ const ExifInfoSchema = CollectionSchema(
name: r'model', name: r'model',
type: IsarType.string, type: IsarType.string,
), ),
r'state': PropertySchema( r'orientation': PropertySchema(
id: 14, id: 14,
name: r'orientation',
type: IsarType.string,
),
r'state': PropertySchema(
id: 15,
name: r'state', name: r'state',
type: IsarType.string, type: IsarType.string,
), ),
r'timeZone': PropertySchema( r'timeZone': PropertySchema(
id: 15, id: 16,
name: r'timeZone', name: r'timeZone',
type: IsarType.string, type: IsarType.string,
) )
@ -154,6 +159,12 @@ int _exifInfoEstimateSize(
bytesCount += 3 + value.length * 3; bytesCount += 3 + value.length * 3;
} }
} }
{
final value = object.orientation;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
{ {
final value = object.state; final value = object.state;
if (value != null) { if (value != null) {
@ -189,8 +200,9 @@ void _exifInfoSerialize(
writer.writeString(offsets[11], object.make); writer.writeString(offsets[11], object.make);
writer.writeFloat(offsets[12], object.mm); writer.writeFloat(offsets[12], object.mm);
writer.writeString(offsets[13], object.model); writer.writeString(offsets[13], object.model);
writer.writeString(offsets[14], object.state); writer.writeString(offsets[14], object.orientation);
writer.writeString(offsets[15], object.timeZone); writer.writeString(offsets[15], object.state);
writer.writeString(offsets[16], object.timeZone);
} }
ExifInfo _exifInfoDeserialize( ExifInfo _exifInfoDeserialize(
@ -215,8 +227,9 @@ ExifInfo _exifInfoDeserialize(
make: reader.readStringOrNull(offsets[11]), make: reader.readStringOrNull(offsets[11]),
mm: reader.readFloatOrNull(offsets[12]), mm: reader.readFloatOrNull(offsets[12]),
model: reader.readStringOrNull(offsets[13]), model: reader.readStringOrNull(offsets[13]),
state: reader.readStringOrNull(offsets[14]), orientation: reader.readStringOrNull(offsets[14]),
timeZone: reader.readStringOrNull(offsets[15]), state: reader.readStringOrNull(offsets[15]),
timeZone: reader.readStringOrNull(offsets[16]),
); );
return object; return object;
} }
@ -260,6 +273,8 @@ P _exifInfoDeserializeProp<P>(
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 15: case 15:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 16:
return (reader.readStringOrNull(offset)) as P;
default: default:
throw IsarError('Unknown property with id $propertyId'); throw IsarError('Unknown property with id $propertyId');
} }
@ -1909,6 +1924,155 @@ extension ExifInfoQueryFilter
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'orientation',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
orientationIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'orientation',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'orientation',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
orientationGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'orientation',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'orientation',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationBetween(
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'orientation',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'orientation',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'orientation',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'orientation',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'orientation',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> orientationIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'orientation',
value: '',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
orientationIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'orientation',
value: '',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> stateIsNull() { QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> stateIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( return query.addFilterCondition(const FilterCondition.isNull(
@ -2377,6 +2541,18 @@ extension ExifInfoQuerySortBy on QueryBuilder<ExifInfo, ExifInfo, QSortBy> {
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByOrientation() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'orientation', Sort.asc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByOrientationDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'orientation', Sort.desc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByState() { QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByState() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'state', Sort.asc); return query.addSortBy(r'state', Sort.asc);
@ -2584,6 +2760,18 @@ extension ExifInfoQuerySortThenBy
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByOrientation() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'orientation', Sort.asc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByOrientationDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'orientation', Sort.desc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByState() { QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByState() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'state', Sort.asc); return query.addSortBy(r'state', Sort.asc);
@ -2701,6 +2889,13 @@ extension ExifInfoQueryWhereDistinct
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QDistinct> distinctByOrientation(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'orientation', caseSensitive: caseSensitive);
});
}
QueryBuilder<ExifInfo, ExifInfo, QDistinct> distinctByState( QueryBuilder<ExifInfo, ExifInfo, QDistinct> distinctByState(
{bool caseSensitive = true}) { {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -2809,6 +3004,12 @@ extension ExifInfoQueryProperty
}); });
} }
QueryBuilder<ExifInfo, String?, QQueryOperations> orientationProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'orientation');
});
}
QueryBuilder<ExifInfo, String?, QQueryOperations> stateProperty() { QueryBuilder<ExifInfo, String?, QQueryOperations> stateProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'state'); return query.addPropertyName(r'state');

View File

@ -9,6 +9,7 @@ import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart
import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart';
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/services/asset.service.dart';
import 'package:immich_mobile/widgets/asset_viewer/custom_video_player_controls.dart'; import 'package:immich_mobile/widgets/asset_viewer/custom_video_player_controls.dart';
import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart'; import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart';
import 'package:native_video_player/native_video_player.dart'; import 'package:native_video_player/native_video_player.dart';
@ -76,6 +77,16 @@ class NativeVideoViewerPage extends HookConsumerWidget {
type: VideoSourceType.file, type: VideoSourceType.file,
); );
} else { } else {
final assetWithExif =
await ref.read(assetServiceProvider).loadExif(asset);
final shouldFlip = assetWithExif.exifInfo?.isFlipped ?? false;
width.value = (shouldFlip ? assetWithExif.height : assetWithExif.width)
?.toDouble() ??
width.value;
height.value = (shouldFlip ? assetWithExif.width : assetWithExif.height)
?.toDouble() ??
height.value;
// Use a network URL for the video player controller // Use a network URL for the video player controller
final serverEndpoint = Store.get(StoreKey.serverEndpoint); final serverEndpoint = Store.get(StoreKey.serverEndpoint);
final String videoUrl = asset.livePhotoVideoId != null final String videoUrl = asset.livePhotoVideoId != null
@ -93,10 +104,14 @@ class NativeVideoViewerPage extends HookConsumerWidget {
// When the volume changes, set the volume // When the volume changes, set the volume
ref.listen(videoPlayerControlsProvider.select((value) => value.mute), ref.listen(videoPlayerControlsProvider.select((value) => value.mute),
(_, mute) { (_, mute) {
if (mute) { try {
controller.value?.setVolume(0.0); if (mute) {
} else { controller.value?.setVolume(0.0);
controller.value?.setVolume(0.7); } else {
controller.value?.setVolume(0.7);
}
} catch (_) {
// Consume error from the controller
} }
}); });
@ -110,16 +125,24 @@ class NativeVideoViewerPage extends HookConsumerWidget {
// Find the position to seek to // Find the position to seek to
final Duration seek = asset.duration * (position / 100.0); final Duration seek = asset.duration * (position / 100.0);
controller.value?.seekTo(seek.inSeconds); try {
controller.value?.seekTo(seek.inSeconds);
} catch (_) {
// Consume error from the controller
}
}); });
// When the custom video controls paus or plays // When the custom video controls paus or plays
ref.listen(videoPlayerControlsProvider.select((value) => value.pause), ref.listen(videoPlayerControlsProvider.select((value) => value.pause),
(_, pause) { (_, pause) {
if (pause) { try {
controller.value?.pause(); if (pause) {
} else { controller.value?.pause();
controller.value?.play(); } else {
controller.value?.play();
}
} catch (_) {
// Consume error from the controller
} }
}); });
@ -153,8 +176,12 @@ class NativeVideoViewerPage extends HookConsumerWidget {
} }
void onPlaybackReady() { void onPlaybackReady() {
controller.value?.play(); try {
controller.value?.setVolume(0.9); controller.value?.play();
controller.value?.setVolume(0.9);
} catch (_) {
// Consume error from the controller
}
} }
void onPlaybackPositionChanged() { void onPlaybackPositionChanged() {
@ -162,8 +189,12 @@ class NativeVideoViewerPage extends HookConsumerWidget {
} }
void onPlaybackEnded() { void onPlaybackEnded() {
if (loopVideo) { try {
controller.value?.play(); if (loopVideo) {
controller.value?.play();
}
} catch (_) {
// Consume error from the controller
} }
} }
@ -199,12 +230,17 @@ class NativeVideoViewerPage extends HookConsumerWidget {
return () { return () {
bufferingTimer.value.cancel(); bufferingTimer.value.cancel();
controller.value?.onPlaybackPositionChanged try {
.removeListener(onPlaybackPositionChanged); controller.value?.onPlaybackPositionChanged
controller.value?.onPlaybackStatusChanged .removeListener(onPlaybackPositionChanged);
.removeListener(onPlaybackPositionChanged); controller.value?.onPlaybackStatusChanged
controller.value?.onPlaybackReady.removeListener(onPlaybackReady); .removeListener(onPlaybackPositionChanged);
controller.value?.onPlaybackEnded.removeListener(onPlaybackEnded); controller.value?.onPlaybackReady.removeListener(onPlaybackReady);
controller.value?.onPlaybackEnded.removeListener(onPlaybackEnded);
controller.value?.stop();
} catch (_) {
// Consume error from the controller
}
}; };
}, },
[], [],

View File

@ -33,8 +33,14 @@ class VideoPlaybackValue {
factory VideoPlaybackValue.fromNativeController( factory VideoPlaybackValue.fromNativeController(
NativeVideoPlayerController controller, NativeVideoPlayerController controller,
) { ) {
final playbackInfo = controller.playbackInfo; PlaybackInfo? playbackInfo;
final videoInfo = controller.videoInfo; VideoInfo? videoInfo;
try {
playbackInfo = controller.playbackInfo;
videoInfo = controller.videoInfo;
} catch (_) {
// Consume error from the controller
}
late VideoPlaybackState s; late VideoPlaybackState s;
if (playbackInfo?.status == null) { if (playbackInfo?.status == null) {
s = VideoPlaybackState.initializing; s = VideoPlaybackState.initializing;

View File

@ -4,7 +4,7 @@ import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/utils/db.dart'; import 'package:immich_mobile/utils/db.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
const int targetVersion = 6; const int targetVersion = 7;
Future<void> migrateDatabaseIfNeeded(Isar db) async { Future<void> migrateDatabaseIfNeeded(Isar db) async {
final int version = Store.get(StoreKey.version, 1); final int version = Store.get(StoreKey.version, 1);