mirror of
https://github.com/immich-app/immich
synced 2026-08-29 13:15:45 +00:00
chore(mobile): migrate remaining simple classes to Freezed (#30907)
This commit is contained in:
parent
2f48a8aab4
commit
37e033a09d
23 changed files with 259 additions and 764 deletions
|
|
@ -1,48 +1,15 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
|
||||
class CleanupConfig {
|
||||
final bool keepFavorites;
|
||||
final AssetKeepType keepMediaType;
|
||||
final List<String> keepAlbumIds;
|
||||
final int cutoffDaysAgo;
|
||||
final bool defaultsInitialized;
|
||||
part 'cleanup_config.freezed.dart';
|
||||
|
||||
const CleanupConfig({
|
||||
this.keepFavorites = true,
|
||||
this.keepMediaType = AssetKeepType.none,
|
||||
this.keepAlbumIds = const [],
|
||||
this.cutoffDaysAgo = -1,
|
||||
this.defaultsInitialized = false,
|
||||
});
|
||||
|
||||
CleanupConfig copyWith({
|
||||
bool? keepFavorites,
|
||||
AssetKeepType? keepMediaType,
|
||||
List<String>? keepAlbumIds,
|
||||
int? cutoffDaysAgo,
|
||||
bool? defaultsInitialized,
|
||||
}) => .new(
|
||||
keepFavorites: keepFavorites ?? this.keepFavorites,
|
||||
keepMediaType: keepMediaType ?? this.keepMediaType,
|
||||
keepAlbumIds: keepAlbumIds ?? this.keepAlbumIds,
|
||||
cutoffDaysAgo: cutoffDaysAgo ?? this.cutoffDaysAgo,
|
||||
defaultsInitialized: defaultsInitialized ?? this.defaultsInitialized,
|
||||
);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is CleanupConfig &&
|
||||
other.keepFavorites == keepFavorites &&
|
||||
other.keepMediaType == keepMediaType &&
|
||||
other.keepAlbumIds == keepAlbumIds &&
|
||||
other.cutoffDaysAgo == cutoffDaysAgo &&
|
||||
other.defaultsInitialized == defaultsInitialized);
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(keepFavorites, keepMediaType, keepAlbumIds, cutoffDaysAgo, defaultsInitialized);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'CleanupConfig(keepFavorites: $keepFavorites, keepMediaType: $keepMediaType, keepAlbumIds: $keepAlbumIds, cutoffDaysAgo: $cutoffDaysAgo, defaultsInitialized: $defaultsInitialized)';
|
||||
@freezed
|
||||
abstract class CleanupConfig with _$CleanupConfig {
|
||||
const factory CleanupConfig({
|
||||
@Default(true) bool keepFavorites,
|
||||
@Default(AssetKeepType.none) AssetKeepType keepMediaType,
|
||||
@Default([]) List<String> keepAlbumIds,
|
||||
@Default(-1) int cutoffDaysAgo,
|
||||
@Default(false) bool defaultsInitialized,
|
||||
}) = _CleanupConfig;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,24 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/utils/option.dart';
|
||||
|
||||
class MapConfig {
|
||||
final int relativeDays;
|
||||
final bool favoritesOnly;
|
||||
final bool includeArchived;
|
||||
final ThemeMode themeMode;
|
||||
final bool withPartners;
|
||||
final DateTime? customFrom;
|
||||
final DateTime? customTo;
|
||||
part 'map_config.freezed.dart';
|
||||
|
||||
const MapConfig({
|
||||
this.relativeDays = 0,
|
||||
this.favoritesOnly = false,
|
||||
this.includeArchived = false,
|
||||
this.themeMode = .system,
|
||||
this.withPartners = false,
|
||||
this.customFrom,
|
||||
this.customTo,
|
||||
});
|
||||
@Freezed(copyWith: false)
|
||||
abstract class MapConfig with _$MapConfig {
|
||||
const MapConfig._();
|
||||
|
||||
const factory MapConfig({
|
||||
@Default(0) int relativeDays,
|
||||
@Default(false) bool favoritesOnly,
|
||||
@Default(false) bool includeArchived,
|
||||
@Default(ThemeMode.system) ThemeMode themeMode,
|
||||
@Default(false) bool withPartners,
|
||||
DateTime? customFrom,
|
||||
DateTime? customTo,
|
||||
}) = _MapConfig;
|
||||
|
||||
// We patch `customFrom` and `customTo`, which prevents us from using Freezed `copyWith`
|
||||
MapConfig copyWith({
|
||||
int? relativeDays,
|
||||
bool? favoritesOnly,
|
||||
|
|
@ -37,24 +36,4 @@ class MapConfig {
|
|||
customFrom: customFrom.patch(this.customFrom),
|
||||
customTo: customTo.patch(this.customTo),
|
||||
);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is MapConfig &&
|
||||
other.relativeDays == relativeDays &&
|
||||
other.favoritesOnly == favoritesOnly &&
|
||||
other.includeArchived == includeArchived &&
|
||||
other.themeMode == themeMode &&
|
||||
other.withPartners == withPartners &&
|
||||
other.customFrom == customFrom &&
|
||||
other.customTo == customTo);
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(relativeDays, favoritesOnly, includeArchived, themeMode, withPartners, customFrom, customTo);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'MapConfig(relativeDays: $relativeDays, favoritesOnly: $favoritesOnly, includeArchived: $includeArchived, themeMode: $themeMode, withPartners: $withPartners, customFrom: $customFrom, customTo: $customTo)';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/utils/option.dart';
|
||||
|
||||
class NetworkConfig {
|
||||
final bool autoEndpointSwitching;
|
||||
final String? preferredWifiName;
|
||||
final String? localEndpoint;
|
||||
final List<String> externalEndpointList;
|
||||
final Map<String, String> customHeaders;
|
||||
part 'network_config.freezed.dart';
|
||||
|
||||
const NetworkConfig({
|
||||
this.autoEndpointSwitching = false,
|
||||
this.preferredWifiName,
|
||||
this.localEndpoint,
|
||||
this.externalEndpointList = const [],
|
||||
this.customHeaders = const {},
|
||||
});
|
||||
@Freezed(copyWith: false)
|
||||
abstract class NetworkConfig with _$NetworkConfig {
|
||||
const NetworkConfig._();
|
||||
|
||||
const factory NetworkConfig({
|
||||
@Default(false) bool autoEndpointSwitching,
|
||||
String? preferredWifiName,
|
||||
String? localEndpoint,
|
||||
@Default([]) List<String> externalEndpointList,
|
||||
@Default({}) Map<String, String> customHeaders,
|
||||
}) = _NetworkConfig;
|
||||
|
||||
// We patch `preferredWifiName` and `localEndpoint`, which prevents us from using Freezed `copyWith`
|
||||
NetworkConfig copyWith({
|
||||
bool? autoEndpointSwitching,
|
||||
Option<String>? preferredWifiName,
|
||||
|
|
@ -29,27 +29,4 @@ class NetworkConfig {
|
|||
externalEndpointList: externalEndpointList ?? this.externalEndpointList,
|
||||
customHeaders: customHeaders ?? this.customHeaders,
|
||||
);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is NetworkConfig &&
|
||||
other.autoEndpointSwitching == autoEndpointSwitching &&
|
||||
other.preferredWifiName == preferredWifiName &&
|
||||
other.localEndpoint == localEndpoint &&
|
||||
listEquals(other.externalEndpointList, externalEndpointList) &&
|
||||
mapEquals(other.customHeaders, customHeaders));
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
autoEndpointSwitching,
|
||||
preferredWifiName,
|
||||
localEndpoint,
|
||||
Object.hashAll(externalEndpointList),
|
||||
Object.hashAllUnordered(customHeaders.entries.map((e) => Object.hash(e.key, e.value))),
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'NetworkConfig(autoEndpointSwitching: $autoEndpointSwitching, preferredWifiName: $preferredWifiName, localEndpoint: $localEndpoint, externalEndpointList: $externalEndpointList, customHeaders: $customHeaders)';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,22 +15,8 @@ abstract class Stack with _$Stack {
|
|||
}) = _Stack;
|
||||
}
|
||||
|
||||
class StackResponse {
|
||||
final String id;
|
||||
final String primaryAssetId;
|
||||
final List<String> assetIds;
|
||||
|
||||
const StackResponse({required this.id, required this.primaryAssetId, required this.assetIds});
|
||||
|
||||
@override
|
||||
bool operator ==(covariant StackResponse other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.id == id && other.primaryAssetId == primaryAssetId && other.assetIds == assetIds;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode ^ primaryAssetId.hashCode ^ assetIds.hashCode;
|
||||
@freezed
|
||||
abstract class StackResponse with _$StackResponse {
|
||||
const factory StackResponse({required String id, required String primaryAssetId, required List<String> assetIds}) =
|
||||
_StackResponse;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
|
||||
part 'store.model.freezed.dart';
|
||||
|
||||
/// Key for each possible value in the `Store`.
|
||||
/// Defines the data type for each value
|
||||
enum StoreKey<T> {
|
||||
|
|
@ -63,30 +66,7 @@ enum StoreKey<T> {
|
|||
Type get type => T;
|
||||
}
|
||||
|
||||
class StoreDto<T> {
|
||||
final StoreKey<T> key;
|
||||
final T? value;
|
||||
|
||||
const StoreDto(this.key, this.value);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''
|
||||
StoreDto: {
|
||||
key: $key,
|
||||
value: ${value ?? '<NA>'},
|
||||
}''';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant StoreDto<T> other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.key == key && other.value == value;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => key.hashCode ^ value.hashCode;
|
||||
@freezed
|
||||
abstract class StoreDto<T> with _$StoreDto<T> {
|
||||
const factory StoreDto(StoreKey<T> key, T? value) = _StoreDto<T>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/utils/option.dart';
|
||||
|
||||
class TimeRange {
|
||||
final DateTime? from;
|
||||
final DateTime? to;
|
||||
part 'time_range.model.freezed.dart';
|
||||
|
||||
const TimeRange({this.from, this.to});
|
||||
@Freezed(copyWith: false)
|
||||
abstract class TimeRange with _$TimeRange {
|
||||
const TimeRange._();
|
||||
|
||||
TimeRange copyWith({Option<DateTime>? from, Option<DateTime>? to}) {
|
||||
return TimeRange(from: from.patch(this.from), to: to.patch(this.to));
|
||||
}
|
||||
const factory TimeRange({DateTime? from, DateTime? to}) = _TimeRange;
|
||||
|
||||
// Patching is custom, which prevents using Freezed `copyWith`
|
||||
TimeRange copyWith({Option<DateTime>? from, Option<DateTime>? to}) =>
|
||||
TimeRange(from: from.patch(this.from), to: to.patch(this.to));
|
||||
|
||||
TimeRange clearFrom() => TimeRange(to: to);
|
||||
TimeRange clearTo() => TimeRange(from: from);
|
||||
|
|
|
|||
|
|
@ -35,96 +35,31 @@ enum AvatarColor {
|
|||
}
|
||||
|
||||
// TODO: Rename to User once Isar is removed
|
||||
class UserDto {
|
||||
final String id;
|
||||
final String email;
|
||||
final String name;
|
||||
final bool isAdmin;
|
||||
final DateTime? updatedAt;
|
||||
@Freezed(equal: false)
|
||||
abstract class UserDto with _$UserDto {
|
||||
const UserDto._();
|
||||
|
||||
final AvatarColor avatarColor;
|
||||
|
||||
final bool memoryEnabled;
|
||||
final bool inTimeline;
|
||||
|
||||
final bool isPartnerSharedBy;
|
||||
final bool isPartnerSharedWith;
|
||||
|
||||
final int quotaUsageInBytes;
|
||||
final int quotaSizeInBytes;
|
||||
const factory UserDto({
|
||||
required String id,
|
||||
required String email,
|
||||
required String name,
|
||||
@Default(false) bool isAdmin,
|
||||
DateTime? updatedAt,
|
||||
required DateTime profileChangedAt,
|
||||
@Default(AvatarColor.primary) AvatarColor avatarColor,
|
||||
@Default(true) bool memoryEnabled,
|
||||
@Default(false) bool inTimeline,
|
||||
@Default(false) bool isPartnerSharedBy,
|
||||
@Default(false) bool isPartnerSharedWith,
|
||||
@Default(false) bool hasProfileImage,
|
||||
@Default(0) int quotaUsageInBytes,
|
||||
@Default(0) int quotaSizeInBytes,
|
||||
}) = _UserDto;
|
||||
|
||||
bool get hasQuota => quotaSizeInBytes > 0;
|
||||
|
||||
final bool hasProfileImage;
|
||||
final DateTime profileChangedAt;
|
||||
|
||||
const UserDto({
|
||||
required this.id,
|
||||
required this.email,
|
||||
required this.name,
|
||||
this.isAdmin = false,
|
||||
this.updatedAt,
|
||||
required this.profileChangedAt,
|
||||
this.avatarColor = AvatarColor.primary,
|
||||
this.memoryEnabled = true,
|
||||
this.inTimeline = false,
|
||||
this.isPartnerSharedBy = false,
|
||||
this.isPartnerSharedWith = false,
|
||||
this.hasProfileImage = false,
|
||||
this.quotaUsageInBytes = 0,
|
||||
this.quotaSizeInBytes = 0,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''User: {
|
||||
id: $id,
|
||||
email: $email,
|
||||
name: $name,
|
||||
isAdmin: $isAdmin,
|
||||
updatedAt: $updatedAt,
|
||||
avatarColor: $avatarColor,
|
||||
memoryEnabled: $memoryEnabled,
|
||||
inTimeline: $inTimeline,
|
||||
isPartnerSharedBy: $isPartnerSharedBy,
|
||||
isPartnerSharedWith: $isPartnerSharedWith,
|
||||
hasProfileImage: $hasProfileImage
|
||||
profileChangedAt: $profileChangedAt
|
||||
}''';
|
||||
}
|
||||
|
||||
UserDto copyWith({
|
||||
String? id,
|
||||
String? email,
|
||||
String? name,
|
||||
bool? isAdmin,
|
||||
DateTime? updatedAt,
|
||||
AvatarColor? avatarColor,
|
||||
bool? memoryEnabled,
|
||||
bool? inTimeline,
|
||||
bool? isPartnerSharedBy,
|
||||
bool? isPartnerSharedWith,
|
||||
bool? hasProfileImage,
|
||||
DateTime? profileChangedAt,
|
||||
int? quotaSizeInBytes,
|
||||
int? quotaUsageInBytes,
|
||||
}) => UserDto(
|
||||
id: id ?? this.id,
|
||||
email: email ?? this.email,
|
||||
name: name ?? this.name,
|
||||
isAdmin: isAdmin ?? this.isAdmin,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
avatarColor: avatarColor ?? this.avatarColor,
|
||||
memoryEnabled: memoryEnabled ?? this.memoryEnabled,
|
||||
inTimeline: inTimeline ?? this.inTimeline,
|
||||
isPartnerSharedBy: isPartnerSharedBy ?? this.isPartnerSharedBy,
|
||||
isPartnerSharedWith: isPartnerSharedWith ?? this.isPartnerSharedWith,
|
||||
hasProfileImage: hasProfileImage ?? this.hasProfileImage,
|
||||
profileChangedAt: profileChangedAt ?? this.profileChangedAt,
|
||||
quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes,
|
||||
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
|
||||
);
|
||||
|
||||
// We use [DateTime.isAtSameMomentAs] for comparing across timezones. As Freezed doesn't support custom equality, we need to have our own `==` for now
|
||||
// TODO(agg23): Switch to newtypes to fix equality
|
||||
@override
|
||||
bool operator ==(covariant UserDto other) {
|
||||
if (identical(this, other)) {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'livephotos_medatada.model.freezed.dart';
|
||||
|
||||
enum LivePhotosPart { video, image }
|
||||
|
||||
class LivePhotosMetadata {
|
||||
// enum
|
||||
LivePhotosPart part;
|
||||
@Freezed(fromJson: false, toJson: false)
|
||||
abstract class LivePhotosMetadata with _$LivePhotosMetadata {
|
||||
const LivePhotosMetadata._();
|
||||
|
||||
String id;
|
||||
LivePhotosMetadata({required this.part, required this.id});
|
||||
|
||||
LivePhotosMetadata copyWith({LivePhotosPart? part, String? id}) {
|
||||
return LivePhotosMetadata(part: part ?? this.part, id: id ?? this.id);
|
||||
}
|
||||
const factory LivePhotosMetadata({required LivePhotosPart part, required String id}) = _LivePhotosMetadata;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{'part': part.index, 'id': id};
|
||||
|
|
@ -25,19 +24,4 @@ class LivePhotosMetadata {
|
|||
|
||||
factory LivePhotosMetadata.fromJson(String source) =>
|
||||
LivePhotosMetadata.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() => 'LivePhotosMetadata(part: $part, id: $id)';
|
||||
|
||||
@override
|
||||
bool operator ==(covariant LivePhotosMetadata other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.part == part && other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => part.hashCode ^ id.hashCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,11 @@ import 'package:immich_mobile/utils/option.dart';
|
|||
|
||||
part 'search_filter.model.freezed.dart';
|
||||
|
||||
class SearchLocationFilter {
|
||||
String? country;
|
||||
String? state;
|
||||
String? city;
|
||||
SearchLocationFilter({this.country, this.state, this.city});
|
||||
@Freezed(fromJson: false, toJson: false)
|
||||
abstract class SearchLocationFilter with _$SearchLocationFilter {
|
||||
const SearchLocationFilter._();
|
||||
|
||||
SearchLocationFilter copyWith({String? country, String? state, String? city}) {
|
||||
return SearchLocationFilter(country: country ?? this.country, state: state ?? this.state, city: city ?? this.city);
|
||||
}
|
||||
const factory SearchLocationFilter({String? country, String? state, String? city}) = _SearchLocationFilter;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{'country': country, 'state': state, 'city': city};
|
||||
|
|
@ -33,31 +29,13 @@ class SearchLocationFilter {
|
|||
|
||||
factory SearchLocationFilter.fromJson(String source) =>
|
||||
SearchLocationFilter.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() => 'SearchLocationFilter(country: $country, state: $state, city: $city)';
|
||||
|
||||
@override
|
||||
bool operator ==(covariant SearchLocationFilter other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.country == country && other.state == state && other.city == city;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => country.hashCode ^ state.hashCode ^ city.hashCode;
|
||||
}
|
||||
|
||||
class SearchCameraFilter {
|
||||
String? make;
|
||||
String? model;
|
||||
SearchCameraFilter({this.make, this.model});
|
||||
@Freezed(fromJson: false, toJson: false)
|
||||
abstract class SearchCameraFilter with _$SearchCameraFilter {
|
||||
const SearchCameraFilter._();
|
||||
|
||||
SearchCameraFilter copyWith({String? make, String? model}) {
|
||||
return SearchCameraFilter(make: make ?? this.make, model: model ?? this.model);
|
||||
}
|
||||
const factory SearchCameraFilter({String? make, String? model}) = _SearchCameraFilter;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{'make': make, 'model': model};
|
||||
|
|
@ -74,31 +52,13 @@ class SearchCameraFilter {
|
|||
|
||||
factory SearchCameraFilter.fromJson(String source) =>
|
||||
SearchCameraFilter.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() => 'SearchCameraFilter(make: $make, model: $model)';
|
||||
|
||||
@override
|
||||
bool operator ==(covariant SearchCameraFilter other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.make == make && other.model == model;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => make.hashCode ^ model.hashCode;
|
||||
}
|
||||
|
||||
class SearchDateFilter {
|
||||
DateTime? takenBefore;
|
||||
DateTime? takenAfter;
|
||||
SearchDateFilter({this.takenBefore, this.takenAfter});
|
||||
@Freezed(fromJson: false, toJson: false)
|
||||
abstract class SearchDateFilter with _$SearchDateFilter {
|
||||
const SearchDateFilter._();
|
||||
|
||||
SearchDateFilter copyWith({DateTime? takenBefore, DateTime? takenAfter}) {
|
||||
return SearchDateFilter(takenBefore: takenBefore ?? this.takenBefore, takenAfter: takenAfter ?? this.takenAfter);
|
||||
}
|
||||
const factory SearchDateFilter({DateTime? takenBefore, DateTime? takenAfter}) = _SearchDateFilter;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
|
|
@ -118,31 +78,15 @@ class SearchDateFilter {
|
|||
|
||||
factory SearchDateFilter.fromJson(String source) =>
|
||||
SearchDateFilter.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() => 'SearchDateFilter(takenBefore: $takenBefore, takenAfter: $takenAfter)';
|
||||
|
||||
@override
|
||||
bool operator ==(covariant SearchDateFilter other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.takenBefore == takenBefore && other.takenAfter == takenAfter;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => takenBefore.hashCode ^ takenAfter.hashCode;
|
||||
}
|
||||
|
||||
class SearchRatingFilter {
|
||||
/// none = no filter; some(null) = filter for unrated; some(1-5) = filter for that rating
|
||||
Option<int?> rating;
|
||||
SearchRatingFilter({this.rating = const Option.none()});
|
||||
@Freezed(fromJson: false, toJson: false)
|
||||
abstract class SearchRatingFilter with _$SearchRatingFilter {
|
||||
const SearchRatingFilter._();
|
||||
|
||||
SearchRatingFilter copyWith({Option<int?>? rating}) {
|
||||
return SearchRatingFilter(rating: rating ?? this.rating);
|
||||
}
|
||||
/// [rating]: none = no filter; some(null) = filter for unrated; some(1-5) = filter for that rating
|
||||
// TODO(agg23): Switch to enum
|
||||
const factory SearchRatingFilter({@Default(Option.none()) Option<int?> rating}) = _SearchRatingFilter;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
if (rating.isNone) {
|
||||
|
|
@ -153,7 +97,7 @@ class SearchRatingFilter {
|
|||
|
||||
factory SearchRatingFilter.fromMap(Map<String, dynamic> map) {
|
||||
if (!(map['active'] as bool? ?? false)) {
|
||||
return SearchRatingFilter();
|
||||
return const SearchRatingFilter();
|
||||
}
|
||||
return SearchRatingFilter(rating: Option.some(map['value'] as int?));
|
||||
}
|
||||
|
|
@ -162,21 +106,6 @@ class SearchRatingFilter {
|
|||
|
||||
factory SearchRatingFilter.fromJson(String source) =>
|
||||
SearchRatingFilter.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() => 'SearchRatingFilter(rating: $rating)';
|
||||
|
||||
@override
|
||||
bool operator ==(covariant SearchRatingFilter other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.rating == rating;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => rating.hashCode;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
|
@ -185,40 +114,26 @@ abstract class SearchDisplayFilters with _$SearchDisplayFilters {
|
|||
_SearchDisplayFilters;
|
||||
}
|
||||
|
||||
class SearchFilter {
|
||||
String? context;
|
||||
String? filename;
|
||||
String? description;
|
||||
String? ocr;
|
||||
String? language;
|
||||
String? assetId;
|
||||
List<String>? tagIds;
|
||||
Set<Person> people;
|
||||
SearchLocationFilter location;
|
||||
SearchCameraFilter camera;
|
||||
SearchDateFilter date;
|
||||
SearchRatingFilter rating;
|
||||
SearchDisplayFilters display;
|
||||
@freezed
|
||||
abstract class SearchFilter with _$SearchFilter {
|
||||
const SearchFilter._();
|
||||
|
||||
// Enum
|
||||
AssetType mediaType;
|
||||
|
||||
SearchFilter({
|
||||
this.context,
|
||||
this.filename,
|
||||
this.description,
|
||||
this.ocr,
|
||||
this.language,
|
||||
this.assetId,
|
||||
this.tagIds,
|
||||
required this.people,
|
||||
required this.location,
|
||||
required this.camera,
|
||||
required this.date,
|
||||
required this.display,
|
||||
required this.rating,
|
||||
required this.mediaType,
|
||||
});
|
||||
const factory SearchFilter({
|
||||
String? context,
|
||||
String? filename,
|
||||
String? description,
|
||||
String? ocr,
|
||||
String? language,
|
||||
String? assetId,
|
||||
List<String>? tagIds,
|
||||
required Set<Person> people,
|
||||
required SearchLocationFilter location,
|
||||
required SearchCameraFilter camera,
|
||||
required SearchDateFilter date,
|
||||
required SearchRatingFilter rating,
|
||||
required SearchDisplayFilters display,
|
||||
required AssetType mediaType,
|
||||
}) = _SearchFilter;
|
||||
|
||||
bool get isEmpty {
|
||||
return (context == null || (context != null && context!.isEmpty)) &&
|
||||
|
|
@ -241,83 +156,4 @@ class SearchFilter {
|
|||
rating.rating.isNone &&
|
||||
mediaType == AssetType.other;
|
||||
}
|
||||
|
||||
SearchFilter copyWith({
|
||||
String? context,
|
||||
String? filename,
|
||||
String? description,
|
||||
String? language,
|
||||
String? ocr,
|
||||
String? assetId,
|
||||
Set<Person>? people,
|
||||
List<String>? tagIds,
|
||||
SearchLocationFilter? location,
|
||||
SearchCameraFilter? camera,
|
||||
SearchDateFilter? date,
|
||||
SearchDisplayFilters? display,
|
||||
SearchRatingFilter? rating,
|
||||
AssetType? mediaType,
|
||||
}) {
|
||||
return SearchFilter(
|
||||
context: context ?? this.context,
|
||||
filename: filename ?? this.filename,
|
||||
description: description ?? this.description,
|
||||
language: language ?? this.language,
|
||||
ocr: ocr ?? this.ocr,
|
||||
assetId: assetId ?? this.assetId,
|
||||
people: people ?? this.people,
|
||||
location: location ?? this.location,
|
||||
camera: camera ?? this.camera,
|
||||
date: date ?? this.date,
|
||||
display: display ?? this.display,
|
||||
rating: rating ?? this.rating,
|
||||
mediaType: mediaType ?? this.mediaType,
|
||||
tagIds: tagIds ?? this.tagIds,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SearchFilter(context: $context, filename: $filename, description: $description, language: $language, ocr: $ocr, people: $people, location: $location, tagIds: $tagIds, camera: $camera, date: $date, display: $display, rating: $rating, mediaType: $mediaType, assetId: $assetId)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant SearchFilter other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.context == context &&
|
||||
other.filename == filename &&
|
||||
other.description == description &&
|
||||
other.language == language &&
|
||||
other.ocr == ocr &&
|
||||
other.assetId == assetId &&
|
||||
other.people == people &&
|
||||
other.tagIds == tagIds &&
|
||||
other.location == location &&
|
||||
other.camera == camera &&
|
||||
other.date == date &&
|
||||
other.display == display &&
|
||||
other.rating == rating &&
|
||||
other.mediaType == mediaType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return context.hashCode ^
|
||||
filename.hashCode ^
|
||||
description.hashCode ^
|
||||
language.hashCode ^
|
||||
ocr.hashCode ^
|
||||
assetId.hashCode ^
|
||||
people.hashCode ^
|
||||
tagIds.hashCode ^
|
||||
location.hashCode ^
|
||||
camera.hashCode ^
|
||||
date.hashCode ^
|
||||
display.hashCode ^
|
||||
rating.hashCode ^
|
||||
mediaType.hashCode;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,23 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
class ServerConfig {
|
||||
final int trashDays;
|
||||
final String oauthButtonText;
|
||||
final String externalDomain;
|
||||
final String mapDarkStyleUrl;
|
||||
final String mapLightStyleUrl;
|
||||
part 'server_config.model.freezed.dart';
|
||||
|
||||
const ServerConfig({
|
||||
required this.trashDays,
|
||||
required this.oauthButtonText,
|
||||
required this.externalDomain,
|
||||
required this.mapDarkStyleUrl,
|
||||
required this.mapLightStyleUrl,
|
||||
});
|
||||
@freezed
|
||||
abstract class ServerConfig with _$ServerConfig {
|
||||
const factory ServerConfig({
|
||||
required int trashDays,
|
||||
required String oauthButtonText,
|
||||
required String externalDomain,
|
||||
required String mapDarkStyleUrl,
|
||||
required String mapLightStyleUrl,
|
||||
}) = _ServerConfig;
|
||||
|
||||
ServerConfig copyWith({int? trashDays, String? oauthButtonText, String? externalDomain}) {
|
||||
return ServerConfig(
|
||||
trashDays: trashDays ?? this.trashDays,
|
||||
oauthButtonText: oauthButtonText ?? this.oauthButtonText,
|
||||
externalDomain: externalDomain ?? this.externalDomain,
|
||||
mapDarkStyleUrl: mapDarkStyleUrl,
|
||||
mapLightStyleUrl: mapLightStyleUrl,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'ServerConfig(trashDays: $trashDays, oauthButtonText: $oauthButtonText, externalDomain: $externalDomain)';
|
||||
|
||||
ServerConfig.fromDto(ServerConfigDto dto)
|
||||
: trashDays = dto.trashDays,
|
||||
oauthButtonText = dto.oauthButtonText,
|
||||
externalDomain = dto.externalDomain,
|
||||
mapDarkStyleUrl = dto.mapDarkStyleUrl,
|
||||
mapLightStyleUrl = dto.mapLightStyleUrl;
|
||||
|
||||
@override
|
||||
bool operator ==(covariant ServerConfig other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.trashDays == trashDays &&
|
||||
other.oauthButtonText == oauthButtonText &&
|
||||
other.externalDomain == externalDomain;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => trashDays.hashCode ^ oauthButtonText.hashCode ^ externalDomain.hashCode;
|
||||
factory ServerConfig.fromDto(ServerConfigDto dto) => ServerConfig(
|
||||
trashDays: dto.trashDays,
|
||||
oauthButtonText: dto.oauthButtonText,
|
||||
externalDomain: dto.externalDomain,
|
||||
mapDarkStyleUrl: dto.mapDarkStyleUrl,
|
||||
mapLightStyleUrl: dto.mapLightStyleUrl,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,27 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/utils/bytes_units.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
part 'share_intent_attachment.model.freezed.dart';
|
||||
|
||||
enum ShareIntentAttachmentType { image, video }
|
||||
|
||||
enum UploadStatus { enqueued, running, complete, failed }
|
||||
|
||||
class ShareIntentAttachment {
|
||||
final String path;
|
||||
@Freezed(fromJson: false, toJson: false, equal: false)
|
||||
abstract class ShareIntentAttachment with _$ShareIntentAttachment {
|
||||
const ShareIntentAttachment._();
|
||||
|
||||
// enum
|
||||
final ShareIntentAttachmentType type;
|
||||
|
||||
// enum
|
||||
final UploadStatus status;
|
||||
|
||||
final double uploadProgress;
|
||||
|
||||
final int fileLength;
|
||||
|
||||
ShareIntentAttachment({
|
||||
required this.path,
|
||||
required this.type,
|
||||
required this.status,
|
||||
this.uploadProgress = 0,
|
||||
this.fileLength = 0,
|
||||
});
|
||||
const factory ShareIntentAttachment({
|
||||
required String path,
|
||||
required ShareIntentAttachmentType type,
|
||||
required UploadStatus status,
|
||||
@Default(0.0) double uploadProgress,
|
||||
@Default(0) int fileLength,
|
||||
}) = _ShareIntentAttachment;
|
||||
|
||||
int get id => hash(path);
|
||||
|
||||
|
|
@ -39,23 +33,7 @@ class ShareIntentAttachment {
|
|||
|
||||
bool get isVideo => type == ShareIntentAttachmentType.video;
|
||||
|
||||
String? _fileSize;
|
||||
|
||||
String get fileSize => _fileSize ??= formatHumanReadableBytes(fileLength, 2);
|
||||
|
||||
ShareIntentAttachment copyWith({
|
||||
String? path,
|
||||
ShareIntentAttachmentType? type,
|
||||
UploadStatus? status,
|
||||
double? uploadProgress,
|
||||
}) {
|
||||
return ShareIntentAttachment(
|
||||
path: path ?? this.path,
|
||||
type: type ?? this.type,
|
||||
status: status ?? this.status,
|
||||
uploadProgress: uploadProgress ?? this.uploadProgress,
|
||||
);
|
||||
}
|
||||
String get fileSize => formatHumanReadableBytes(fileLength, 2);
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
|
|
@ -80,18 +58,14 @@ class ShareIntentAttachment {
|
|||
factory ShareIntentAttachment.fromJson(String source) =>
|
||||
ShareIntentAttachment.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
// Identity is sourced from the backing file, not from upload progress
|
||||
@override
|
||||
String toString() {
|
||||
return 'ShareIntentAttachment(path: $path, type: $type, status: $status, uploadProgress: $uploadProgress)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant ShareIntentAttachment other) {
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other.path == path && other.type == type;
|
||||
return other is ShareIntentAttachment && other.path == path && other.type == type;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ class SimilarPhotosAction extends ActionBuilder {
|
|||
.new(
|
||||
assetId: assetId,
|
||||
people: {},
|
||||
location: .new(),
|
||||
camera: .new(),
|
||||
date: .new(),
|
||||
location: const .new(),
|
||||
camera: const .new(),
|
||||
date: const .new(),
|
||||
display: const .new(isNotInAlbum: false, isArchive: false, isFavorite: false),
|
||||
rating: .new(),
|
||||
rating: const .new(),
|
||||
mediaType: .other,
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ class DriftSearchPage extends HookConsumerWidget {
|
|||
final filter = useState<SearchFilter>(
|
||||
SearchFilter(
|
||||
people: {},
|
||||
location: SearchLocationFilter(),
|
||||
camera: SearchCameraFilter(),
|
||||
date: SearchDateFilter(),
|
||||
location: const SearchLocationFilter(),
|
||||
camera: const SearchCameraFilter(),
|
||||
date: const SearchDateFilter(),
|
||||
display: const SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false),
|
||||
rating: SearchRatingFilter(),
|
||||
rating: const SearchRatingFilter(),
|
||||
mediaType: AssetType.other,
|
||||
language: "${context.locale.languageCode}-${context.locale.countryCode}",
|
||||
tagIds: [],
|
||||
|
|
@ -208,7 +208,7 @@ class DriftSearchPage extends HookConsumerWidget {
|
|||
|
||||
void handleClear() {
|
||||
locationCurrentFilterWidget.value = null;
|
||||
search(filter.value.copyWith(location: SearchLocationFilter()));
|
||||
search(filter.value.copyWith(location: const SearchLocationFilter()));
|
||||
}
|
||||
|
||||
void handleApply() {
|
||||
|
|
@ -256,7 +256,7 @@ class DriftSearchPage extends HookConsumerWidget {
|
|||
|
||||
void handleClear() {
|
||||
cameraCurrentFilterWidget.value = null;
|
||||
search(filter.value.copyWith(camera: SearchCameraFilter()));
|
||||
search(filter.value.copyWith(camera: const SearchCameraFilter()));
|
||||
}
|
||||
|
||||
void handleApply() {
|
||||
|
|
@ -290,7 +290,7 @@ class DriftSearchPage extends HookConsumerWidget {
|
|||
dateInputFilter.value = selectedDate;
|
||||
if (selectedDate == null) {
|
||||
dateRangeCurrentFilterWidget.value = null;
|
||||
search(filter.value.copyWith(date: SearchDateFilter()));
|
||||
search(filter.value.copyWith(date: const SearchDateFilter()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -419,7 +419,7 @@ class DriftSearchPage extends HookConsumerWidget {
|
|||
|
||||
void handleClear() {
|
||||
ratingCurrentFilterWidget.value = null;
|
||||
search(filter.value.copyWith(rating: SearchRatingFilter()));
|
||||
search(filter.value.copyWith(rating: const SearchRatingFilter()));
|
||||
}
|
||||
|
||||
void handleApply() {
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ class _AlbumSelectorState extends ConsumerState<AlbumSelector> {
|
|||
List<RemoteAlbum> sortedAlbums = [];
|
||||
List<RemoteAlbum> shownAlbums = [];
|
||||
|
||||
AlbumFilter filter = AlbumFilter(query: "", mode: QuickFilterMode.all);
|
||||
AlbumSort sort = AlbumSort(mode: AlbumSortMode.lastModified, isReverse: true);
|
||||
AlbumFilter filter = const AlbumFilter(query: "", mode: QuickFilterMode.all);
|
||||
AlbumSort sort = const AlbumSort(mode: AlbumSortMode.lastModified, isReverse: true);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||
import 'package:immich_mobile/domain/models/time_range.model.dart';
|
||||
|
|
@ -12,25 +13,23 @@ import 'package:immich_mobile/providers/map/map_state.provider.dart';
|
|||
import 'package:immich_mobile/utils/option.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
|
||||
class MapState {
|
||||
final ThemeMode themeMode;
|
||||
final LatLngBounds bounds;
|
||||
final bool onlyFavorites;
|
||||
final bool includeArchived;
|
||||
final bool withPartners;
|
||||
final int relativeDays;
|
||||
final TimeRange timeRange;
|
||||
part 'map.state.freezed.dart';
|
||||
|
||||
const MapState({
|
||||
this.themeMode = ThemeMode.system,
|
||||
required this.bounds,
|
||||
this.onlyFavorites = false,
|
||||
this.includeArchived = false,
|
||||
this.withPartners = false,
|
||||
this.relativeDays = 0,
|
||||
this.timeRange = const TimeRange(),
|
||||
});
|
||||
@Freezed(equal: false)
|
||||
abstract class MapState with _$MapState {
|
||||
const MapState._();
|
||||
|
||||
const factory MapState({
|
||||
@Default(ThemeMode.system) ThemeMode themeMode,
|
||||
required LatLngBounds bounds,
|
||||
@Default(false) bool onlyFavorites,
|
||||
@Default(false) bool includeArchived,
|
||||
@Default(false) bool withPartners,
|
||||
@Default(0) int relativeDays,
|
||||
@Default(TimeRange()) TimeRange timeRange,
|
||||
}) = _MapState;
|
||||
|
||||
// We only care about bounds changes, overriding Freezed
|
||||
@override
|
||||
bool operator ==(covariant MapState other) {
|
||||
return bounds == other.bounds;
|
||||
|
|
@ -39,26 +38,6 @@ class MapState {
|
|||
@override
|
||||
int get hashCode => bounds.hashCode;
|
||||
|
||||
MapState copyWith({
|
||||
LatLngBounds? bounds,
|
||||
ThemeMode? themeMode,
|
||||
bool? onlyFavorites,
|
||||
bool? includeArchived,
|
||||
bool? withPartners,
|
||||
int? relativeDays,
|
||||
TimeRange? timeRange,
|
||||
}) {
|
||||
return MapState(
|
||||
bounds: bounds ?? this.bounds,
|
||||
themeMode: themeMode ?? this.themeMode,
|
||||
onlyFavorites: onlyFavorites ?? this.onlyFavorites,
|
||||
includeArchived: includeArchived ?? this.includeArchived,
|
||||
withPartners: withPartners ?? this.withPartners,
|
||||
relativeDays: relativeDays ?? this.relativeDays,
|
||||
timeRange: timeRange ?? this.timeRange,
|
||||
);
|
||||
}
|
||||
|
||||
TimelineMapOptions toOptions() => TimelineMapOptions(
|
||||
bounds: bounds,
|
||||
onlyFavorites: onlyFavorites,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/constants.dart';
|
||||
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||
|
|
@ -14,6 +15,8 @@ import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
|||
import 'package:immich_mobile/utils/debounce.dart';
|
||||
import 'package:intl/intl.dart' hide TextDirection;
|
||||
|
||||
part 'scrubber.widget.freezed.dart';
|
||||
|
||||
/// A widget that will display a BoxScrollView with a ScrollThumb that can be dragged
|
||||
/// for quick navigation of the BoxScrollView.
|
||||
class Scrubber extends ConsumerStatefulWidget {
|
||||
|
|
@ -596,25 +599,12 @@ class _SlideFadeTransition extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class _Segment {
|
||||
final DateTime date;
|
||||
final double startOffset;
|
||||
final String scrollLabel;
|
||||
final bool showSegment;
|
||||
|
||||
const _Segment({required this.date, required this.startOffset, required this.scrollLabel, this.showSegment = false});
|
||||
|
||||
_Segment copyWith({DateTime? date, double? startOffset, String? scrollLabel, bool? showSegment}) {
|
||||
return _Segment(
|
||||
date: date ?? this.date,
|
||||
startOffset: startOffset ?? this.startOffset,
|
||||
scrollLabel: scrollLabel ?? this.scrollLabel,
|
||||
showSegment: showSegment ?? this.showSegment,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Segment(scrollLabel: $scrollLabel, date: $date)';
|
||||
}
|
||||
@freezed
|
||||
abstract class _Segment with _$Segment {
|
||||
const factory _Segment({
|
||||
required DateTime date,
|
||||
required double startOffset,
|
||||
required String scrollLabel,
|
||||
@Default(false) bool showSegment,
|
||||
}) = __Segment;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
|
||||
class PendingAlbumUpload {
|
||||
final LocalAsset asset;
|
||||
final double progress;
|
||||
final bool failed;
|
||||
part 'pending_album_uploads.provider.freezed.dart';
|
||||
|
||||
const PendingAlbumUpload({required this.asset, this.progress = 0.0, this.failed = false});
|
||||
|
||||
PendingAlbumUpload copyWith({double? progress, bool? failed}) =>
|
||||
PendingAlbumUpload(asset: asset, progress: progress ?? this.progress, failed: failed ?? this.failed);
|
||||
@freezed
|
||||
abstract class PendingAlbumUpload with _$PendingAlbumUpload {
|
||||
const factory PendingAlbumUpload({
|
||||
required LocalAsset asset,
|
||||
@Default(0.0) double progress,
|
||||
@Default(false) bool failed,
|
||||
}) = _PendingAlbumUpload;
|
||||
}
|
||||
|
||||
class AlbumPendingUploadsNotifier extends AutoDisposeFamilyNotifier<List<PendingAlbumUpload>, String> {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,22 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:native_video_player/native_video_player.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
|
||||
part 'video_player_provider.freezed.dart';
|
||||
|
||||
enum VideoPlaybackStatus { paused, playing, buffering, completed }
|
||||
|
||||
class VideoPlayerState {
|
||||
final Duration position;
|
||||
final Duration duration;
|
||||
final VideoPlaybackStatus status;
|
||||
|
||||
const VideoPlayerState({required this.position, required this.duration, required this.status});
|
||||
|
||||
VideoPlayerState copyWith({Duration? position, Duration? duration, VideoPlaybackStatus? status}) {
|
||||
return VideoPlayerState(
|
||||
position: position ?? this.position,
|
||||
duration: duration ?? this.duration,
|
||||
status: status ?? this.status,
|
||||
);
|
||||
}
|
||||
@freezed
|
||||
abstract class VideoPlayerState with _$VideoPlayerState {
|
||||
const factory VideoPlayerState({
|
||||
required Duration position,
|
||||
required Duration duration,
|
||||
required VideoPlaybackStatus status,
|
||||
}) = _VideoPlayerState;
|
||||
}
|
||||
|
||||
const _defaultState = VideoPlayerState(
|
||||
|
|
@ -221,7 +217,7 @@ class VideoPlayerNotifier extends StateNotifier<VideoPlayerState> {
|
|||
|
||||
state = state.copyWith(
|
||||
position: position,
|
||||
status: state.status == VideoPlaybackStatus.buffering ? VideoPlaybackStatus.playing : null,
|
||||
status: state.status == VideoPlaybackStatus.buffering ? VideoPlaybackStatus.playing : state.status,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,18 +15,9 @@ import 'package:logging/logging.dart';
|
|||
|
||||
part 'drift_backup.provider.freezed.dart';
|
||||
|
||||
class EnqueueStatus {
|
||||
final int enqueueCount;
|
||||
final int totalCount;
|
||||
|
||||
const EnqueueStatus({required this.enqueueCount, required this.totalCount});
|
||||
|
||||
EnqueueStatus copyWith({int? enqueueCount, int? totalCount}) {
|
||||
return EnqueueStatus(enqueueCount: enqueueCount ?? this.enqueueCount, totalCount: totalCount ?? this.totalCount);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'EnqueueStatus(enqueueCount: $enqueueCount, totalCount: $totalCount)';
|
||||
@freezed
|
||||
abstract class EnqueueStatus with _$EnqueueStatus {
|
||||
const factory EnqueueStatus({required int enqueueCount, required int totalCount}) = _EnqueueStatus;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
|
|
@ -8,48 +9,20 @@ import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
|
|||
import 'package:immich_mobile/providers/user.provider.dart';
|
||||
import 'package:immich_mobile/services/cleanup.service.dart';
|
||||
|
||||
class CleanupState {
|
||||
final DateTime? selectedDate;
|
||||
final List<LocalAsset> assetsToDelete;
|
||||
final int totalBytes;
|
||||
final bool isScanning;
|
||||
final bool isDeleting;
|
||||
final AssetKeepType keepMediaType;
|
||||
final bool keepFavorites;
|
||||
final Set<String> keepAlbumIds;
|
||||
part 'cleanup.provider.freezed.dart';
|
||||
|
||||
const CleanupState({
|
||||
this.selectedDate,
|
||||
this.assetsToDelete = const [],
|
||||
this.totalBytes = 0,
|
||||
this.isScanning = false,
|
||||
this.isDeleting = false,
|
||||
this.keepMediaType = AssetKeepType.none,
|
||||
this.keepFavorites = true,
|
||||
this.keepAlbumIds = const {},
|
||||
});
|
||||
|
||||
CleanupState copyWith({
|
||||
@freezed
|
||||
abstract class CleanupState with _$CleanupState {
|
||||
const factory CleanupState({
|
||||
DateTime? selectedDate,
|
||||
List<LocalAsset>? assetsToDelete,
|
||||
int? totalBytes,
|
||||
bool? isScanning,
|
||||
bool? isDeleting,
|
||||
AssetKeepType? keepMediaType,
|
||||
bool? keepFavorites,
|
||||
Set<String>? keepAlbumIds,
|
||||
}) {
|
||||
return CleanupState(
|
||||
selectedDate: selectedDate ?? this.selectedDate,
|
||||
assetsToDelete: assetsToDelete ?? this.assetsToDelete,
|
||||
totalBytes: totalBytes ?? this.totalBytes,
|
||||
isScanning: isScanning ?? this.isScanning,
|
||||
isDeleting: isDeleting ?? this.isDeleting,
|
||||
keepMediaType: keepMediaType ?? this.keepMediaType,
|
||||
keepFavorites: keepFavorites ?? this.keepFavorites,
|
||||
keepAlbumIds: keepAlbumIds ?? this.keepAlbumIds,
|
||||
);
|
||||
}
|
||||
@Default([]) List<LocalAsset> assetsToDelete,
|
||||
@Default(0) int totalBytes,
|
||||
@Default(false) bool isScanning,
|
||||
@Default(false) bool isDeleting,
|
||||
@Default(AssetKeepType.none) AssetKeepType keepMediaType,
|
||||
@Default(true) bool keepFavorites,
|
||||
@Default({}) Set<String> keepAlbumIds,
|
||||
}) = _CleanupState;
|
||||
}
|
||||
|
||||
final cleanupProvider = StateNotifierProvider<CleanupNotifier, CleanupState>((ref) {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,15 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/models/albums/album_search.model.dart';
|
||||
import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart';
|
||||
|
||||
class AlbumFilter {
|
||||
String? userId;
|
||||
String? query;
|
||||
QuickFilterMode mode;
|
||||
part 'album_filter.utils.freezed.dart';
|
||||
|
||||
AlbumFilter({required this.mode, this.userId, this.query});
|
||||
|
||||
AlbumFilter copyWith({String? userId, String? query, QuickFilterMode? mode}) {
|
||||
return AlbumFilter(userId: userId ?? this.userId, query: query ?? this.query, mode: mode ?? this.mode);
|
||||
}
|
||||
@freezed
|
||||
abstract class AlbumFilter with _$AlbumFilter {
|
||||
const factory AlbumFilter({required QuickFilterMode mode, String? userId, String? query}) = _AlbumFilter;
|
||||
}
|
||||
|
||||
class AlbumSort {
|
||||
AlbumSortMode mode;
|
||||
bool isReverse;
|
||||
|
||||
AlbumSort({required this.mode, this.isReverse = false});
|
||||
|
||||
AlbumSort copyWith({AlbumSortMode? mode, bool? isReverse}) {
|
||||
return AlbumSort(mode: mode ?? this.mode, isReverse: isReverse ?? this.isReverse);
|
||||
}
|
||||
@freezed
|
||||
abstract class AlbumSort with _$AlbumSort {
|
||||
const factory AlbumSort({required AlbumSortMode mode, @Default(false) bool isReverse}) = _AlbumSort;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/duration_extensions.dart';
|
||||
import 'package:immich_mobile/generated/translations.g.dart';
|
||||
|
|
@ -9,6 +10,8 @@ import 'package:intl/intl.dart';
|
|||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/timezone.dart';
|
||||
|
||||
part 'date_time_picker.freezed.dart';
|
||||
|
||||
Future<String?> showDateTimePicker({
|
||||
required BuildContext context,
|
||||
DateTime? initialDateTime,
|
||||
|
|
@ -165,39 +168,19 @@ class _DateTimePicker extends HookWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class _TimeZoneOffset implements Comparable<_TimeZoneOffset> {
|
||||
final String display;
|
||||
final Location location;
|
||||
@freezed
|
||||
abstract class _TimeZoneOffset with _$TimeZoneOffset implements Comparable<_TimeZoneOffset> {
|
||||
const _TimeZoneOffset._();
|
||||
|
||||
const _TimeZoneOffset({required this.display, required this.location});
|
||||
const factory _TimeZoneOffset({required String display, required Location location}) = __TimeZoneOffset;
|
||||
|
||||
_TimeZoneOffset copyWith({String? display, Location? location}) {
|
||||
return _TimeZoneOffset(display: display ?? this.display, location: location ?? this.location);
|
||||
}
|
||||
factory _TimeZoneOffset.fromLocation(tz.Location l) =>
|
||||
_TimeZoneOffset(display: _getFormattedOffset(l.currentTimeZone.offset, l), location: l);
|
||||
|
||||
int get offsetInMilliseconds => location.currentTimeZone.offset;
|
||||
|
||||
_TimeZoneOffset.fromLocation(tz.Location l)
|
||||
: display = _getFormattedOffset(l.currentTimeZone.offset, l),
|
||||
location = l;
|
||||
|
||||
@override
|
||||
int compareTo(_TimeZoneOffset other) {
|
||||
return offsetInMilliseconds.compareTo(other.offsetInMilliseconds);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => '_TimeZoneOffset(display: $display, location: $location)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other is _TimeZoneOffset && other.display == display && other.offsetInMilliseconds == offsetInMilliseconds;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => display.hashCode ^ offsetInMilliseconds.hashCode ^ location.hashCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ void main() {
|
|||
fakeAsync((async) {
|
||||
final image = _task(
|
||||
'live-image',
|
||||
metaData: LivePhotosMetadata(part: LivePhotosPart.image, id: 'live-1').toJson(),
|
||||
metaData: const LivePhotosMetadata(part: LivePhotosPart.image, id: 'live-1').toJson(),
|
||||
);
|
||||
final video = _task(
|
||||
'live-video',
|
||||
filename: 'photo.MOV',
|
||||
metaData: LivePhotosMetadata(part: LivePhotosPart.video, id: 'live-1').toJson(),
|
||||
metaData: const LivePhotosMetadata(part: LivePhotosPart.video, id: 'live-1').toJson(),
|
||||
);
|
||||
onProgress(TaskProgressUpdate(image, 0.9));
|
||||
onProgress(TaskProgressUpdate(video, 0.9));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue