feat(mobile): share to mechanism (#15229)

* setup ios

* chore: succesfully sent media to the app

* share from Android

* wip: navigate to share screen

* wip: UI for displaying upload candidate

* wip: logic

* wip: upload logic

* wip: up up up we got it up

* wip

* wip

* wip

* upload state

* feat: i18n

* fix: release build ios'

* feat: clear file cache

* pr feedback

* using const for checking download status

---------

Co-authored-by: Alex <alex@pop-os.localdomain>
This commit is contained in:
Alex
2025-01-16 21:20:44 -06:00
committed by GitHub
parent 3a2bf91889
commit fd99bd05cf
33 changed files with 1368 additions and 55 deletions

View File

@@ -0,0 +1,63 @@
import 'dart:io';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/interfaces/share_handler.interface.dart';
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
import 'package:share_handler/share_handler.dart';
final shareHandlerRepositoryProvider = Provider(
(ref) => ShareHandlerRepository(),
);
class ShareHandlerRepository implements IShareHandlerRepository {
ShareHandlerRepository();
@override
void Function(List<ShareIntentAttachment> attachments)? onSharedMedia;
@override
Future<void> init() async {
final handler = ShareHandlerPlatform.instance;
final media = await handler.getInitialSharedMedia();
if (media != null && media.attachments != null) {
onSharedMedia?.call(_buildPayload(media.attachments!));
}
handler.sharedMediaStream.listen((SharedMedia media) {
if (media.attachments != null) {
onSharedMedia?.call(_buildPayload(media.attachments!));
}
});
}
List<ShareIntentAttachment> _buildPayload(
List<SharedAttachment?> attachments,
) {
final payload = <ShareIntentAttachment>[];
for (final attachment in attachments) {
if (attachment == null) {
continue;
}
final type = attachment.type == SharedAttachmentType.image
? ShareIntentAttachmentType.image
: ShareIntentAttachmentType.video;
final fileLength = File(attachment.path).lengthSync();
payload.add(
ShareIntentAttachment(
path: attachment.path,
type: type,
status: UploadStatus.enqueued,
uploadProgress: 0.0,
fileLength: fileLength,
),
);
}
return payload;
}
}

View File

@@ -0,0 +1,42 @@
import 'package:background_downloader/background_downloader.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/interfaces/upload.interface.dart';
import 'package:immich_mobile/utils/upload.dart';
final uploadRepositoryProvider = Provider((ref) => UploadRepository());
class UploadRepository implements IUploadRepository {
@override
void Function(TaskStatusUpdate)? onUploadStatus;
@override
void Function(TaskProgressUpdate)? onTaskProgress;
UploadRepository() {
FileDownloader().registerCallbacks(
group: uploadGroup,
taskStatusCallback: (update) => onUploadStatus?.call(update),
taskProgressCallback: (update) => onTaskProgress?.call(update),
);
}
@override
Future<bool> upload(UploadTask task) {
return FileDownloader().enqueue(task);
}
@override
Future<void> deleteAllTrackingRecords() {
return FileDownloader().database.deleteAllRecords();
}
@override
Future<bool> cancel(String id) {
return FileDownloader().cancelTaskWithId(id);
}
@override
Future<void> deleteRecordsWithIds(List<String> ids) {
return FileDownloader().database.deleteRecordsWithIds(ids);
}
}