Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: iOS intents to integrate Immich into Apple Shortcuts and Siri #12915

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion mobile/ios/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
Expand Down
31 changes: 31 additions & 0 deletions mobile/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */; };
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */; };
6FC4C0DB2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FC4C0DA2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift */; };
6FC4C0DD2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
Expand All @@ -19,6 +21,16 @@
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
6FC4C0D82CA324C200D44B0C /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
Expand All @@ -38,6 +50,11 @@
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundServicePlugin.swift; sourceTree = "<group>"; };
65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundSyncWorker.swift; sourceTree = "<group>"; };
6FC4C0AE2CA322AB00D44B0C /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
6FC4C0B62CA324C100D44B0C /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
6FC4C0C12CA324C200D44B0C /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; };
6FC4C0DA2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSyncShortcutIntent.swift; sourceTree = "<group>"; };
6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSyncAppShortcut.swift; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -80,15 +97,19 @@
isa = PBXGroup;
children = (
886774DBDDE6B35BF2B4F2CD /* Pods_Runner.framework */,
6FC4C0B62CA324C100D44B0C /* Intents.framework */,
6FC4C0C12CA324C200D44B0C /* IntentsUI.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
65DD438629917FAD0047FFA8 /* BackgroundSync */ = {
isa = PBXGroup;
children = (
6FC4C0DA2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift */,
65F32F32299D349D00CE9261 /* BackgroundSyncWorker.swift */,
65F32F30299BD2F800CE9261 /* BackgroundServicePlugin.swift */,
6FC4C0DC2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift */,
);
path = BackgroundSync;
sourceTree = "<group>";
Expand Down Expand Up @@ -126,6 +147,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
6FC4C0AE2CA322AB00D44B0C /* Runner.entitlements */,
65DD438629917FAD0047FFA8 /* BackgroundSync */,
FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
Expand Down Expand Up @@ -156,6 +178,7 @@
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
D218A34AEE62BC1EF119F5B0 /* [CP] Embed Pods Frameworks */,
6724EEB7D74949FA08581154 /* [CP] Copy Pods Resources */,
6FC4C0D82CA324C200D44B0C /* Embed Foundation Extensions */,
);
buildRules = (
);
Expand All @@ -173,6 +196,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1530;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
Expand Down Expand Up @@ -313,6 +337,8 @@
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */,
6FC4C0DB2CA3268700D44B0C /* BackgroundSyncShortcutIntent.swift in Sources */,
6FC4C0DD2CA32AF000D44B0C /* BackgroundSyncAppShortcut.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -396,6 +422,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
Expand Down Expand Up @@ -539,8 +566,10 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 175;
Expand All @@ -567,8 +596,10 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 175;
Expand Down
4 changes: 4 additions & 0 deletions mobile/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ import permission_handler_apple
}
}

if #available(iOS 16.0, *) {
BackgroundSyncAppShortcut.updateAppShortcutParameters()
}

return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

Expand Down
21 changes: 21 additions & 0 deletions mobile/ios/Runner/BackgroundSync/BackgroundSyncAppShortcut.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// BackgroundSyncAppShortcut.swift
// Runner
//
// Created by Encotric on 24/09/2024.
//

import AppIntents


@available(iOS 16.0, *)
struct BackgroundSyncAppShortcut: AppShortcutsProvider {

@AppShortcutsBuilder static var appShortcuts: [AppShortcut] {
AppShortcut(intent: BackgroundSyncShortcutIntent(), phrases: [
// TODO: localized title
"Upload gallery using \(.applicationName)"], systemImageName: "square.and.arrow.up.on.square")
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// BackgroundSyncShortcutIntent.swift
// Runner
//
// Created by Encotric on 24/09/2024.
//

import AppIntents
import SwiftUI

@available(iOS 16.0, *)
struct BackgroundSyncShortcutIntent: AppIntent {

// TODO: localized title and description
static var title: LocalizedStringResource = "Sync gallery"

static var openAppWhenRun: Bool = true

static var isDiscoverable: Bool = true

func perform() async throws -> some IntentResult {

let backgroundWorker = BackgroundSyncWorker { _ in () }
backgroundWorker.run(maxSeconds: nil)

return .result()
}

}
4 changes: 4 additions & 0 deletions mobile/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@
<string>We need to manage backup your photos album</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need to manage backup your photos album</string>
<key>NSUserActivityTypes</key>
<array>
<string>IntentIntent</string>
</array>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
Expand Down
5 changes: 4 additions & 1 deletion mobile/ios/Runner/Runner.entitlements
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
<dict>
<key>com.apple.developer.siri</key>
<true/>
</dict>
</plist>
2 changes: 2 additions & 0 deletions mobile/ios/Runner/RunnerProfile.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.siri</key>
<true/>
</dict>
</plist>
36 changes: 36 additions & 0 deletions mobile/lib/models/backup/upload_request.model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class UploadRequest {
final String method;
final String url;
int priority = 0;
final Map<String, String> headers;
final Map<String, String> fields;
final bool isBackground;
void Function(int, int) onProgress;

UploadRequest(
{required this.method,
required this.url,
required this.fields,
required this.headers,
required this.isBackground,
required this.onProgress});

@override
bool operator ==(covariant UploadRequest other) {
if (identical(this, other)) return true;

return other.method == method &&
other.url == url &&
other.fields == fields &&
other.headers == headers &&
other.onProgress == onProgress;
}

@override
int get hashCode =>
method.hashCode ^
url.hashCode ^
priority.hashCode ^
headers.hashCode ^
fields.hashCode;
}
Loading
Loading