Source Code added
This commit is contained in:
parent
800376eafd
commit
9efa9bc6dd
3912 changed files with 754770 additions and 2 deletions
169
mobile/lib/repositories/asset_media.repository.dart
Normal file
169
mobile/lib/repositories/asset_media.repository.dart
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/entities/asset.entity.dart' as asset_entity;
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/response_extensions.dart';
|
||||
import 'package:immich_mobile/repositories/asset_api.repository.dart';
|
||||
import 'package:immich_mobile/utils/hash.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
final assetMediaRepositoryProvider = Provider((ref) => AssetMediaRepository(ref.watch(assetApiRepositoryProvider)));
|
||||
|
||||
class AssetMediaRepository {
|
||||
final AssetApiRepository _assetApiRepository;
|
||||
|
||||
static final Logger _log = Logger("AssetMediaRepository");
|
||||
|
||||
const AssetMediaRepository(this._assetApiRepository);
|
||||
|
||||
Future<bool> _androidSupportsTrash() async {
|
||||
if (Platform.isAndroid) {
|
||||
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
|
||||
int sdkVersion = androidInfo.version.sdkInt;
|
||||
return sdkVersion >= 31;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<List<String>> deleteAll(List<String> ids) async {
|
||||
if (CurrentPlatform.isAndroid) {
|
||||
if (await _androidSupportsTrash()) {
|
||||
return PhotoManager.editor.android.moveToTrash(
|
||||
ids.map((e) => AssetEntity(id: e, width: 1, height: 1, typeInt: 0)).toList(),
|
||||
);
|
||||
} else {
|
||||
return PhotoManager.editor.deleteWithIds(ids);
|
||||
}
|
||||
}
|
||||
return PhotoManager.editor.deleteWithIds(ids);
|
||||
}
|
||||
|
||||
Future<asset_entity.Asset?> get(String id) async {
|
||||
final entity = await AssetEntity.fromId(id);
|
||||
return toAsset(entity);
|
||||
}
|
||||
|
||||
static asset_entity.Asset? toAsset(AssetEntity? local) {
|
||||
if (local == null) return null;
|
||||
final asset_entity.Asset asset = asset_entity.Asset(
|
||||
checksum: "",
|
||||
localId: local.id,
|
||||
ownerId: fastHash(Store.get(StoreKey.currentUser).id),
|
||||
fileCreatedAt: local.createDateTime,
|
||||
fileModifiedAt: local.modifiedDateTime,
|
||||
updatedAt: local.modifiedDateTime,
|
||||
durationInSeconds: local.duration,
|
||||
type: asset_entity.AssetType.values[local.typeInt],
|
||||
fileName: local.title!,
|
||||
width: local.width,
|
||||
height: local.height,
|
||||
isFavorite: local.isFavorite,
|
||||
);
|
||||
if (asset.fileCreatedAt.year == 1970) {
|
||||
asset.fileCreatedAt = asset.fileModifiedAt;
|
||||
}
|
||||
if (local.latitude != null) {
|
||||
asset.exifInfo = ExifInfo(latitude: local.latitude, longitude: local.longitude);
|
||||
}
|
||||
asset.local = local;
|
||||
return asset;
|
||||
}
|
||||
|
||||
Future<String?> getOriginalFilename(String id) async {
|
||||
final entity = await AssetEntity.fromId(id);
|
||||
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// titleAsync gets the correct original filename for some assets on iOS
|
||||
// otherwise using the `entity.title` would return a random GUID
|
||||
final originalFilename = await entity.titleAsync;
|
||||
// treat empty filename as missing
|
||||
return originalFilename.isNotEmpty ? originalFilename : null;
|
||||
} catch (e) {
|
||||
_log.warning("Failed to get original filename for asset: $id. Error: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make this more efficient
|
||||
Future<int> shareAssets(List<BaseAsset> assets, BuildContext context) async {
|
||||
final downloadedXFiles = <XFile>[];
|
||||
final tempFiles = <File>[];
|
||||
|
||||
for (var asset in assets) {
|
||||
final localId = (asset is LocalAsset)
|
||||
? asset.id
|
||||
: asset is RemoteAsset
|
||||
? asset.localId
|
||||
: null;
|
||||
if (localId != null && !asset.isEdited) {
|
||||
File? f = await AssetEntity(id: localId, width: 1, height: 1, typeInt: 0).originFile;
|
||||
downloadedXFiles.add(XFile(f!.path));
|
||||
if (CurrentPlatform.isIOS) {
|
||||
tempFiles.add(f);
|
||||
}
|
||||
} else {
|
||||
final remoteId = (asset is RemoteAsset) ? asset.id : asset.remoteId;
|
||||
if (remoteId == null) {
|
||||
_log.warning("Asset has no remote ID for sharing: $asset");
|
||||
continue;
|
||||
}
|
||||
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
final name = asset.name;
|
||||
final tempFile = await File('${tempDir.path}/$name').create();
|
||||
final res = await _assetApiRepository.downloadAsset(remoteId, edited: true);
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
_log.severe("Download for $name failed", res.toLoggerString());
|
||||
continue;
|
||||
}
|
||||
|
||||
await tempFile.writeAsBytes(res.bodyBytes);
|
||||
downloadedXFiles.add(XFile(tempFile.path));
|
||||
tempFiles.add(tempFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (downloadedXFiles.isEmpty) {
|
||||
_log.warning("No asset can be retrieved for share");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we dont want to await the share result since the
|
||||
// "preparing" dialog will not disappear until
|
||||
final size = context.sizeData;
|
||||
unawaited(
|
||||
Share.shareXFiles(
|
||||
downloadedXFiles,
|
||||
sharePositionOrigin: Rect.fromPoints(Offset.zero, Offset(size.width / 3, size.height)),
|
||||
).then((result) async {
|
||||
for (var file in tempFiles) {
|
||||
try {
|
||||
await file.delete();
|
||||
} catch (e) {
|
||||
_log.warning("Failed to delete temporary file: ${file.path}", e);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return downloadedXFiles.length;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue