Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f82cd45d0 | |||
| 27bc8eba7b |
+30
-30
@@ -2,37 +2,37 @@
|
|||||||
# Manual edits may be lost in future updates.
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||||
version = "4.52.1"
|
version = "4.52.3"
|
||||||
constraints = "4.52.1"
|
constraints = "4.52.3"
|
||||||
hashes = [
|
hashes = [
|
||||||
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
|
"h1:3jU62KY4Oj3xzMwkTQWon1nlIvFkgTCqI93IzUGaa0c=",
|
||||||
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
|
"h1:BWimtYXrvbzbbuoVcyobjQnXjjOb9X69JFTw+GuPxfk=",
|
||||||
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
|
"h1:C/KvLEm8dVQ6zG2X4asLDtmw2JW/xu7E8MddtaXniO0=",
|
||||||
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
|
"h1:Doo0xcLFf+CnfDWjsA7G1NvSLURuwcgyVy8k0NF1gJA=",
|
||||||
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
|
"h1:Gc3FGDtR8lUWsi9VImnnE5/USDXiIwYsv4Hbl+d2lwY=",
|
||||||
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
|
"h1:HsDY6s1gup5fW9TeuTUy85QMIld1nDOUFlwsfxIq1ig=",
|
||||||
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
|
"h1:MnHkB56E4b/kT6WZigsZJnB5rgnCfDVbrLBNxIsEXPY=",
|
||||||
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
|
"h1:O/FUQEqhtknJNdsaMbIBi2pLWBds2VvN5FsTVVntzb0=",
|
||||||
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
|
"h1:OKQBynkp0J5DIf5FOl/NR3S2rvh89pY+t5wevYxdTJs=",
|
||||||
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
|
"h1:On+vPsYV8U/J/8wFZPXjeAgNJqFFQj42vNOKuNKURkY=",
|
||||||
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
|
"h1:SPkrMRJahxK0uum7FnUugbGN/JepHMH8M71DBtYrvG0=",
|
||||||
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
|
"h1:bEh1ASPMiin3F36+hTfjMQTBnuDl2DzjzSCdova3JEM=",
|
||||||
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
|
"h1:dtIK+x5Q1sh5SMPaHBHXhL9XDIqbRW0EBmVZ+KHQB8E=",
|
||||||
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
|
"h1:kZcwWfODMWWyauZ66oaO/X+xXkqBtrbYwfUFEtspwEc=",
|
||||||
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
|
"zh:53946fce4a631f1d98c61550821c88edede9169dfe5cc254e09a2ab207f76b3f",
|
||||||
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
|
"zh:61654a21f1dd4331492d4ef77e9ebff066bc01e1281f92b925e5697c9138d681",
|
||||||
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
|
"zh:6a54e9d129b276f052a2f1b73ad0b8735fe6a7403c6a8f6aa111e525eeefaf35",
|
||||||
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
|
"zh:7692374e655c346a630b5a7cd776c5e0b2388900dcd7ab69a3af85d0c31c6c43",
|
||||||
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
|
|
||||||
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
|
|
||||||
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
|
|
||||||
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
|
|
||||||
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
|
|
||||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||||
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
|
"zh:8fe5b792a4d2b1c3a0e573649642962494faa00299baa6aaf813b9a43203dc02",
|
||||||
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
|
"zh:a0f403a4862df90f09de65c6e939d6cfd069a8dda2dd33f82948bf6f5f1124ef",
|
||||||
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
|
"zh:a25dc3eb60777b600f8f125d321fe7c50b811c5302b58e9a727ceb749a04e35d",
|
||||||
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
|
"zh:a2f2ac7dc703c69d2e8c67c9cb5620b5348cb4fd6b98515fbe3f478517b56602",
|
||||||
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
|
"zh:d452e7bd24445ee14166470cf50f3aca566d46cab5f26f1c5c988c0f3106b697",
|
||||||
|
"zh:e10a52b0294735659eb3f0821ad2006ec097918efe58d31d37a5e3c47efef5f6",
|
||||||
|
"zh:e28dd0954cef9f05adf4d4b440d6f134f605344dfa56307181996675e6550af2",
|
||||||
|
"zh:f1e3b2f43a472280442f01ba71a3c06c9167432e553381132ea5c4a77e0b6dd5",
|
||||||
|
"zh:f71fd63718d38fd43829861e91fe79e16d7b4c7c3d508ae3d077368d89b8e5a0",
|
||||||
|
"zh:faf8d3da4b819c4ae8e565d2b1a684c6a948a086cb299189a5e7b30b2178409d",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
cloudflare = {
|
cloudflare = {
|
||||||
source = "cloudflare/cloudflare"
|
source = "cloudflare/cloudflare"
|
||||||
version = "4.52.1"
|
version = "4.52.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-30
@@ -2,37 +2,37 @@
|
|||||||
# Manual edits may be lost in future updates.
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||||
version = "4.52.1"
|
version = "4.52.3"
|
||||||
constraints = "4.52.1"
|
constraints = "4.52.3"
|
||||||
hashes = [
|
hashes = [
|
||||||
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
|
"h1:3jU62KY4Oj3xzMwkTQWon1nlIvFkgTCqI93IzUGaa0c=",
|
||||||
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
|
"h1:BWimtYXrvbzbbuoVcyobjQnXjjOb9X69JFTw+GuPxfk=",
|
||||||
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
|
"h1:C/KvLEm8dVQ6zG2X4asLDtmw2JW/xu7E8MddtaXniO0=",
|
||||||
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
|
"h1:Doo0xcLFf+CnfDWjsA7G1NvSLURuwcgyVy8k0NF1gJA=",
|
||||||
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
|
"h1:Gc3FGDtR8lUWsi9VImnnE5/USDXiIwYsv4Hbl+d2lwY=",
|
||||||
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
|
"h1:HsDY6s1gup5fW9TeuTUy85QMIld1nDOUFlwsfxIq1ig=",
|
||||||
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
|
"h1:MnHkB56E4b/kT6WZigsZJnB5rgnCfDVbrLBNxIsEXPY=",
|
||||||
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
|
"h1:O/FUQEqhtknJNdsaMbIBi2pLWBds2VvN5FsTVVntzb0=",
|
||||||
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
|
"h1:OKQBynkp0J5DIf5FOl/NR3S2rvh89pY+t5wevYxdTJs=",
|
||||||
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
|
"h1:On+vPsYV8U/J/8wFZPXjeAgNJqFFQj42vNOKuNKURkY=",
|
||||||
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
|
"h1:SPkrMRJahxK0uum7FnUugbGN/JepHMH8M71DBtYrvG0=",
|
||||||
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
|
"h1:bEh1ASPMiin3F36+hTfjMQTBnuDl2DzjzSCdova3JEM=",
|
||||||
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
|
"h1:dtIK+x5Q1sh5SMPaHBHXhL9XDIqbRW0EBmVZ+KHQB8E=",
|
||||||
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
|
"h1:kZcwWfODMWWyauZ66oaO/X+xXkqBtrbYwfUFEtspwEc=",
|
||||||
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
|
"zh:53946fce4a631f1d98c61550821c88edede9169dfe5cc254e09a2ab207f76b3f",
|
||||||
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
|
"zh:61654a21f1dd4331492d4ef77e9ebff066bc01e1281f92b925e5697c9138d681",
|
||||||
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
|
"zh:6a54e9d129b276f052a2f1b73ad0b8735fe6a7403c6a8f6aa111e525eeefaf35",
|
||||||
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
|
"zh:7692374e655c346a630b5a7cd776c5e0b2388900dcd7ab69a3af85d0c31c6c43",
|
||||||
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
|
|
||||||
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
|
|
||||||
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
|
|
||||||
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
|
|
||||||
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
|
|
||||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||||
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
|
"zh:8fe5b792a4d2b1c3a0e573649642962494faa00299baa6aaf813b9a43203dc02",
|
||||||
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
|
"zh:a0f403a4862df90f09de65c6e939d6cfd069a8dda2dd33f82948bf6f5f1124ef",
|
||||||
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
|
"zh:a25dc3eb60777b600f8f125d321fe7c50b811c5302b58e9a727ceb749a04e35d",
|
||||||
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
|
"zh:a2f2ac7dc703c69d2e8c67c9cb5620b5348cb4fd6b98515fbe3f478517b56602",
|
||||||
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
|
"zh:d452e7bd24445ee14166470cf50f3aca566d46cab5f26f1c5c988c0f3106b697",
|
||||||
|
"zh:e10a52b0294735659eb3f0821ad2006ec097918efe58d31d37a5e3c47efef5f6",
|
||||||
|
"zh:e28dd0954cef9f05adf4d4b440d6f134f605344dfa56307181996675e6550af2",
|
||||||
|
"zh:f1e3b2f43a472280442f01ba71a3c06c9167432e553381132ea5c4a77e0b6dd5",
|
||||||
|
"zh:f71fd63718d38fd43829861e91fe79e16d7b4c7c3d508ae3d077368d89b8e5a0",
|
||||||
|
"zh:faf8d3da4b819c4ae8e565d2b1a684c6a948a086cb299189a5e7b30b2178409d",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ terraform {
|
|||||||
required_providers {
|
required_providers {
|
||||||
cloudflare = {
|
cloudflare = {
|
||||||
source = "cloudflare/cloudflare"
|
source = "cloudflare/cloudflare"
|
||||||
version = "4.52.1"
|
version = "4.52.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 77;
|
objectVersion = 54;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@@ -27,11 +27,9 @@
|
|||||||
FAC6F89B2D287C890078CB2F /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = FAC6F8902D287C890078CB2F /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
FAC6F89B2D287C890078CB2F /* ShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = FAC6F8902D287C890078CB2F /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
FAC6F8B72D287F120078CB2F /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC6F8B52D287F120078CB2F /* ShareViewController.swift */; };
|
FAC6F8B72D287F120078CB2F /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC6F8B52D287F120078CB2F /* ShareViewController.swift */; };
|
||||||
FAC6F8B92D287F120078CB2F /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FAC6F8B32D287F120078CB2F /* MainInterface.storyboard */; };
|
FAC6F8B92D287F120078CB2F /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FAC6F8B32D287F120078CB2F /* MainInterface.storyboard */; };
|
||||||
FE619FDB2E6F5D0600D0B708 /* NativeImageViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE619FD52E6F5D0600D0B708 /* NativeImageViewFactory.swift */; };
|
FEAFA8732E4D42F4001E47FE /* Thumbhash.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEAFA8722E4D42F4001E47FE /* Thumbhash.swift */; };
|
||||||
FE619FDC2E6F5D0600D0B708 /* Thumbhash.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE619FD72E6F5D0600D0B708 /* Thumbhash.swift */; };
|
FED3B1962E253E9B0030FD97 /* ThumbnailsImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED3B1942E253E9B0030FD97 /* ThumbnailsImpl.swift */; };
|
||||||
FE619FDD2E6F5D0600D0B708 /* Thumbnails.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE619FD82E6F5D0600D0B708 /* Thumbnails.g.swift */; };
|
FED3B1972E253E9B0030FD97 /* Thumbnails.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED3B1932E253E9B0030FD97 /* Thumbnails.g.swift */; };
|
||||||
FE619FDE2E6F5D0600D0B708 /* ThumbnailsImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE619FD92E6F5D0600D0B708 /* ThumbnailsImpl.swift */; };
|
|
||||||
FE619FDF2E6F5D0600D0B708 /* NativeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE619FD42E6F5D0600D0B708 /* NativeImageView.swift */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -113,11 +111,9 @@
|
|||||||
FAC6F8B42D287F120078CB2F /* ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareExtension.entitlements; sourceTree = "<group>"; };
|
FAC6F8B42D287F120078CB2F /* ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareExtension.entitlements; sourceTree = "<group>"; };
|
||||||
FAC6F8B52D287F120078CB2F /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
FAC6F8B52D287F120078CB2F /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
||||||
FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerProfile.entitlements; sourceTree = "<group>"; };
|
FAC7416727DB9F5500C668D8 /* RunnerProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerProfile.entitlements; sourceTree = "<group>"; };
|
||||||
FE619FD42E6F5D0600D0B708 /* NativeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeImageView.swift; sourceTree = "<group>"; };
|
FEAFA8722E4D42F4001E47FE /* Thumbhash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Thumbhash.swift; sourceTree = "<group>"; };
|
||||||
FE619FD52E6F5D0600D0B708 /* NativeImageViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeImageViewFactory.swift; sourceTree = "<group>"; };
|
FED3B1932E253E9B0030FD97 /* Thumbnails.g.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Thumbnails.g.swift; sourceTree = "<group>"; };
|
||||||
FE619FD72E6F5D0600D0B708 /* Thumbhash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Thumbhash.swift; sourceTree = "<group>"; };
|
FED3B1942E253E9B0030FD97 /* ThumbnailsImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailsImpl.swift; sourceTree = "<group>"; };
|
||||||
FE619FD82E6F5D0600D0B708 /* Thumbnails.g.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Thumbnails.g.swift; sourceTree = "<group>"; };
|
|
||||||
FE619FD92E6F5D0600D0B708 /* ThumbnailsImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailsImpl.swift; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
@@ -133,6 +129,8 @@
|
|||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
|
B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
);
|
||||||
path = Sync;
|
path = Sync;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -245,7 +243,6 @@
|
|||||||
97C146F01CF9000F007C117D /* Runner */ = {
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FE619FDA2E6F5D0600D0B708 /* Images */,
|
|
||||||
B21E34A62E5AF9760031FDB9 /* Background */,
|
B21E34A62E5AF9760031FDB9 /* Background */,
|
||||||
B2CF7F8C2DDE4EBB00744BF6 /* Sync */,
|
B2CF7F8C2DDE4EBB00744BF6 /* Sync */,
|
||||||
FA9973382CF6DF4B000EF859 /* Runner.entitlements */,
|
FA9973382CF6DF4B000EF859 /* Runner.entitlements */,
|
||||||
@@ -259,6 +256,7 @@
|
|||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||||
|
FED3B1952E253E9B0030FD97 /* Images */,
|
||||||
);
|
);
|
||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -284,22 +282,12 @@
|
|||||||
path = ShareExtension;
|
path = ShareExtension;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FE619FD62E6F5D0600D0B708 /* Viewer */ = {
|
FED3B1952E253E9B0030FD97 /* Images */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FE619FD42E6F5D0600D0B708 /* NativeImageView.swift */,
|
FEAFA8722E4D42F4001E47FE /* Thumbhash.swift */,
|
||||||
FE619FD52E6F5D0600D0B708 /* NativeImageViewFactory.swift */,
|
FED3B1932E253E9B0030FD97 /* Thumbnails.g.swift */,
|
||||||
);
|
FED3B1942E253E9B0030FD97 /* ThumbnailsImpl.swift */,
|
||||||
path = Viewer;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
FE619FDA2E6F5D0600D0B708 /* Images */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
FE619FD62E6F5D0600D0B708 /* Viewer */,
|
|
||||||
FE619FD72E6F5D0600D0B708 /* Thumbhash.swift */,
|
|
||||||
FE619FD82E6F5D0600D0B708 /* Thumbnails.g.swift */,
|
|
||||||
FE619FD92E6F5D0600D0B708 /* ThumbnailsImpl.swift */,
|
|
||||||
);
|
);
|
||||||
path = Images;
|
path = Images;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -570,14 +558,12 @@
|
|||||||
65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */,
|
65F32F31299BD2F800CE9261 /* BackgroundServicePlugin.swift in Sources */,
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||||
B21E34AC2E5B09190031FDB9 /* BackgroundWorker.swift in Sources */,
|
B21E34AC2E5B09190031FDB9 /* BackgroundWorker.swift in Sources */,
|
||||||
|
FEAFA8732E4D42F4001E47FE /* Thumbhash.swift in Sources */,
|
||||||
|
FED3B1962E253E9B0030FD97 /* ThumbnailsImpl.swift in Sources */,
|
||||||
B21E34AA2E5AFD2B0031FDB9 /* BackgroundWorkerApiImpl.swift in Sources */,
|
B21E34AA2E5AFD2B0031FDB9 /* BackgroundWorkerApiImpl.swift in Sources */,
|
||||||
|
FED3B1972E253E9B0030FD97 /* Thumbnails.g.swift in Sources */,
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||||
B2BE315F2E5E5229006EEF88 /* BackgroundWorker.g.swift in Sources */,
|
B2BE315F2E5E5229006EEF88 /* BackgroundWorker.g.swift in Sources */,
|
||||||
FE619FDB2E6F5D0600D0B708 /* NativeImageViewFactory.swift in Sources */,
|
|
||||||
FE619FDC2E6F5D0600D0B708 /* Thumbhash.swift in Sources */,
|
|
||||||
FE619FDD2E6F5D0600D0B708 /* Thumbnails.g.swift in Sources */,
|
|
||||||
FE619FDE2E6F5D0600D0B708 /* ThumbnailsImpl.swift in Sources */,
|
|
||||||
FE619FDF2E6F5D0600D0B708 /* NativeImageView.swift in Sources */,
|
|
||||||
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */,
|
65F32F33299D349D00CE9261 /* BackgroundSyncWorker.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import UIKit
|
|||||||
) -> Bool {
|
) -> Bool {
|
||||||
// Required for flutter_local_notification
|
// Required for flutter_local_notification
|
||||||
if #available(iOS 10.0, *) {
|
if #available(iOS 10.0, *) {
|
||||||
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
|
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
@@ -48,9 +48,6 @@ import UIKit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let factory = NativeImageViewFactory(messenger: controller.binaryMessenger)
|
|
||||||
registrar(forPlugin: "NativeImageView")!.register(factory, withId: NativeImageViewFactory.id)
|
|
||||||
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,12 +193,12 @@ class ThumbnailApiImpl: ThumbnailApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func requestAsset(assetId: String) -> PHAsset? {
|
private static func requestAsset(assetId: String) -> PHAsset? {
|
||||||
var asset: PHAsset?
|
var asset: PHAsset?
|
||||||
assetQueue.sync { asset = assetCache.object(forKey: assetId as NSString) }
|
assetQueue.sync { asset = assetCache.object(forKey: assetId as NSString) }
|
||||||
if asset != nil { return asset }
|
if asset != nil { return asset }
|
||||||
|
|
||||||
guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: fetchOptions).firstObject
|
guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: Self.fetchOptions).firstObject
|
||||||
else { return nil }
|
else { return nil }
|
||||||
assetQueue.async { assetCache.setObject(asset, forKey: assetId as NSString) }
|
assetQueue.async { assetCache.setObject(asset, forKey: assetId as NSString) }
|
||||||
return asset
|
return asset
|
||||||
|
|||||||
@@ -1,219 +0,0 @@
|
|||||||
import Flutter
|
|
||||||
import UIKit
|
|
||||||
import Photos
|
|
||||||
|
|
||||||
// TODO: the bounds this uses for scaling can change with the hero animation,
|
|
||||||
// so it doesn't display the image correctly until swiping to the next asset and back
|
|
||||||
class NativeImageView: NSObject, FlutterPlatformView {
|
|
||||||
private var _containerView: UIView
|
|
||||||
private var _scrollView: UIScrollView
|
|
||||||
private var _imageView: UIImageView
|
|
||||||
private var _image: UIImage?
|
|
||||||
private var _hasSetupZoom = false
|
|
||||||
|
|
||||||
private static let imageManager = PHImageManager.default()
|
|
||||||
private static let fetchOptions = {
|
|
||||||
let fetchOptions = PHFetchOptions()
|
|
||||||
fetchOptions.fetchLimit = 1
|
|
||||||
fetchOptions.wantsIncrementalChangeDetails = false
|
|
||||||
return fetchOptions
|
|
||||||
}()
|
|
||||||
private static let requestOptions = {
|
|
||||||
let requestOptions = PHImageRequestOptions()
|
|
||||||
requestOptions.isNetworkAccessAllowed = true
|
|
||||||
requestOptions.deliveryMode = .opportunistic
|
|
||||||
requestOptions.resizeMode = .none
|
|
||||||
requestOptions.isSynchronous = false
|
|
||||||
requestOptions.version = .current
|
|
||||||
return requestOptions
|
|
||||||
}()
|
|
||||||
|
|
||||||
init(
|
|
||||||
frame: CGRect,
|
|
||||||
viewIdentifier viewId: Int64,
|
|
||||||
arguments args: Any?,
|
|
||||||
binaryMessenger messenger: FlutterBinaryMessenger
|
|
||||||
) {
|
|
||||||
_containerView = UIView(frame: frame)
|
|
||||||
_scrollView = UIScrollView()
|
|
||||||
_imageView = UIImageView()
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
setupViews()
|
|
||||||
|
|
||||||
guard let arguments = args as? [String: Any],
|
|
||||||
let assetId = arguments["assetId"] as? String else {
|
|
||||||
print("Asset ID not provided")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let asset = ThumbnailApiImpl.requestAsset(assetId: assetId) else {
|
|
||||||
print("Asset not found for identifier: \(assetId)")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
loadImage(from: asset)
|
|
||||||
}
|
|
||||||
|
|
||||||
func view() -> UIView {
|
|
||||||
return _containerView
|
|
||||||
}
|
|
||||||
|
|
||||||
private func setupViews() {
|
|
||||||
// Configure image view
|
|
||||||
_imageView.contentMode = .scaleAspectFit
|
|
||||||
_imageView.preferredImageDynamicRange = .high
|
|
||||||
if #available(iOS 17.0, *) {
|
|
||||||
_imageView.layer.wantsExtendedDynamicRangeContent = true
|
|
||||||
_imageView.layer.contentsFormat = .RGBA16Float
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure scroll view
|
|
||||||
_scrollView.delegate = self
|
|
||||||
_scrollView.showsVerticalScrollIndicator = false
|
|
||||||
_scrollView.showsHorizontalScrollIndicator = false
|
|
||||||
_scrollView.bouncesZoom = true
|
|
||||||
_scrollView.decelerationRate = .fast
|
|
||||||
_scrollView.contentInsetAdjustmentBehavior = .never
|
|
||||||
_scrollView.backgroundColor = .clear
|
|
||||||
|
|
||||||
// Add double tap gesture
|
|
||||||
let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(_:)))
|
|
||||||
doubleTapGesture.numberOfTapsRequired = 2
|
|
||||||
_scrollView.addGestureRecognizer(doubleTapGesture)
|
|
||||||
|
|
||||||
// Setup view hierarchy
|
|
||||||
_scrollView.addSubview(_imageView)
|
|
||||||
_containerView.addSubview(_scrollView)
|
|
||||||
|
|
||||||
// Setup constraints
|
|
||||||
_scrollView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
_scrollView.topAnchor.constraint(equalTo: _containerView.topAnchor),
|
|
||||||
_scrollView.leadingAnchor.constraint(equalTo: _containerView.leadingAnchor),
|
|
||||||
_scrollView.trailingAnchor.constraint(equalTo: _containerView.trailingAnchor),
|
|
||||||
_scrollView.bottomAnchor.constraint(equalTo: _containerView.bottomAnchor)
|
|
||||||
])
|
|
||||||
|
|
||||||
// Observe bounds changes
|
|
||||||
_containerView.addObserver(self, forKeyPath: "bounds", options: [.new], context: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
|
||||||
if keyPath == "bounds", let image = _image {
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
|
||||||
self?.setupZoomScale(for: image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
|
||||||
_containerView.removeObserver(self, forKeyPath: "bounds")
|
|
||||||
}
|
|
||||||
|
|
||||||
private func loadImage(from asset: PHAsset) {
|
|
||||||
Self.imageManager.requestImageDataAndOrientation(
|
|
||||||
for: asset,
|
|
||||||
options: Self.requestOptions
|
|
||||||
) { [weak self] data, uti, orientation, info in
|
|
||||||
guard let data = data else { return }
|
|
||||||
|
|
||||||
if #available(iOS 17.0, *) {
|
|
||||||
var config = UIImageReader.Configuration()
|
|
||||||
config.prefersHighDynamicRange = true
|
|
||||||
let imageReader = UIImageReader(configuration: config)
|
|
||||||
guard let image = imageReader.image(data: data) else { return }
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self?.setImage(image)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
guard let image = UIImage(data: data) else { return }
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self?.setImage(image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func setImage(_ image: UIImage) {
|
|
||||||
_image = image
|
|
||||||
_imageView.image = image
|
|
||||||
|
|
||||||
// Wait for next run loop to ensure layout is complete
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
|
||||||
self?.setupZoomScale(for: image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func setupZoomScale(for image: UIImage) {
|
|
||||||
guard _scrollView.bounds.size.width > 0, _scrollView.bounds.size.height > 0 else {
|
|
||||||
// View not laid out yet
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set image view size to match image
|
|
||||||
_imageView.frame = CGRect(origin: .zero, size: image.size)
|
|
||||||
_scrollView.contentSize = image.size
|
|
||||||
|
|
||||||
// Calculate zoom scales
|
|
||||||
let scrollViewSize = _scrollView.bounds.size
|
|
||||||
let widthScale = scrollViewSize.width / image.size.width
|
|
||||||
let heightScale = scrollViewSize.height / image.size.height
|
|
||||||
let minScale = min(widthScale, heightScale)
|
|
||||||
|
|
||||||
_scrollView.minimumZoomScale = minScale
|
|
||||||
_scrollView.maximumZoomScale = max(2.0, minScale * 5.0)
|
|
||||||
_scrollView.zoomScale = minScale
|
|
||||||
|
|
||||||
centerImageView()
|
|
||||||
_hasSetupZoom = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private func centerImageView() {
|
|
||||||
let scrollViewSize = _scrollView.bounds.size
|
|
||||||
let imageViewSize = _imageView.frame.size
|
|
||||||
|
|
||||||
let horizontalInset = max(0, (scrollViewSize.width - imageViewSize.width) / 2)
|
|
||||||
let verticalInset = max(0, (scrollViewSize.height - imageViewSize.height) / 2)
|
|
||||||
|
|
||||||
_scrollView.contentInset = UIEdgeInsets(
|
|
||||||
top: verticalInset,
|
|
||||||
left: horizontalInset,
|
|
||||||
bottom: verticalInset,
|
|
||||||
right: horizontalInset
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func handleDoubleTap(_ gesture: UITapGestureRecognizer) {
|
|
||||||
guard _hasSetupZoom else { return }
|
|
||||||
|
|
||||||
if _scrollView.zoomScale > _scrollView.minimumZoomScale {
|
|
||||||
_scrollView.setZoomScale(_scrollView.minimumZoomScale, animated: true)
|
|
||||||
} else {
|
|
||||||
let tapLocation = gesture.location(in: _imageView)
|
|
||||||
let zoomScale = min(_scrollView.maximumZoomScale, _scrollView.minimumZoomScale * 3.0)
|
|
||||||
let zoomRect = zoomRectForScale(zoomScale, center: tapLocation)
|
|
||||||
_scrollView.zoom(to: zoomRect, animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func zoomRectForScale(_ scale: CGFloat, center: CGPoint) -> CGRect {
|
|
||||||
var zoomRect = CGRect.zero
|
|
||||||
zoomRect.size.width = _scrollView.frame.size.width / scale
|
|
||||||
zoomRect.size.height = _scrollView.frame.size.height / scale
|
|
||||||
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0)
|
|
||||||
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0)
|
|
||||||
return zoomRect
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - UIScrollViewDelegate
|
|
||||||
extension NativeImageView: UIScrollViewDelegate {
|
|
||||||
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
|
|
||||||
return _imageView
|
|
||||||
}
|
|
||||||
|
|
||||||
func scrollViewDidZoom(_ scrollView: UIScrollView) {
|
|
||||||
centerImageView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import Flutter
|
|
||||||
|
|
||||||
public class NativeImageViewFactory: NSObject, FlutterPlatformViewFactory {
|
|
||||||
public static let id = "native_image_view"
|
|
||||||
|
|
||||||
private let messenger: FlutterBinaryMessenger
|
|
||||||
|
|
||||||
init(messenger: FlutterBinaryMessenger) {
|
|
||||||
self.messenger = messenger
|
|
||||||
}
|
|
||||||
|
|
||||||
public func create(
|
|
||||||
withFrame frame: CGRect,
|
|
||||||
viewIdentifier viewId: Int64,
|
|
||||||
arguments args: Any?
|
|
||||||
) -> FlutterPlatformView {
|
|
||||||
NativeImageView(
|
|
||||||
frame: frame,
|
|
||||||
viewIdentifier: viewId,
|
|
||||||
arguments: args,
|
|
||||||
binaryMessenger: messenger
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
|
|
||||||
return FlutterStandardMessageCodec.sharedInstance()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@ import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet.wid
|
|||||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/top_app_bar.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/top_app_bar.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/video_viewer.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/video_viewer.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/images/native_image.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/is_motion_video_playing.provider.dart';
|
import 'package:immich_mobile/providers/asset_viewer/is_motion_video_playing.provider.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart';
|
import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
|
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
|
||||||
@@ -533,21 +533,24 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PhotoViewGalleryPageOptions _imageBuilder(BuildContext ctx, BaseAsset asset) {
|
PhotoViewGalleryPageOptions _imageBuilder(BuildContext ctx, BaseAsset asset) {
|
||||||
return PhotoViewGalleryPageOptions.customChild(
|
final size = ctx.sizeData;
|
||||||
disableScaleGestures: true,
|
return PhotoViewGalleryPageOptions(
|
||||||
|
key: ValueKey(asset.heroTag),
|
||||||
|
imageProvider: getFullImageProvider(asset, size: size),
|
||||||
|
heroAttributes: PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'),
|
||||||
|
filterQuality: FilterQuality.high,
|
||||||
|
tightMode: true,
|
||||||
|
disableScaleGestures: showingBottomSheet,
|
||||||
onDragStart: _onDragStart,
|
onDragStart: _onDragStart,
|
||||||
onDragUpdate: _onDragUpdate,
|
onDragUpdate: _onDragUpdate,
|
||||||
onDragEnd: _onDragEnd,
|
onDragEnd: _onDragEnd,
|
||||||
onTapDown: _onTapDown,
|
onTapDown: _onTapDown,
|
||||||
onLongPressStart: asset.isMotionPhoto ? _onLongPress : null,
|
onLongPressStart: asset.isMotionPhoto ? _onLongPress : null,
|
||||||
heroAttributes: PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'),
|
errorBuilder: (_, __, ___) => Container(
|
||||||
filterQuality: FilterQuality.high,
|
width: size.width,
|
||||||
basePosition: Alignment.center,
|
height: size.height,
|
||||||
child: NativeImageView(
|
color: backgroundColor,
|
||||||
key: _getVideoPlayerKey(asset.heroTag),
|
child: Thumbnail.fromAsset(asset: asset, fit: BoxFit.contain),
|
||||||
assetId: (asset as LocalAsset).id,
|
|
||||||
width: ctx.width,
|
|
||||||
height: ctx.height,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/gestures.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
class NativeImageView extends StatelessWidget {
|
|
||||||
final String assetId;
|
|
||||||
final double width;
|
|
||||||
final double height;
|
|
||||||
|
|
||||||
const NativeImageView({super.key, required this.assetId, required this.width, required this.height});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (defaultTargetPlatform != TargetPlatform.iOS) {
|
|
||||||
return Container(
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
color: Colors.grey,
|
|
||||||
child: const Center(child: Text('PHAsset view only available on iOS')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
child: UiKitView(
|
|
||||||
viewType: 'native_image_view',
|
|
||||||
layoutDirection: TextDirection.ltr,
|
|
||||||
creationParams: {'assetId': assetId},
|
|
||||||
creationParamsCodec: const StandardMessageCodec(),
|
|
||||||
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
|
|
||||||
Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer()),
|
|
||||||
Factory<HorizontalDragGestureRecognizer>(() => HorizontalDragGestureRecognizer()),
|
|
||||||
Factory<ScaleGestureRecognizer>(() => ScaleGestureRecognizer()),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,16 +6,17 @@
|
|||||||
onDateChange: (year?: number, month?: number, day?: number) => Promise<void>;
|
onDateChange: (year?: number, month?: number, day?: number) => Promise<void>;
|
||||||
onClearFilters?: () => void;
|
onClearFilters?: () => void;
|
||||||
defaultDate?: string;
|
defaultDate?: string;
|
||||||
|
startYear: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { onDateChange, onClearFilters, defaultDate }: Props = $props();
|
let { onDateChange, onClearFilters, defaultDate, startYear }: Props = $props();
|
||||||
|
|
||||||
let selectedYear = $state<number | undefined>(undefined);
|
let selectedYear = $state<number | undefined>(undefined);
|
||||||
let selectedMonth = $state<number | undefined>(undefined);
|
let selectedMonth = $state<number | undefined>(undefined);
|
||||||
let selectedDay = $state<number | undefined>(undefined);
|
let selectedDay = $state<number | undefined>(undefined);
|
||||||
|
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
const yearOptions = Array.from({ length: 30 }, (_, i) => currentYear - i);
|
let yearOptions = $derived(Array.from({ length: currentYear - startYear + 1 }, (_, i) => currentYear - i));
|
||||||
|
|
||||||
const monthOptions = Array.from({ length: 12 }, (_, i) => ({
|
const monthOptions = Array.from({ length: 12 }, (_, i) => ({
|
||||||
value: i + 1,
|
value: i + 1,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
import { setQueryValue } from '$lib/utils/navigation';
|
import { setQueryValue } from '$lib/utils/navigation';
|
||||||
import { buildDateString } from '$lib/utils/string-utils';
|
import { buildDateString } from '$lib/utils/string-utils';
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||||
import { searchAssets, updateAssets, type AssetResponseDto } from '@immich/sdk';
|
import { AssetOrder, searchAssets, updateAssets, type AssetResponseDto } from '@immich/sdk';
|
||||||
import { Button, LoadingSpinner, modalManager, Text } from '@immich/ui';
|
import { Button, LoadingSpinner, modalManager, Text } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiMapMarkerMultipleOutline,
|
mdiMapMarkerMultipleOutline,
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
let partialDate = $state<string | null>(data.partialDate);
|
let partialDate = $state<string | null>(data.partialDate);
|
||||||
let isLoading = $state(false);
|
let isLoading = $state(false);
|
||||||
let assets = $state<AssetResponseDto[]>([]);
|
let assets = $state<AssetResponseDto[]>([]);
|
||||||
|
let startYear = $state(2000);
|
||||||
let shiftKeyIsDown = $state(false);
|
let shiftKeyIsDown = $state(false);
|
||||||
let assetInteraction = new AssetInteraction();
|
let assetInteraction = new AssetInteraction();
|
||||||
let location = $state<{ latitude: number; longitude: number }>({ latitude: 0, longitude: 0 });
|
let location = $state<{ latitude: number; longitude: number }>({ latitude: 0, longitude: 0 });
|
||||||
@@ -64,6 +65,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getEarliestAsset = async () => {
|
||||||
|
const earliest = await searchAssets({
|
||||||
|
metadataSearchDto: {
|
||||||
|
withExif: true,
|
||||||
|
size: 1,
|
||||||
|
order: AssetOrder.Asc,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const asset = earliest.assets.items[0];
|
||||||
|
if (!asset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startYear = new Date(asset.localDateTime).getFullYear();
|
||||||
|
};
|
||||||
|
|
||||||
|
void getEarliestAsset();
|
||||||
|
|
||||||
const loadAssets = async () => {
|
const loadAssets = async () => {
|
||||||
if (takenRange) {
|
if (takenRange) {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -262,6 +282,7 @@
|
|||||||
onDateChange={handleDateChange}
|
onDateChange={handleDateChange}
|
||||||
onClearFilters={handleClearFilters}
|
onClearFilters={handleClearFilters}
|
||||||
defaultDate={partialDate || undefined}
|
defaultDate={partialDate || undefined}
|
||||||
|
{startYear}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user