refactor(server,web): time buckets for main timeline, archived, and favorites (1) (#3537)

* refactor: time buckets

* feat(web): use new time bucket api

* feat(web): use asset grid in archive/favorites

* chore: open api

* chore: clean up uuid validation

* refactor(web): move memory lane to photos page

* Update web/src/routes/(user)/archive/+page.svelte

Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com>

* fix: hide archived photos on main timeline

* fix: select exif info

---------

Co-authored-by: Sergey Kondrikov <sergey.kondrikov@gmail.com>
This commit is contained in:
Jason Rasmussen
2023-08-04 17:07:15 -04:00
committed by GitHub
parent e5bdf671b5
commit c6abef186c
51 changed files with 1516 additions and 1862 deletions

View File

@@ -1,106 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class AssetCountByTimeBucketResponseDto {
/// Returns a new [AssetCountByTimeBucketResponseDto] instance.
AssetCountByTimeBucketResponseDto({
this.buckets = const [],
required this.totalCount,
});
List<AssetCountByTimeBucket> buckets;
int totalCount;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetCountByTimeBucketResponseDto &&
other.buckets == buckets &&
other.totalCount == totalCount;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(buckets.hashCode) +
(totalCount.hashCode);
@override
String toString() => 'AssetCountByTimeBucketResponseDto[buckets=$buckets, totalCount=$totalCount]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'buckets'] = this.buckets;
json[r'totalCount'] = this.totalCount;
return json;
}
/// Returns a new [AssetCountByTimeBucketResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static AssetCountByTimeBucketResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return AssetCountByTimeBucketResponseDto(
buckets: AssetCountByTimeBucket.listFromJson(json[r'buckets']),
totalCount: mapValueOfType<int>(json, r'totalCount')!,
);
}
return null;
}
static List<AssetCountByTimeBucketResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetCountByTimeBucketResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetCountByTimeBucketResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, AssetCountByTimeBucketResponseDto> mapFromJson(dynamic json) {
final map = <String, AssetCountByTimeBucketResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AssetCountByTimeBucketResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of AssetCountByTimeBucketResponseDto-objects as value to a dart map
static Map<String, List<AssetCountByTimeBucketResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetCountByTimeBucketResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = AssetCountByTimeBucketResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'buckets',
'totalCount',
};
}

View File

@@ -1,135 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class GetAssetByTimeBucketDto {
/// Returns a new [GetAssetByTimeBucketDto] instance.
GetAssetByTimeBucketDto({
this.timeBucket = const [],
this.userId,
this.withoutThumbs,
});
List<String> timeBucket;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? userId;
/// Include assets without thumbnails
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? withoutThumbs;
@override
bool operator ==(Object other) => identical(this, other) || other is GetAssetByTimeBucketDto &&
other.timeBucket == timeBucket &&
other.userId == userId &&
other.withoutThumbs == withoutThumbs;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(timeBucket.hashCode) +
(userId == null ? 0 : userId!.hashCode) +
(withoutThumbs == null ? 0 : withoutThumbs!.hashCode);
@override
String toString() => 'GetAssetByTimeBucketDto[timeBucket=$timeBucket, userId=$userId, withoutThumbs=$withoutThumbs]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'timeBucket'] = this.timeBucket;
if (this.userId != null) {
json[r'userId'] = this.userId;
} else {
// json[r'userId'] = null;
}
if (this.withoutThumbs != null) {
json[r'withoutThumbs'] = this.withoutThumbs;
} else {
// json[r'withoutThumbs'] = null;
}
return json;
}
/// Returns a new [GetAssetByTimeBucketDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static GetAssetByTimeBucketDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return GetAssetByTimeBucketDto(
timeBucket: json[r'timeBucket'] is Iterable
? (json[r'timeBucket'] as Iterable).cast<String>().toList(growable: false)
: const [],
userId: mapValueOfType<String>(json, r'userId'),
withoutThumbs: mapValueOfType<bool>(json, r'withoutThumbs'),
);
}
return null;
}
static List<GetAssetByTimeBucketDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <GetAssetByTimeBucketDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = GetAssetByTimeBucketDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, GetAssetByTimeBucketDto> mapFromJson(dynamic json) {
final map = <String, GetAssetByTimeBucketDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = GetAssetByTimeBucketDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of GetAssetByTimeBucketDto-objects as value to a dart map
static Map<String, List<GetAssetByTimeBucketDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<GetAssetByTimeBucketDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = GetAssetByTimeBucketDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'timeBucket',
};
}

View File

@@ -1,133 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class GetAssetCountByTimeBucketDto {
/// Returns a new [GetAssetCountByTimeBucketDto] instance.
GetAssetCountByTimeBucketDto({
required this.timeGroup,
this.userId,
this.withoutThumbs,
});
TimeGroupEnum timeGroup;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? userId;
/// Include assets without thumbnails
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? withoutThumbs;
@override
bool operator ==(Object other) => identical(this, other) || other is GetAssetCountByTimeBucketDto &&
other.timeGroup == timeGroup &&
other.userId == userId &&
other.withoutThumbs == withoutThumbs;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(timeGroup.hashCode) +
(userId == null ? 0 : userId!.hashCode) +
(withoutThumbs == null ? 0 : withoutThumbs!.hashCode);
@override
String toString() => 'GetAssetCountByTimeBucketDto[timeGroup=$timeGroup, userId=$userId, withoutThumbs=$withoutThumbs]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'timeGroup'] = this.timeGroup;
if (this.userId != null) {
json[r'userId'] = this.userId;
} else {
// json[r'userId'] = null;
}
if (this.withoutThumbs != null) {
json[r'withoutThumbs'] = this.withoutThumbs;
} else {
// json[r'withoutThumbs'] = null;
}
return json;
}
/// Returns a new [GetAssetCountByTimeBucketDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static GetAssetCountByTimeBucketDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return GetAssetCountByTimeBucketDto(
timeGroup: TimeGroupEnum.fromJson(json[r'timeGroup'])!,
userId: mapValueOfType<String>(json, r'userId'),
withoutThumbs: mapValueOfType<bool>(json, r'withoutThumbs'),
);
}
return null;
}
static List<GetAssetCountByTimeBucketDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <GetAssetCountByTimeBucketDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = GetAssetCountByTimeBucketDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, GetAssetCountByTimeBucketDto> mapFromJson(dynamic json) {
final map = <String, GetAssetCountByTimeBucketDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = GetAssetCountByTimeBucketDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of GetAssetCountByTimeBucketDto-objects as value to a dart map
static Map<String, List<GetAssetCountByTimeBucketDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<GetAssetCountByTimeBucketDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = GetAssetCountByTimeBucketDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'timeGroup',
};
}

View File

@@ -10,9 +10,9 @@
part of openapi.api;
class AssetCountByTimeBucket {
/// Returns a new [AssetCountByTimeBucket] instance.
AssetCountByTimeBucket({
class TimeBucketResponseDto {
/// Returns a new [TimeBucketResponseDto] instance.
TimeBucketResponseDto({
required this.count,
required this.timeBucket,
});
@@ -22,7 +22,7 @@ class AssetCountByTimeBucket {
String timeBucket;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetCountByTimeBucket &&
bool operator ==(Object other) => identical(this, other) || other is TimeBucketResponseDto &&
other.count == count &&
other.timeBucket == timeBucket;
@@ -33,7 +33,7 @@ class AssetCountByTimeBucket {
(timeBucket.hashCode);
@override
String toString() => 'AssetCountByTimeBucket[count=$count, timeBucket=$timeBucket]';
String toString() => 'TimeBucketResponseDto[count=$count, timeBucket=$timeBucket]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -42,14 +42,14 @@ class AssetCountByTimeBucket {
return json;
}
/// Returns a new [AssetCountByTimeBucket] instance and imports its values from
/// Returns a new [TimeBucketResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static AssetCountByTimeBucket? fromJson(dynamic value) {
static TimeBucketResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return AssetCountByTimeBucket(
return TimeBucketResponseDto(
count: mapValueOfType<int>(json, r'count')!,
timeBucket: mapValueOfType<String>(json, r'timeBucket')!,
);
@@ -57,11 +57,11 @@ class AssetCountByTimeBucket {
return null;
}
static List<AssetCountByTimeBucket> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetCountByTimeBucket>[];
static List<TimeBucketResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <TimeBucketResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetCountByTimeBucket.fromJson(row);
final value = TimeBucketResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
@@ -70,12 +70,12 @@ class AssetCountByTimeBucket {
return result.toList(growable: growable);
}
static Map<String, AssetCountByTimeBucket> mapFromJson(dynamic json) {
final map = <String, AssetCountByTimeBucket>{};
static Map<String, TimeBucketResponseDto> mapFromJson(dynamic json) {
final map = <String, TimeBucketResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AssetCountByTimeBucket.fromJson(entry.value);
final value = TimeBucketResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
@@ -84,14 +84,14 @@ class AssetCountByTimeBucket {
return map;
}
// maps a json object with a list of AssetCountByTimeBucket-objects as value to a dart map
static Map<String, List<AssetCountByTimeBucket>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetCountByTimeBucket>>{};
// maps a json object with a list of TimeBucketResponseDto-objects as value to a dart map
static Map<String, List<TimeBucketResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<TimeBucketResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = AssetCountByTimeBucket.listFromJson(entry.value, growable: growable,);
map[entry.key] = TimeBucketResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;

View File

@@ -11,9 +11,9 @@
part of openapi.api;
class TimeGroupEnum {
class TimeBucketSize {
/// Instantiate a new enum with the provided [value].
const TimeGroupEnum._(this.value);
const TimeBucketSize._(this.value);
/// The underlying value of this enum member.
final String value;
@@ -23,22 +23,22 @@ class TimeGroupEnum {
String toJson() => value;
static const day = TimeGroupEnum._(r'day');
static const month = TimeGroupEnum._(r'month');
static const DAY = TimeBucketSize._(r'DAY');
static const MONTH = TimeBucketSize._(r'MONTH');
/// List of all possible values in this [enum][TimeGroupEnum].
static const values = <TimeGroupEnum>[
day,
month,
/// List of all possible values in this [enum][TimeBucketSize].
static const values = <TimeBucketSize>[
DAY,
MONTH,
];
static TimeGroupEnum? fromJson(dynamic value) => TimeGroupEnumTypeTransformer().decode(value);
static TimeBucketSize? fromJson(dynamic value) => TimeBucketSizeTypeTransformer().decode(value);
static List<TimeGroupEnum>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <TimeGroupEnum>[];
static List<TimeBucketSize>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <TimeBucketSize>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = TimeGroupEnum.fromJson(row);
final value = TimeBucketSize.fromJson(row);
if (value != null) {
result.add(value);
}
@@ -48,16 +48,16 @@ class TimeGroupEnum {
}
}
/// Transformation class that can [encode] an instance of [TimeGroupEnum] to String,
/// and [decode] dynamic data back to [TimeGroupEnum].
class TimeGroupEnumTypeTransformer {
factory TimeGroupEnumTypeTransformer() => _instance ??= const TimeGroupEnumTypeTransformer._();
/// Transformation class that can [encode] an instance of [TimeBucketSize] to String,
/// and [decode] dynamic data back to [TimeBucketSize].
class TimeBucketSizeTypeTransformer {
factory TimeBucketSizeTypeTransformer() => _instance ??= const TimeBucketSizeTypeTransformer._();
const TimeGroupEnumTypeTransformer._();
const TimeBucketSizeTypeTransformer._();
String encode(TimeGroupEnum data) => data.value;
String encode(TimeBucketSize data) => data.value;
/// Decodes a [dynamic value][data] to a TimeGroupEnum.
/// Decodes a [dynamic value][data] to a TimeBucketSize.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -65,11 +65,11 @@ class TimeGroupEnumTypeTransformer {
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
TimeGroupEnum? decode(dynamic data, {bool allowNull = true}) {
TimeBucketSize? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'day': return TimeGroupEnum.day;
case r'month': return TimeGroupEnum.month;
case r'DAY': return TimeBucketSize.DAY;
case r'MONTH': return TimeBucketSize.MONTH;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
@@ -79,7 +79,7 @@ class TimeGroupEnumTypeTransformer {
return null;
}
/// Singleton [TimeGroupEnumTypeTransformer] instance.
static TimeGroupEnumTypeTransformer? _instance;
/// Singleton [TimeBucketSizeTypeTransformer] instance.
static TimeBucketSizeTypeTransformer? _instance;
}