mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
feat(mobile): edit date time action
This commit is contained in:
parent
f2f3db3a79
commit
12764666e9
@ -790,6 +790,7 @@
|
|||||||
"edit_avatar": "Edit avatar",
|
"edit_avatar": "Edit avatar",
|
||||||
"edit_date": "Edit date",
|
"edit_date": "Edit date",
|
||||||
"edit_date_and_time": "Edit date and time",
|
"edit_date_and_time": "Edit date and time",
|
||||||
|
"edit_date_time_action_prompt": "{count} date and time edited",
|
||||||
"edit_description": "Edit description",
|
"edit_description": "Edit description",
|
||||||
"edit_description_prompt": "Please select a new description:",
|
"edit_description_prompt": "Please select a new description:",
|
||||||
"edit_exclusion_pattern": "Edit exclusion pattern",
|
"edit_exclusion_pattern": "Edit exclusion pattern",
|
||||||
|
@ -12,6 +12,7 @@ class RemoteAsset extends BaseAsset {
|
|||||||
final String id;
|
final String id;
|
||||||
final String? localId;
|
final String? localId;
|
||||||
final String? thumbHash;
|
final String? thumbHash;
|
||||||
|
final DateTime? localDateTime;
|
||||||
final AssetVisibility visibility;
|
final AssetVisibility visibility;
|
||||||
final String ownerId;
|
final String ownerId;
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ class RemoteAsset extends BaseAsset {
|
|||||||
super.durationInSeconds,
|
super.durationInSeconds,
|
||||||
super.isFavorite = false,
|
super.isFavorite = false,
|
||||||
this.thumbHash,
|
this.thumbHash,
|
||||||
|
this.localDateTime,
|
||||||
this.visibility = AssetVisibility.timeline,
|
this.visibility = AssetVisibility.timeline,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -51,6 +53,7 @@ class RemoteAsset extends BaseAsset {
|
|||||||
localId: ${localId ?? "<NA>"},
|
localId: ${localId ?? "<NA>"},
|
||||||
isFavorite: $isFavorite,
|
isFavorite: $isFavorite,
|
||||||
thumbHash: ${thumbHash ?? "<NA>"},
|
thumbHash: ${thumbHash ?? "<NA>"},
|
||||||
|
localDateTime: ${localDateTime ?? "<NA>"},
|
||||||
visibility: $visibility,
|
visibility: $visibility,
|
||||||
}''';
|
}''';
|
||||||
}
|
}
|
||||||
@ -64,6 +67,7 @@ class RemoteAsset extends BaseAsset {
|
|||||||
ownerId == other.ownerId &&
|
ownerId == other.ownerId &&
|
||||||
localId == other.localId &&
|
localId == other.localId &&
|
||||||
thumbHash == other.thumbHash &&
|
thumbHash == other.thumbHash &&
|
||||||
|
localDateTime == other.localDateTime &&
|
||||||
visibility == other.visibility;
|
visibility == other.visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,5 +78,6 @@ class RemoteAsset extends BaseAsset {
|
|||||||
ownerId.hashCode ^
|
ownerId.hashCode ^
|
||||||
localId.hashCode ^
|
localId.hashCode ^
|
||||||
thumbHash.hashCode ^
|
thumbHash.hashCode ^
|
||||||
|
localDateTime.hashCode ^
|
||||||
visibility.hashCode;
|
visibility.hashCode;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:drift/drift.dart' hide Query;
|
import 'package:drift/drift.dart' hide Query;
|
||||||
import 'package:immich_mobile/domain/models/exif.model.dart' as domain;
|
import 'package:immich_mobile/domain/models/exif.model.dart' as domain;
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
import 'package:immich_mobile/infrastructure/utils/drift_default.mixin.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
|
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
|
||||||
@ -143,3 +144,22 @@ class RemoteExifEntity extends Table with DriftDefaultsMixin {
|
|||||||
@override
|
@override
|
||||||
Set<Column> get primaryKey => {assetId};
|
Set<Column> get primaryKey => {assetId};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension RemoteExifEntityDataDomainEx on RemoteExifEntityData {
|
||||||
|
domain.ExifInfo toDto() => domain.ExifInfo (
|
||||||
|
fileSize: fileSize,
|
||||||
|
description: description,
|
||||||
|
orientation: orientation,
|
||||||
|
timeZone: timeZone,
|
||||||
|
dateTimeOriginal: dateTimeOriginal,
|
||||||
|
latitude: latitude,
|
||||||
|
longitude: longitude,
|
||||||
|
city: city,
|
||||||
|
state: state,
|
||||||
|
country: country,
|
||||||
|
make: make,
|
||||||
|
model: model,
|
||||||
|
f: fNumber,
|
||||||
|
iso: iso,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -49,6 +49,7 @@ extension RemoteAssetEntityDataDomainEx on RemoteAssetEntityData {
|
|||||||
isFavorite: isFavorite,
|
isFavorite: isFavorite,
|
||||||
height: height,
|
height: height,
|
||||||
width: width,
|
width: width,
|
||||||
|
localDateTime: localDateTime,
|
||||||
thumbHash: thumbHash,
|
thumbHash: thumbHash,
|
||||||
visibility: visibility,
|
visibility: visibility,
|
||||||
localId: null,
|
localId: null,
|
||||||
|
@ -2,7 +2,6 @@ import 'package:drift/drift.dart';
|
|||||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
|
||||||
as entity;
|
as entity;
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
@ -52,27 +51,6 @@ class DriftRemoteExifRepository extends DriftDatabaseRepository {
|
|||||||
final query = _db.remoteExifEntity.select()
|
final query = _db.remoteExifEntity.select()
|
||||||
..where((exif) => exif.assetId.equals(assetId));
|
..where((exif) => exif.assetId.equals(assetId));
|
||||||
|
|
||||||
return query.map((asset) => asset.toDto()).getSingleOrNull();
|
return query.map((exif) => exif.toDto()).getSingleOrNull();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension on RemoteExifEntityData {
|
|
||||||
ExifInfo toDto() {
|
|
||||||
return ExifInfo(
|
|
||||||
fileSize: fileSize,
|
|
||||||
description: description,
|
|
||||||
orientation: orientation,
|
|
||||||
timeZone: timeZone,
|
|
||||||
dateTimeOriginal: dateTimeOriginal,
|
|
||||||
latitude: latitude,
|
|
||||||
longitude: longitude,
|
|
||||||
city: city,
|
|
||||||
state: state,
|
|
||||||
country: country,
|
|
||||||
make: make,
|
|
||||||
model: model,
|
|
||||||
f: fNumber,
|
|
||||||
iso: iso,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/remote_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||||
@ -9,6 +10,13 @@ class DriftRemoteAssetRepository extends DriftDatabaseRepository {
|
|||||||
final Drift _db;
|
final Drift _db;
|
||||||
const DriftRemoteAssetRepository(this._db) : super(_db);
|
const DriftRemoteAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
Future<RemoteAsset?> get(String assetId) {
|
||||||
|
final query = _db.remoteAssetEntity.select()
|
||||||
|
..where((asset) => asset.id.equals(assetId));
|
||||||
|
|
||||||
|
return query.map((asset) => asset.toDto()).getSingleOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updateFavorite(List<String> ids, bool isFavorite) {
|
Future<void> updateFavorite(List<String> ids, bool isFavorite) {
|
||||||
return _db.batch((batch) async {
|
return _db.batch((batch) async {
|
||||||
for (final id in ids) {
|
for (final id in ids) {
|
||||||
@ -47,4 +55,26 @@ class DriftRemoteAssetRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateDateTime(List<String> ids, String dateTime) {
|
||||||
|
final localDateTime = dateTime.replaceAll(RegExp(r'[\+|-][0-9]{2}:[0-9]{2}'), '');
|
||||||
|
return _db.batch((batch) async {
|
||||||
|
for (final id in ids) {
|
||||||
|
batch.update(
|
||||||
|
_db.remoteAssetEntity,
|
||||||
|
RemoteAssetEntityCompanion(
|
||||||
|
localDateTime: Value(DateTime.parse(localDateTime).toUtc()),
|
||||||
|
),
|
||||||
|
where: (e) => e.id.equals(id),
|
||||||
|
);
|
||||||
|
batch.update(
|
||||||
|
_db.remoteExifEntity,
|
||||||
|
RemoteExifEntityCompanion(
|
||||||
|
dateTimeOriginal: Value(DateTime.parse(dateTime)),
|
||||||
|
),
|
||||||
|
where: (e) => e.assetId.equals(id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,49 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
|
|
||||||
class EditDateTimeActionButton extends ConsumerWidget {
|
class EditDateTimeActionButton extends ConsumerWidget {
|
||||||
const EditDateTimeActionButton({super.key});
|
final ActionSource source;
|
||||||
|
|
||||||
|
const EditDateTimeActionButton({super.key, required this.source});
|
||||||
|
|
||||||
|
_onTap(BuildContext context, WidgetRef ref) async {
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final result =
|
||||||
|
await ref.read(actionProvider.notifier).editDateTime(source, context);
|
||||||
|
if (result == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ref.read(timelineServiceProvider).reloadBucket();
|
||||||
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
|
final successMessage = 'edit_date_time_action_prompt'.t(
|
||||||
|
context: context,
|
||||||
|
args: {'count': result.count.toString()},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (context.mounted) {
|
||||||
|
ImmichToast.show(
|
||||||
|
context: context,
|
||||||
|
msg: result.success
|
||||||
|
? successMessage
|
||||||
|
: 'scaffold_body_error_occurred'.t(context: context),
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
toastType: result.success ? ToastType.success : ToastType.error,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@ -12,6 +51,7 @@ class EditDateTimeActionButton extends ConsumerWidget {
|
|||||||
maxWidth: 95.0,
|
maxWidth: 95.0,
|
||||||
iconData: Icons.edit_calendar_outlined,
|
iconData: Icons.edit_calendar_outlined,
|
||||||
label: "control_bottom_app_bar_edit_time".t(context: context),
|
label: "control_bottom_app_bar_edit_time".t(context: context),
|
||||||
|
onPressed: () => _onTap(context, ref),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import 'package:immich_mobile/constants/enums.dart';
|
|||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ class EditLocationActionButton extends ConsumerWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await ref.read(timelineServiceProvider).reloadBucket();
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
final successMessage = 'edit_location_action_prompt'.t(
|
final successMessage = 'edit_location_action_prompt'.t(
|
||||||
|
@ -41,7 +41,7 @@ class HomeBottomAppBar extends ConsumerWidget {
|
|||||||
isTrashEnable
|
isTrashEnable
|
||||||
? const TrashActionButton()
|
? const TrashActionButton()
|
||||||
: const DeletePermanentActionButton(),
|
: const DeletePermanentActionButton(),
|
||||||
const EditDateTimeActionButton(),
|
const EditDateTimeActionButton(source: ActionSource.timeline),
|
||||||
const EditLocationActionButton(source: ActionSource.timeline),
|
const EditLocationActionButton(source: ActionSource.timeline),
|
||||||
const MoveToLockFolderActionButton(
|
const MoveToLockFolderActionButton(
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
|
@ -194,6 +194,28 @@ class ActionNotifier extends Notifier<void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ActionResult?> editDateTime(
|
||||||
|
ActionSource source,
|
||||||
|
BuildContext context,
|
||||||
|
) async {
|
||||||
|
final ids = _getOwnedRemoteForSource(source);
|
||||||
|
try {
|
||||||
|
final isEdited = await _service.editDateTime(ids, context);
|
||||||
|
if (!isEdited) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActionResult(count: ids.length, success: true);
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Failed to edit date and time for assets', error, stack);
|
||||||
|
return ActionResult(
|
||||||
|
count: ids.length,
|
||||||
|
success: false,
|
||||||
|
error: error.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension on Iterable<RemoteAsset> {
|
extension on Iterable<RemoteAsset> {
|
||||||
|
@ -79,6 +79,18 @@ class AssetApiRepository extends ApiRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateDateTime(
|
||||||
|
List<String> ids,
|
||||||
|
String dateTime,
|
||||||
|
) async {
|
||||||
|
return _api.updateAssets(
|
||||||
|
AssetBulkUpdateDto(
|
||||||
|
ids: ids,
|
||||||
|
dateTimeOriginal: dateTime,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_mapVisibility(AssetVisibilityEnum visibility) => switch (visibility) {
|
_mapVisibility(AssetVisibilityEnum visibility) => switch (visibility) {
|
||||||
AssetVisibilityEnum.timeline => AssetVisibility.timeline,
|
AssetVisibilityEnum.timeline => AssetVisibility.timeline,
|
||||||
AssetVisibilityEnum.hidden => AssetVisibility.hidden,
|
AssetVisibilityEnum.hidden => AssetVisibility.hidden,
|
||||||
|
@ -8,9 +8,11 @@ import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
|||||||
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/exif.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/asset_api.repository.dart';
|
import 'package:immich_mobile/repositories/asset_api.repository.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/date_time_picker.dart';
|
||||||
import 'package:immich_mobile/widgets/common/location_picker.dart';
|
import 'package:immich_mobile/widgets/common/location_picker.dart';
|
||||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:timezone/timezone.dart';
|
||||||
|
|
||||||
final actionServiceProvider = Provider<ActionService>(
|
final actionServiceProvider = Provider<ActionService>(
|
||||||
(ref) => ActionService(
|
(ref) => ActionService(
|
||||||
@ -99,7 +101,7 @@ class ActionService {
|
|||||||
) async {
|
) async {
|
||||||
LatLng? initialLatLng;
|
LatLng? initialLatLng;
|
||||||
if (remoteIds.length == 1) {
|
if (remoteIds.length == 1) {
|
||||||
final exif = await _remoteExifRepository.get(remoteIds[0]);
|
final exif = await _remoteExifRepository.get(remoteIds.first);
|
||||||
|
|
||||||
if (exif?.latitude != null && exif?.longitude != null) {
|
if (exif?.latitude != null && exif?.longitude != null) {
|
||||||
initialLatLng = LatLng(exif!.latitude!, exif.longitude!);
|
initialLatLng = LatLng(exif!.latitude!, exif.longitude!);
|
||||||
@ -126,4 +128,61 @@ class ActionService {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> editDateTime(
|
||||||
|
List<String> remoteIds,
|
||||||
|
BuildContext context,
|
||||||
|
) async {
|
||||||
|
DateTime? initialDateTime;
|
||||||
|
Duration? initialOffset;
|
||||||
|
String? initialTimeZone;
|
||||||
|
if (remoteIds.length == 1) {
|
||||||
|
final asset = await _remoteAssetRepository.get(remoteIds.first);
|
||||||
|
final exif = await _remoteExifRepository.get(remoteIds.first);
|
||||||
|
|
||||||
|
initialDateTime = asset?.localDateTime;
|
||||||
|
initialTimeZone = exif?.timeZone;
|
||||||
|
if (initialDateTime != null && initialTimeZone != null) {
|
||||||
|
try {
|
||||||
|
final location = getLocation(initialTimeZone);
|
||||||
|
initialOffset = TZDateTime.from(initialDateTime, location).timeZoneOffset;
|
||||||
|
} on LocationNotFoundException {
|
||||||
|
RegExp re = RegExp(
|
||||||
|
r'^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$',
|
||||||
|
caseSensitive: false,
|
||||||
|
);
|
||||||
|
final m = re.firstMatch(initialTimeZone);
|
||||||
|
if (m != null) {
|
||||||
|
final offset = Duration(
|
||||||
|
hours: int.parse(m.group(1) ?? '0'),
|
||||||
|
minutes: int.parse(m.group(2) ?? '0'),
|
||||||
|
);
|
||||||
|
initialOffset = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final dateTime = await showDateTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialDateTime: initialDateTime,
|
||||||
|
initialTZ: initialTimeZone,
|
||||||
|
initialTZOffset: initialOffset,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dateTime == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _assetApiRepository.updateDateTime(
|
||||||
|
remoteIds,
|
||||||
|
dateTime,
|
||||||
|
);
|
||||||
|
await _remoteAssetRepository.updateDateTime(
|
||||||
|
remoteIds,
|
||||||
|
dateTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user