=> {
let path: string;
let isFileTemporary: boolean;
let writeToTemporaryFile = async () => {
@@ -126,9 +126,7 @@ export const makeFileForDataOrStreamOrPathOrZipItem = async (
} else {
path = await makeTempFilePath();
isFileTemporary = true;
- if (item instanceof Uint8Array) {
- writeToTemporaryFile = () => fs.writeFile(path, item);
- } else if (item instanceof ReadableStream) {
+ if (item instanceof ReadableStream) {
writeToTemporaryFile = () => writeStream(path, item);
} else {
writeToTemporaryFile = async () => {
diff --git a/desktop/src/preload.ts b/desktop/src/preload.ts
index ef586210dd..ea6a7af7b2 100644
--- a/desktop/src/preload.ts
+++ b/desktop/src/preload.ts
@@ -69,6 +69,7 @@ import type {
FFmpegCommand,
FolderWatch,
PendingUploads,
+ UtilityProcessType,
ZipItem,
} from "./types/ipc";
@@ -112,10 +113,11 @@ const logout = () => {
return ipcRenderer.invoke("logout");
};
-const masterKeyB64 = () => ipcRenderer.invoke("masterKeyB64");
+const masterKeyFromSafeStorage = () =>
+ ipcRenderer.invoke("masterKeyFromSafeStorage");
-const saveMasterKeyB64 = (masterKeyB64: string) =>
- ipcRenderer.invoke("saveMasterKeyB64", masterKeyB64);
+const saveMasterKeyInSafeStorage = (masterKey: string) =>
+ ipcRenderer.invoke("saveMasterKeyInSafeStorage", masterKey);
const lastShownChangelogVersion = () =>
ipcRenderer.invoke("lastShownChangelogVersion");
@@ -192,41 +194,45 @@ const convertToJPEG = (imageData: Uint8Array) =>
ipcRenderer.invoke("convertToJPEG", imageData);
const generateImageThumbnail = (
- dataOrPathOrZipItem: Uint8Array | string | ZipItem,
+ pathOrZipItem: string | ZipItem,
maxDimension: number,
maxSize: number,
) =>
ipcRenderer.invoke(
"generateImageThumbnail",
- dataOrPathOrZipItem,
+ pathOrZipItem,
maxDimension,
maxSize,
);
const ffmpegExec = (
command: FFmpegCommand,
- dataOrPathOrZipItem: Uint8Array | string | ZipItem,
+ pathOrZipItem: string | ZipItem,
outputFileExtension: string,
) =>
ipcRenderer.invoke(
"ffmpegExec",
command,
- dataOrPathOrZipItem,
+ pathOrZipItem,
outputFileExtension,
);
-// - ML
+const ffmpegDetermineVideoDuration = (pathOrZipItem: string | ZipItem) =>
+ ipcRenderer.invoke("ffmpegDetermineVideoDuration", pathOrZipItem);
-const createMLWorker = () => {
+// - Utility processes
+
+const triggerCreateUtilityProcess = (type: UtilityProcessType) => {
+ const portEvent = `utilityProcessPort/${type}`;
const l = (event: IpcRendererEvent) => {
void windowLoaded.then(() => {
// "*"" is the origin to send to.
- window.postMessage("createMLWorker/port", "*", event.ports);
- ipcRenderer.off("createMLWorker/port", l);
+ window.postMessage(portEvent, "*", event.ports);
+ ipcRenderer.off(portEvent, l);
});
};
- ipcRenderer.on("createMLWorker/port", l);
- ipcRenderer.send("createMLWorker");
+ ipcRenderer.on(portEvent, l);
+ ipcRenderer.send("triggerCreateUtilityProcess", type);
};
// - Watch
@@ -353,8 +359,8 @@ contextBridge.exposeInMainWorld("electron", {
selectDirectory,
pathForFile,
logout,
- masterKeyB64,
- saveMasterKeyB64,
+ masterKeyFromSafeStorage,
+ saveMasterKeyInSafeStorage,
lastShownChangelogVersion,
setLastShownChangelogVersion,
isAutoLaunchEnabled,
@@ -390,10 +396,11 @@ contextBridge.exposeInMainWorld("electron", {
convertToJPEG,
generateImageThumbnail,
ffmpegExec,
+ ffmpegDetermineVideoDuration,
// - ML
- createMLWorker,
+ triggerCreateUtilityProcess,
// - Watch
diff --git a/desktop/src/types/ipc.ts b/desktop/src/types/ipc.ts
index 7701836217..db1d009f8b 100644
--- a/desktop/src/types/ipc.ts
+++ b/desktop/src/types/ipc.ts
@@ -5,6 +5,8 @@
* See [Note: types.ts <-> preload.ts <-> ipc.ts]
*/
+export type UtilityProcessType = "ml";
+
export interface AppUpdate {
autoUpdatable: boolean;
version: string;
diff --git a/desktop/yarn.lock b/desktop/yarn.lock
index 25b3a8f43a..4c00433d43 100644
--- a/desktop/yarn.lock
+++ b/desktop/yarn.lock
@@ -25,7 +25,7 @@
ajv "^6.12.0"
ajv-keywords "^3.4.1"
-"@electron/asar@3.4.1":
+"@electron/asar@3.4.1", "@electron/asar@^3.3.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.4.1.tgz#4e9196a4b54fba18c56cd8d5cac67c5bdc588065"
integrity sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==
@@ -34,15 +34,6 @@
glob "^7.1.6"
minimatch "^3.0.4"
-"@electron/asar@^3.2.7":
- version "3.2.18"
- resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.18.tgz#fa607f829209bab8b9e0ce6658d3fe81b2cba517"
- integrity sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==
- dependencies:
- commander "^5.0.0"
- glob "^7.1.6"
- minimatch "^3.0.4"
-
"@electron/fuses@^1.8.0":
version "1.8.0"
resolved "https://registry.yarnpkg.com/@electron/fuses/-/fuses-1.8.0.tgz#ad34d3cc4703b1258b83f6989917052cfc1490a0"
@@ -91,10 +82,10 @@
fs-extra "^9.0.1"
promise-retry "^2.0.1"
-"@electron/osx-sign@1.3.1":
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.3.1.tgz#faf7eeca7ca004a6be541dc4cf7a1bd59ec59b1c"
- integrity sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==
+"@electron/osx-sign@1.3.3":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@electron/osx-sign/-/osx-sign-1.3.3.tgz#af751510488318d9f7663694af85819690d75583"
+ integrity sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==
dependencies:
compare-version "^0.1.2"
debug "^4.3.4"
@@ -123,12 +114,12 @@
tar "^6.0.5"
yargs "^17.0.1"
-"@electron/universal@2.0.1":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-2.0.1.tgz#7b070ab355e02957388f3dbd68e2c3cd08c448ae"
- integrity sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==
+"@electron/universal@2.0.3":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@electron/universal/-/universal-2.0.3.tgz#1680df6ced8f128ca0ff24e29c2165d41d78b3ce"
+ integrity sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==
dependencies:
- "@electron/asar" "^3.2.7"
+ "@electron/asar" "^3.3.1"
"@malept/cross-spawn-promise" "^2.0.0"
debug "^4.3.1"
dir-compare "^4.2.0"
@@ -136,13 +127,20 @@
minimatch "^9.0.3"
plist "^3.1.0"
-"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
+"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
+"@eslint-community/eslint-utils@^4.7.0":
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a"
+ integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==
+ dependencies:
+ eslint-visitor-keys "^3.4.3"
+
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae"
@@ -177,10 +175,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.9.1.tgz#4a97e85e982099d6c7ee8410aacb55adaa576f06"
integrity sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==
-"@eslint/js@^9.25.1":
- version "9.25.1"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.25.1.tgz#25f5c930c2b68b5ebe7ac857f754cbd61ef6d117"
- integrity sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==
+"@eslint/js@^9.28.0":
+ version "9.28.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.28.0.tgz#7822ccc2f8cae7c3cd4f902377d520e9ae03f844"
+ integrity sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==
"@eslint/object-schema@^2.1.4":
version "2.1.4"
@@ -202,6 +200,18 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570"
integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==
+"@isaacs/balanced-match@^4.0.1":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29"
+ integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==
+
+"@isaacs/brace-expansion@^5.0.0":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3"
+ integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==
+ dependencies:
+ "@isaacs/balanced-match" "^4.0.1"
+
"@isaacs/fs-minipass@^4.0.0":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32"
@@ -268,10 +278,10 @@
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
-"@pkgr/core@^0.1.0":
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
- integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
+"@pkgr/core@^0.2.4":
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c"
+ integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==
"@sindresorhus/is@^4.0.0":
version "4.6.0"
@@ -290,10 +300,10 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
-"@tsconfig/node22@^22.0.1":
- version "22.0.1"
- resolved "https://registry.yarnpkg.com/@tsconfig/node22/-/node22-22.0.1.tgz#27e3ee9b359e31e5b94690bf2bad5a923c1d57d0"
- integrity sha512-VkgOa3n6jvs1p+r3DiwBqeEwGAwEvnVCg/hIjiANl5IEcqP3G0u5m8cBJspe1t9qjZRlZ7WFgqq5bJrGdgAKMg==
+"@tsconfig/node22@^22.0.2":
+ version "22.0.2"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node22/-/node22-22.0.2.tgz#1e04e2c5cc946dac787d69bb502462a851ae51b6"
+ integrity sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==
"@types/auto-launch@^5.0.5":
version "5.0.5"
@@ -385,85 +395,101 @@
dependencies:
"@types/node" "*"
-"@typescript-eslint/eslint-plugin@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz#62f1befe59647524994e89de4516d8dcba7a850a"
- integrity sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==
+"@typescript-eslint/eslint-plugin@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz#532641b416ed2afd5be893cddb2a58e9cd1f7a3e"
+ integrity sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==
dependencies:
"@eslint-community/regexpp" "^4.10.0"
- "@typescript-eslint/scope-manager" "8.31.1"
- "@typescript-eslint/type-utils" "8.31.1"
- "@typescript-eslint/utils" "8.31.1"
- "@typescript-eslint/visitor-keys" "8.31.1"
+ "@typescript-eslint/scope-manager" "8.33.1"
+ "@typescript-eslint/type-utils" "8.33.1"
+ "@typescript-eslint/utils" "8.33.1"
+ "@typescript-eslint/visitor-keys" "8.33.1"
graphemer "^1.4.0"
- ignore "^5.3.1"
+ ignore "^7.0.0"
natural-compare "^1.4.0"
- ts-api-utils "^2.0.1"
+ ts-api-utils "^2.1.0"
-"@typescript-eslint/parser@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.31.1.tgz#e9b0ccf30d37dde724ee4d15f4dbc195995cce1b"
- integrity sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==
+"@typescript-eslint/parser@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.33.1.tgz#ef9a5ee6aa37a6b4f46cc36d08a14f828238afe2"
+ integrity sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==
dependencies:
- "@typescript-eslint/scope-manager" "8.31.1"
- "@typescript-eslint/types" "8.31.1"
- "@typescript-eslint/typescript-estree" "8.31.1"
- "@typescript-eslint/visitor-keys" "8.31.1"
+ "@typescript-eslint/scope-manager" "8.33.1"
+ "@typescript-eslint/types" "8.33.1"
+ "@typescript-eslint/typescript-estree" "8.33.1"
+ "@typescript-eslint/visitor-keys" "8.33.1"
debug "^4.3.4"
-"@typescript-eslint/scope-manager@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz#1eb52e76878f545e4add142e0d8e3e97e7aa443b"
- integrity sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==
+"@typescript-eslint/project-service@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.33.1.tgz#c85e7d9a44d6a11fe64e73ac1ed47de55dc2bf9f"
+ integrity sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==
dependencies:
- "@typescript-eslint/types" "8.31.1"
- "@typescript-eslint/visitor-keys" "8.31.1"
-
-"@typescript-eslint/type-utils@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz#be0f438fb24b03568e282a0aed85f776409f970c"
- integrity sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==
- dependencies:
- "@typescript-eslint/typescript-estree" "8.31.1"
- "@typescript-eslint/utils" "8.31.1"
+ "@typescript-eslint/tsconfig-utils" "^8.33.1"
+ "@typescript-eslint/types" "^8.33.1"
debug "^4.3.4"
- ts-api-utils "^2.0.1"
-"@typescript-eslint/types@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.31.1.tgz#478ed6f7e8aee1be7b63a60212b6bffe1423b5d4"
- integrity sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==
-
-"@typescript-eslint/typescript-estree@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz#37792fe7ef4d3021c7580067c8f1ae66daabacdf"
- integrity sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==
+"@typescript-eslint/scope-manager@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz#d1e0efb296da5097d054bc9972e69878a2afea73"
+ integrity sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==
dependencies:
- "@typescript-eslint/types" "8.31.1"
- "@typescript-eslint/visitor-keys" "8.31.1"
+ "@typescript-eslint/types" "8.33.1"
+ "@typescript-eslint/visitor-keys" "8.33.1"
+
+"@typescript-eslint/tsconfig-utils@8.33.1", "@typescript-eslint/tsconfig-utils@^8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz#7836afcc097a4657a5ed56670851a450d8b70ab8"
+ integrity sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==
+
+"@typescript-eslint/type-utils@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz#d73ee1a29d8a0abe60d4abbff4f1d040f0de15fa"
+ integrity sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==
+ dependencies:
+ "@typescript-eslint/typescript-estree" "8.33.1"
+ "@typescript-eslint/utils" "8.33.1"
+ debug "^4.3.4"
+ ts-api-utils "^2.1.0"
+
+"@typescript-eslint/types@8.33.1", "@typescript-eslint/types@^8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.33.1.tgz#b693111bc2180f8098b68e9958cf63761657a55f"
+ integrity sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==
+
+"@typescript-eslint/typescript-estree@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz#d271beed470bc915b8764e22365d4925c2ea265d"
+ integrity sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==
+ dependencies:
+ "@typescript-eslint/project-service" "8.33.1"
+ "@typescript-eslint/tsconfig-utils" "8.33.1"
+ "@typescript-eslint/types" "8.33.1"
+ "@typescript-eslint/visitor-keys" "8.33.1"
debug "^4.3.4"
fast-glob "^3.3.2"
is-glob "^4.0.3"
minimatch "^9.0.4"
semver "^7.6.0"
- ts-api-utils "^2.0.1"
+ ts-api-utils "^2.1.0"
-"@typescript-eslint/utils@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.31.1.tgz#5628ea0393598a0b2f143d0fc6d019f0dee9dd14"
- integrity sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==
+"@typescript-eslint/utils@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.33.1.tgz#ea22f40d3553da090f928cf17907e963643d4b96"
+ integrity sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==
dependencies:
- "@eslint-community/eslint-utils" "^4.4.0"
- "@typescript-eslint/scope-manager" "8.31.1"
- "@typescript-eslint/types" "8.31.1"
- "@typescript-eslint/typescript-estree" "8.31.1"
+ "@eslint-community/eslint-utils" "^4.7.0"
+ "@typescript-eslint/scope-manager" "8.33.1"
+ "@typescript-eslint/types" "8.33.1"
+ "@typescript-eslint/typescript-estree" "8.33.1"
-"@typescript-eslint/visitor-keys@8.31.1":
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz#6742b0e3ba1e0c1e35bdaf78c03e759eb8dd8e75"
- integrity sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==
+"@typescript-eslint/visitor-keys@8.33.1":
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz#6c6e002c24d13211df3df851767f24dfdb4f42bc"
+ integrity sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==
dependencies:
- "@typescript-eslint/types" "8.31.1"
+ "@typescript-eslint/types" "8.33.1"
eslint-visitor-keys "^4.2.0"
"@xmldom/xmldom@^0.8.8":
@@ -569,44 +595,45 @@ app-builder-bin@5.0.0-alpha.12:
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz#2daf82f8badc698e0adcc95ba36af4ff0650dc80"
integrity sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==
-app-builder-lib@26.0.14:
- version "26.0.14"
- resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-26.0.14.tgz#a28fbefb600cf052d1259932f32289e043573f61"
- integrity sha512-nc/A9MUd95MCc7bR4yVW7Lhs9FZTA/l8QdV8PE1vZZOOiogK4dupBfCCJG0UqLU81JS62f078/bwAeuMjt3hfQ==
+app-builder-lib@26.0.17:
+ version "26.0.17"
+ resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-26.0.17.tgz#b23c3722482d3363328248967da3238a44c8da0c"
+ integrity sha512-fk8edQKtNVnjBUK0kvYEmpbgD3pn3zAwpisjor0KVZLe7kDtnHkaaczjuonshTW+eK1wHhS1W5P2Vv0/u9rwHQ==
dependencies:
"@develar/schema-utils" "~2.6.5"
"@electron/asar" "3.4.1"
"@electron/fuses" "^1.8.0"
"@electron/notarize" "2.5.0"
- "@electron/osx-sign" "1.3.1"
+ "@electron/osx-sign" "1.3.3"
"@electron/rebuild" "3.7.2"
- "@electron/universal" "2.0.1"
+ "@electron/universal" "2.0.3"
"@malept/flatpak-bundler" "^0.4.0"
"@types/fs-extra" "9.0.13"
async-exit-hook "^2.0.1"
- builder-util "26.0.13"
+ builder-util "26.0.17"
builder-util-runtime "9.3.2"
chromium-pickle-js "^0.2.0"
+ ci-info "^4.2.0"
config-file-ts "0.2.8-rc1"
debug "^4.3.4"
dotenv "^16.4.5"
dotenv-expand "^11.0.6"
ejs "^3.1.8"
- electron-publish "26.0.13"
+ electron-publish "26.0.17"
fs-extra "^10.1.0"
hosted-git-info "^4.1.0"
- is-ci "^3.0.0"
isbinaryfile "^5.0.0"
js-yaml "^4.1.0"
json5 "^2.2.3"
lazy-val "^1.0.5"
- minimatch "^10.0.0"
+ minimatch "^10.0.3"
plist "3.1.0"
resedit "^1.7.0"
semver "^7.3.8"
tar "^6.1.12"
temp-file "^3.4.0"
tiny-async-pool "1.3.0"
+ which "^5.0.0"
applescript@^1.0.0:
version "1.0.0"
@@ -736,22 +763,22 @@ builder-util-runtime@9.3.2:
debug "^4.3.4"
sax "^1.2.4"
-builder-util@26.0.13:
- version "26.0.13"
- resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-26.0.13.tgz#a2c11f8e89e5392719e540d610d70d8413943d74"
- integrity sha512-6b64uHzywaL2KAG+rVcqk/Prta1m3I2Jo1d4d2CrApb6EeSk2V384tmSL0EniH+P8jaNbMp6qhg7cIALw32zRA==
+builder-util@26.0.17:
+ version "26.0.17"
+ resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-26.0.17.tgz#2f000ae7789e0c7c8479397c99d0e25dec3b1d27"
+ integrity sha512-fym+vg0kegrHBSCmkYYql2EbsLvnlUhIUKRQJ7EHjyftwMz8mibpvTRll3pzK1rtWm/VRdjl7AB397jdtg/Jmw==
dependencies:
"7zip-bin" "~5.2.0"
"@types/debug" "^4.1.6"
app-builder-bin "5.0.0-alpha.12"
builder-util-runtime "9.3.2"
chalk "^4.1.2"
+ ci-info "^4.2.0"
cross-spawn "^7.0.6"
debug "^4.3.4"
fs-extra "^10.1.0"
http-proxy-agent "^7.0.0"
https-proxy-agent "^7.0.0"
- is-ci "^3.0.0"
js-yaml "^4.1.0"
sanitize-filename "^1.6.3"
source-map-support "^0.5.19"
@@ -841,10 +868,10 @@ chromium-pickle-js@^0.2.0:
resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205"
integrity sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==
-ci-info@^3.2.0:
- version "3.9.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
- integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
+ci-info@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.2.0.tgz#cbd21386152ebfe1d56f280a3b5feccbd96764c7"
+ integrity sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==
clean-stack@^2.0.0:
version "2.2.0"
@@ -1007,6 +1034,17 @@ cross-env@^7.0.3:
dependencies:
cross-spawn "^7.0.1"
+cross-spawn@^6.0.0:
+ version "6.0.6"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57"
+ integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==
+ dependencies:
+ nice-try "^1.0.4"
+ path-key "^2.0.1"
+ semver "^5.5.0"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
@@ -1087,7 +1125,7 @@ detect-libc@^2.0.1:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700"
integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
-detect-newline@^4.0.0:
+detect-newline@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-4.0.1.tgz#fcefdb5713e1fb8cb2839b8b6ee22e6716ab8f23"
integrity sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==
@@ -1105,13 +1143,13 @@ dir-compare@^4.2.0:
minimatch "^3.0.5"
p-limit "^3.1.0 "
-dmg-builder@26.0.14:
- version "26.0.14"
- resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-26.0.14.tgz#ce8180da319cf3ee05d42cd460a7509207ad474b"
- integrity sha512-0l7oEj175hee7NfnaUpb0zf7fsgh1SyHeLjDA0AtOMnBUfTGxPPwrifbUxfd73qzamrGNcyeqza+m/EJx3QUug==
+dmg-builder@26.0.17:
+ version "26.0.17"
+ resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-26.0.17.tgz#a7cf71fd0f752c8db65f196c91ede4b49d962ec4"
+ integrity sha512-ls+KKvW4u4/kSkPtdjkTpqSzuVGm90JWRrEulcR/Lu8rrEXaeTcXiesuo3/MWNeiEpwfFgNa8t/paQVH59lw7A==
dependencies:
- app-builder-lib "26.0.14"
- builder-util "26.0.13"
+ app-builder-lib "26.0.17"
+ builder-util "26.0.17"
builder-util-runtime "9.3.2"
fs-extra "^10.1.0"
iconv-lite "^0.6.2"
@@ -1159,18 +1197,18 @@ ejs@^3.1.8:
dependencies:
jake "^10.8.5"
-electron-builder@^26.0.14:
- version "26.0.14"
- resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.0.14.tgz#8927c6da42a69425d15e08f351e944ea0e7866da"
- integrity sha512-YBxpWLMGj0oS7fbS3LVingeZqFunU0F8s+uB9QTd5+wN4qgrf/rSGRkqoImbWg2+F2yHq11wmaA/Xr9xzvgQ0w==
+electron-builder@^26.0.17:
+ version "26.0.17"
+ resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.0.17.tgz#3e252d624aa16031b1c81686ca573180fa437e3d"
+ integrity sha512-PJbm3XAG9qje73j4iXi043F0JnzHEDP2y/MQBprW+zizZqT2DywTkFN14ryLt8aGkGnoYBP44Smccff0A2AafQ==
dependencies:
- app-builder-lib "26.0.14"
- builder-util "26.0.13"
+ app-builder-lib "26.0.17"
+ builder-util "26.0.17"
builder-util-runtime "9.3.2"
chalk "^4.1.2"
- dmg-builder "26.0.14"
+ ci-info "^4.2.0"
+ dmg-builder "26.0.17"
fs-extra "^10.1.0"
- is-ci "^3.0.0"
lazy-val "^1.0.5"
simple-update-notifier "2.0.0"
yargs "^17.6.2"
@@ -1180,13 +1218,13 @@ electron-log@^5.4.0:
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-5.4.0.tgz#3180bf5194b2e2efacb62ec1392f8150faf4de6b"
integrity sha512-AXI5OVppskrWxEAmCxuv8ovX+s2Br39CpCAgkGMNHQtjYT3IiVbSQTncEjFVGPgoH35ZygRm/mvUMBDWwhRxgg==
-electron-publish@26.0.13:
- version "26.0.13"
- resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-26.0.13.tgz#04340520e6e9de5262fecfa011658cfcc3fc8917"
- integrity sha512-O5hfHSwli5cegQ4JS3Dp0dZcheex6UCRE/qYyRQvhB6DhSwojiwTnAGEuQCJXc8K8Zxz2lku5Du3VwYHf8d5Lw==
+electron-publish@26.0.17:
+ version "26.0.17"
+ resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-26.0.17.tgz#c4ed32d39de5796b019fbe8058dd971a6b72371b"
+ integrity sha512-03hz7MEbzLmZpOCHB+TvoXvn3FW+bZyfgq2gCi4AaeqU6i8Jpx584CljFP8zuDbb0nJcN0uHhpvAWjufDkgyVg==
dependencies:
"@types/fs-extra" "^9.0.11"
- builder-util "26.0.13"
+ builder-util "26.0.17"
builder-util-runtime "9.3.2"
chalk "^4.1.2"
form-data "^4.0.0"
@@ -1202,10 +1240,10 @@ electron-store@^8.2.0:
conf "^10.2.0"
type-fest "^2.17.0"
-electron-updater@^6.6.3:
- version "6.6.3"
- resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.3.tgz#a1f53671ffbb08a475d495d48f0c0d971e665d5d"
- integrity sha512-i448/SwMtqxy5wqAcXScnWjiFxZp+hmWA2jZCmojcdfodEGhi/DWTdRP01mE3lCILb8hmdE28SBaHf1oQW3+kw==
+electron-updater@^6.6.5:
+ version "6.6.5"
+ resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.5.tgz#6614daa2f737c294471eee7ce7b61deda0d5543a"
+ integrity sha512-jnk38WfByl2Pb0cje02xls/pJkvkq3AQZI7usDCLriU23adkerLTkRrugbCPuUxUOa79nY1g/rokHPWHZFBKyA==
dependencies:
builder-util-runtime "9.3.2"
fs-extra "^10.1.0"
@@ -1216,10 +1254,10 @@ electron-updater@^6.6.3:
semver "^7.6.3"
tiny-typed-emitter "^2.1.0"
-electron@^36.1.0:
- version "36.1.0"
- resolved "https://registry.yarnpkg.com/electron/-/electron-36.1.0.tgz#9919b77e61cd1400acc6dd24f9db8451fba5f8eb"
- integrity sha512-gnp3BnbKdGsVc7cm1qlEaZc8pJsR08mIs8H/yTo8gHEtFkGGJbDTVZOYNAfbQlL0aXh+ozv+CnyiNeDNkT1Upg==
+electron@^36.4.0:
+ version "36.4.0"
+ resolved "https://registry.yarnpkg.com/electron/-/electron-36.4.0.tgz#9463bf5fa7565ae7be3a274f7f6a46359bcfe74d"
+ integrity sha512-LLOOZEuW5oqvnjC7HBQhIqjIIJAZCIFjQxltQGLfEC7XFsBoZgQ3u3iFj+Kzw68Xj97u1n57Jdt7P98qLvUibQ==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^22.7.7"
@@ -1289,7 +1327,7 @@ eslint-scope@^8.0.2:
esrecurse "^4.3.0"
estraverse "^5.2.0"
-eslint-visitor-keys@^3.3.0:
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
@@ -1372,6 +1410,19 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+execa@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
+ integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
+ dependencies:
+ cross-spawn "^6.0.0"
+ get-stream "^4.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
exponential-backoff@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6"
@@ -1438,10 +1489,10 @@ fd-slicer@~1.1.0:
dependencies:
pend "~1.2.0"
-fdir@^6.4.2:
- version "6.4.2"
- resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689"
- integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==
+fdir@^6.4.4:
+ version "6.4.4"
+ resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.4.tgz#1cfcf86f875a883e19a8fab53622cfe992e8d2f9"
+ integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==
ffmpeg-static@^5.2.0:
version "5.2.0"
@@ -1589,10 +1640,12 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
has-symbols "^1.0.3"
hasown "^2.0.0"
-get-stdin@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575"
- integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==
+get-stream@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
+ integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
+ dependencies:
+ pump "^3.0.0"
get-stream@^5.1.0:
version "5.2.0"
@@ -1601,10 +1654,10 @@ get-stream@^5.1.0:
dependencies:
pump "^3.0.0"
-git-hooks-list@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-3.1.0.tgz#386dc531dcc17474cf094743ff30987a3d3e70fc"
- integrity sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==
+git-hooks-list@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-4.1.1.tgz#ae340b82a9312354c73b48007f33840bbd83d3c0"
+ integrity sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA==
glob-parent@^5.1.2:
version "5.1.2"
@@ -1632,7 +1685,7 @@ glob@^10.3.12, glob@^10.3.7:
package-json-from-dist "^1.0.0"
path-scurry "^1.11.1"
-glob@^7.0.0, glob@^7.1.3, glob@^7.1.6:
+glob@^7.1.3, glob@^7.1.6:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@@ -1830,11 +1883,16 @@ ieee754@^1.1.13:
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-ignore@^5.2.0, ignore@^5.3.1:
+ignore@^5.2.0:
version "5.3.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
+ignore@^7.0.0:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.4.tgz#a12c70d0f2607c5bf508fb65a40c75f037d7a078"
+ integrity sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==
+
import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@@ -1884,13 +1942,6 @@ ip-address@^9.0.5:
jsbn "1.1.0"
sprintf-js "^1.1.3"
-is-ci@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867"
- integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==
- dependencies:
- ci-info "^3.2.0"
-
is-core-module@^2.13.0:
version "2.15.1"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37"
@@ -1945,6 +1996,11 @@ is-plain-obj@^4.1.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==
+is-stream@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+ integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
+
is-unicode-supported@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
@@ -1965,6 +2021,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+isexe@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d"
+ integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==
+
jackspeak@2.1.1, jackspeak@^3.1.2:
version "2.1.1"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd"
@@ -2216,12 +2277,12 @@ mimic-response@^3.1.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
-minimatch@^10.0.0:
- version "10.0.1"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b"
- integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==
+minimatch@^10.0.3:
+ version "10.0.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.3.tgz#cf7a0314a16c4d9ab73a7730a0e8e3c3502d47aa"
+ integrity sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==
dependencies:
- brace-expansion "^2.0.1"
+ "@isaacs/brace-expansion" "^5.0.0"
minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
@@ -2244,7 +2305,7 @@ minimatch@^9.0.3, minimatch@^9.0.4:
dependencies:
brace-expansion "^2.0.1"
-minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
+minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
@@ -2363,6 +2424,11 @@ next-electron-server@^1.0.0:
resolved "https://registry.yarnpkg.com/next-electron-server/-/next-electron-server-1.0.0.tgz#03e133ed64a5ef671b6c6409f908c4901b1828cb"
integrity sha512-fTUaHwT0Jry2fbdUSIkAiIqgDAInI5BJFF4/j90/okvZCYlyx6yxpXB30KpzmOG6TN/ESwyvsFJVvS2WHT8PAA==
+nice-try@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+ integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+
node-abi@^3.45.0:
version "3.67.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.67.0.tgz#1d159907f18d18e18809dbbb5df47ed2426a08df"
@@ -2399,6 +2465,13 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+npm-run-path@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+ integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==
+ dependencies:
+ path-key "^2.0.0"
+
object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@@ -2463,6 +2536,11 @@ p-cancelable@^2.0.0:
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
+p-finally@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+ integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
+
p-limit@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
@@ -2535,6 +2613,11 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+path-key@^2.0.0, path-key@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+ integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==
+
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
@@ -2599,13 +2682,13 @@ prettier-plugin-organize-imports@^4.1.0:
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz#f3d3764046a8e7ba6491431158b9be6ffd83b90f"
integrity sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==
-prettier-plugin-packagejson@^2.5.10:
- version "2.5.10"
- resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.10.tgz#f47068d0aa12efcdddb802189d8adae874ba00e7"
- integrity sha512-LUxATI5YsImIVSaaLJlJ3aE6wTD+nvots18U3GuQMJpUyClChaZlQrqx3dBnbhF20OnKWZyx8EgyZypQtBDtgQ==
+prettier-plugin-packagejson@^2.5.15:
+ version "2.5.15"
+ resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.15.tgz#7ea880d4bb1681b5331ea7044efd3d653776f469"
+ integrity sha512-2QSx6y4IT6LTwXtCvXAopENW5IP/aujC8fobEM2pDbs0IGkiVjW/ipPuYAHuXigbNe64aGWF7vIetukuzM3CBw==
dependencies:
- sort-package-json "2.15.1"
- synckit "0.9.2"
+ sort-package-json "3.2.1"
+ synckit "0.11.8"
prettier@3.5.3:
version "3.5.3"
@@ -2829,6 +2912,11 @@ semver@^7.3.2, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.6.0, semve
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
+semver@^7.7.1:
+ version "7.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
+ integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
+
serialize-error@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18"
@@ -2836,6 +2924,13 @@ serialize-error@^7.0.1:
dependencies:
type-fest "^0.13.1"
+shebang-command@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+ integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==
+ dependencies:
+ shebang-regex "^1.0.0"
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -2843,6 +2938,11 @@ shebang-command@^2.0.0:
dependencies:
shebang-regex "^3.0.0"
+shebang-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+ integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==
+
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
@@ -2853,24 +2953,25 @@ shell-quote@^1.8.1:
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
-shelljs@^0.8.5:
- version "0.8.5"
- resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
- integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
+shelljs@^0.9.2:
+ version "0.9.2"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.9.2.tgz#a8ac724434520cd7ae24d52071e37a18ac2bb183"
+ integrity sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==
dependencies:
- glob "^7.0.0"
+ execa "^1.0.0"
+ fast-glob "^3.3.2"
interpret "^1.0.0"
rechoir "^0.6.2"
-shx@^0.3.4:
- version "0.3.4"
- resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.4.tgz#74289230b4b663979167f94e1935901406e40f02"
- integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==
+shx@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/shx/-/shx-0.4.0.tgz#c6ea6ace7e778da0ab32d2eab9def59d788e9336"
+ integrity sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA==
dependencies:
- minimist "^1.2.3"
- shelljs "^0.8.5"
+ minimist "^1.2.8"
+ shelljs "^0.9.2"
-signal-exit@^3.0.2:
+signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
@@ -2923,19 +3024,18 @@ sort-object-keys@^1.1.3:
resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
-sort-package-json@2.15.1:
- version "2.15.1"
- resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.15.1.tgz#e5a035fad7da277b1947b9eecc93ea09c1c2526e"
- integrity sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA==
+sort-package-json@3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-3.2.1.tgz#889f3bdf43ceeff5fa4278a7c53ae5b1520d287e"
+ integrity sha512-rTfRdb20vuoAn7LDlEtCqOkYfl2X+Qze6cLbNOzcDpbmKEhJI30tTN44d5shbKJnXsvz24QQhlCm81Bag7EOKg==
dependencies:
detect-indent "^7.0.1"
- detect-newline "^4.0.0"
- get-stdin "^9.0.0"
- git-hooks-list "^3.0.0"
+ detect-newline "^4.0.1"
+ git-hooks-list "^4.0.0"
is-plain-obj "^4.1.0"
- semver "^7.6.0"
+ semver "^7.7.1"
sort-object-keys "^1.1.3"
- tinyglobby "^0.2.9"
+ tinyglobby "^0.2.12"
source-map-support@^0.5.19:
version "0.5.21"
@@ -2990,6 +3090,11 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
dependencies:
ansi-regex "^5.0.1"
+strip-eof@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+ integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==
+
strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
@@ -3021,13 +3126,12 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-synckit@0.9.2:
- version "0.9.2"
- resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62"
- integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==
+synckit@0.11.8:
+ version "0.11.8"
+ resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457"
+ integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==
dependencies:
- "@pkgr/core" "^0.1.0"
- tslib "^2.6.2"
+ "@pkgr/core" "^0.2.4"
tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.2.1:
version "6.2.1"
@@ -3078,12 +3182,12 @@ tiny-typed-emitter@^2.1.0:
resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5"
integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==
-tinyglobby@^0.2.9:
- version "0.2.10"
- resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f"
- integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==
+tinyglobby@^0.2.12:
+ version "0.2.13"
+ resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.13.tgz#a0e46515ce6cbcd65331537e57484af5a7b2ff7e"
+ integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==
dependencies:
- fdir "^6.4.2"
+ fdir "^6.4.4"
picomatch "^4.0.2"
tmp-promise@^3.0.2:
@@ -3117,12 +3221,12 @@ truncate-utf8-bytes@^1.0.0:
dependencies:
utf8-byte-length "^1.0.1"
-ts-api-utils@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd"
- integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==
+ts-api-utils@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91"
+ integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
-tslib@^2.1.0, tslib@^2.6.2:
+tslib@^2.1.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
@@ -3149,14 +3253,14 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
-typescript-eslint@^8.31.1:
- version "8.31.1"
- resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.31.1.tgz#b77ab1e48ced2daab9225ff94bab54391a4af69b"
- integrity sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==
+typescript-eslint@^8.33.1:
+ version "8.33.1"
+ resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.33.1.tgz#d2d59c9b24afe1f903a855b02145802e4ae930ff"
+ integrity sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==
dependencies:
- "@typescript-eslint/eslint-plugin" "8.31.1"
- "@typescript-eslint/parser" "8.31.1"
- "@typescript-eslint/utils" "8.31.1"
+ "@typescript-eslint/eslint-plugin" "8.33.1"
+ "@typescript-eslint/parser" "8.33.1"
+ "@typescript-eslint/utils" "8.33.1"
typescript@^5.4.3, typescript@^5.8.3:
version "5.8.3"
@@ -3230,6 +3334,13 @@ wcwidth@^1.0.1:
dependencies:
defaults "^1.0.3"
+which@^1.2.9:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
which@^2.0.1, which@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
@@ -3237,6 +3348,13 @@ which@^2.0.1, which@^2.0.2:
dependencies:
isexe "^2.0.0"
+which@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/which/-/which-5.0.0.tgz#d93f2d93f79834d4363c7d0c23e00d07c466c8d6"
+ integrity sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==
+ dependencies:
+ isexe "^3.1.1"
+
winreg@1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
@@ -3311,3 +3429,8 @@ yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+zod@^3.25.51:
+ version "3.25.51"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.51.tgz#aa2cf648e54f6f060f139cf77b694819f63c9f3a"
+ integrity sha512-TQSnBldh+XSGL+opiSIq0575wvDPqu09AqWe1F7JhUMKY+M91/aGlK4MhpVNO7MgYfHcVCB1ffwAUTJzllKJqg==
diff --git a/docs/docs/.vitepress/config.ts b/docs/docs/.vitepress/config.ts
index a2df3c23a1..4914ab6251 100644
--- a/docs/docs/.vitepress/config.ts
+++ b/docs/docs/.vitepress/config.ts
@@ -8,13 +8,6 @@ export default defineConfig({
head: [["link", { rel: "icon", type: "image/png", href: "/favicon.png" }]],
cleanUrls: true,
ignoreDeadLinks: "localhostLinks",
- vite: {
- build: {
- rollupOptions: {
- external: ['client-museum-s3.png'] // Added to handle static asset import
- }
- }
- },
themeConfig: {
// We use the default theme (with some CSS color overrides). This
// themeConfig block can be used to further customize the default theme.
diff --git a/docs/docs/.vitepress/sidebar.ts b/docs/docs/.vitepress/sidebar.ts
index 02b8fdc5e9..a90caad19b 100644
--- a/docs/docs/.vitepress/sidebar.ts
+++ b/docs/docs/.vitepress/sidebar.ts
@@ -52,6 +52,10 @@ export const sidebar = [
link: "/photos/features/machine-learning",
},
{ text: "Map", link: "/photos/features/map" },
+ {
+ text: "Notifications",
+ link: "/photos/features/notifications",
+ },
{
text: "Passkeys",
link: "/photos/features/passkeys",
@@ -264,34 +268,27 @@ export const sidebar = [
collapsed: true,
items: [
{ text: "Introduction", link: "/self-hosting/guides/" },
- {
- text: "Hosting Ente from source",
- link: "/self-hosting/guides/from-source",
- },
- {
- text: "Hosting Ente without Docker",
- link: "/self-hosting/guides/standalone-ente",
- },
{
text: "Administering your server",
link: "/self-hosting/guides/admin",
},
{
- text: "Configure CLI for self hosted instance",
+ text: "Configuring CLI for your instance",
link: "/self-hosting/guides/selfhost-cli",
},
{
- text: "DB migration",
- link: "/self-hosting/guides/db-migration",
+ text: "Running Ente from source",
+ link: "/self-hosting/guides/from-source",
},
{
- text: "Mobile build",
- link: "/self-hosting/guides/mobile-build",
+ text: "Running Ente without Docker",
+ link: "/self-hosting/guides/standalone-ente",
},
],
},
{
text: "Troubleshooting",
+ collapsed: true,
items: [
{
text: "General",
@@ -299,7 +296,7 @@ export const sidebar = [
},
{
text: "Bucket CORS",
- link: '/self-hosting/troubleshooting/bucket-cors'
+ link: "/self-hosting/troubleshooting/bucket-cors",
},
{
text: "Uploads",
@@ -309,10 +306,6 @@ export const sidebar = [
text: "Docker / quickstart",
link: "/self-hosting/troubleshooting/docker",
},
- {
- text: "Yarn",
- link: "/self-hosting/troubleshooting/yarn",
- },
{
text: "Ente CLI secrets",
link: "/self-hosting/troubleshooting/keyring",
@@ -321,19 +314,21 @@ export const sidebar = [
},
{
text: "Community Guides",
- items :[
+ collapsed: true,
+ items: [
{
text: "Ente via Tailscale",
- link: "/self-hosting/guides/Tailscale",
+ link: "/self-hosting/guides/tailscale",
},
{
text: "Ente with External S3",
link: "/self-hosting/guides/external-s3",
- }
- ]
+ },
+ ],
},
{
text: "FAQ",
+ collapsed: true,
items: [
{ text: "General", link: "/self-hosting/faq/" },
{
@@ -348,16 +343,12 @@ export const sidebar = [
text: "Backups",
link: "/self-hosting/faq/backup",
},
+ {
+ text: "Environment variables",
+ link: "/self-hosting/faq/environment",
+ },
],
},
],
},
- {
- text: "About",
- link: "/about/",
- },
- {
- text: "Contribute",
- link: "/about/contribute",
- },
];
diff --git a/docs/docs/about/contribute.md b/docs/docs/about/contribute.md
deleted file mode 100644
index 3addd2e606..0000000000
--- a/docs/docs/about/contribute.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Contribute
-description: Details about how to contribute to Ente's docs
----
-
-# Contributing
-
-To contribute to these docs, you can use the "Edit this page" button at the
-bottom of each page. This will allow you to directly edit the markdown file that
-is used to generate this documentation and open a quick pull request directly
-from GitHub's UI.
-
-If you're more comfortable in contributing with your text editor, see the
-`docs/` folder of our GitHub repository,
-[github.com/ente-io/ente](https://github.com/ente-io/ente).
diff --git a/docs/docs/about/index.md b/docs/docs/about/index.md
deleted file mode 100644
index 18455f6b5a..0000000000
--- a/docs/docs/about/index.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title: About Ente
-description: >
- An overview of Ente: the company, and the people behind it, and the products
- that we make.
----
-
-# About
-
-Ente is a end-to-end encrypted platform for privately, reliably, and securely
-storing your data on the cloud. On top of this platform, Ente offers two
-products:
-
-- **Ente Photos** - An alternative to Google Photos and Apple Photos
-
-- **Ente Auth** - A free 2FA alternative to Authy
-
-Both these apps are available for all desktop (Linux, Mac, Windows) and mobile
-(Android, iOS and F-Droid) platforms. They also work directly in your web
-browser without you needing to install anything.
-
-More products are in the pipeline.
-
-## History
-
-Ente was the founded by Vishnu Mohandas (he's also Ente's CEO) in response to
-privacy concerns with major tech companies. The underlying motivation was the
-understanding that big tech had no incentive to fix their act, but with
-end-to-end encrypted cross platform apps, there was a way for people to take
-back control over their own data without sacrificing on features.
-
-### What does Ente mean?
-
-In Malayalam, Vishnu's native language, "ente" means "mine". Thus "Ente Photos"
-has the literal meaning "my photos".
-
-This was a good name, but still Vishnu looked around for better ones. But one
-day, he discovered that "ente" means "duck" in German. This unexpected
-connection sealed the deal. We should ask him why he likes ducks so much, but
-apparently he does, so this dual meaning ("mine" / "duck") led him to finalize
-the name, and also led to the adoption of "Ducky", Ente's mascot:
-
-
-
-{width=200px}
-
-
-
-For the full origin story of Ducky you can check out
-[this blog post](https://ente.io/blog/ducky/).
-
-### How do I pronounce Ente?
-
-en-_tay_. Like cafe.
-
-## Get in touch
-
-If you have a support query that is not answered by these docs, please reach out
-to our Customer Support by sending an email to support@ente.io
-
-To stay up to date with new product launches, and behind the scenes details of
-how we're building Ente, you can read our [blog](https://ente.io/blog) (or
-subscribe to it via [RSS](https://ente.io/blog/rss.xml))
-
-To suggest new features and/or offer your perspective on how we should design
-planned and upcoming features, use our
-[GitHub discussions](https://github.com/ente-io/ente/discussions)
-
-Or if you'd just like to hang out, join our
-[Discord](https://discord.gg/z2YVKkycX3), follow us on
-[Twitter](https://twitter.com/enteio) or give us a shout out on
-[Mastodon](https://mstdn.social/@ente)
diff --git a/docs/docs/auth/faq/index.md b/docs/docs/auth/faq/index.md
index 5e631906aa..b731fa573e 100644
--- a/docs/docs/auth/faq/index.md
+++ b/docs/docs/auth/faq/index.md
@@ -41,6 +41,16 @@ Usually, this discrepancy occurs because the time in your browser might be
incorrect. In particular, multiple users have reported that Firefox provides
incorrect time when certain privacy settings are enabled.
+> [!TIP]
+>
+> Newer Ente Auth clients (upcoming 4.4.0+) will automatically try to correct
+> for incorrect system time, so you should be seeing correct codes even if your
+> system time is out of sync. However, this automatic correction will not work
+> if you're using Ente Auth in offline mode.
+>
+> If you've recently changed your system time and the codes are still incorrect,
+> try to refresh / restart the app if needed.
+
### Can I access my codes on web?
You can access your codes on the web at [auth.ente.io](https://auth.ente.io).
diff --git a/docs/docs/auth/migration-guides/authy/index.md b/docs/docs/auth/migration-guides/authy/index.md
index 27baa97ab1..724fbdc1d2 100644
--- a/docs/docs/auth/migration-guides/authy/index.md
+++ b/docs/docs/auth/migration-guides/authy/index.md
@@ -10,8 +10,9 @@ A guide written by Green, an ente.io lover
> [!WARNING]
>
> Authy has dropped all support for its desktop apps. It is no longer possible
-> to export data from Authy using methods 1 and 2. You will need either an iOS device
-> and computer (method 4) or a rooted Android phone (method 3) to follow this guide.
+> to export data from Authy using methods 1 and 2. You will need either an iOS
+> device and computer (method 4) or a rooted Android phone (method 3) to follow
+> this guide.
---
@@ -204,11 +205,24 @@ This uses the tool [Aegis Authenticator](https://getaegis.app/) from
## Method 4: Authy-iOS-MiTM
-**Who should use this?** Technical iOS users of Authy that cannot export their tokens with methods 1 or 2 (due to those methods being patched) or method 3 (due to that method requiring a rooted Android device).
+**Who should use this?** Technical iOS users of Authy that cannot export their
+tokens with methods 1 or 2 (due to those methods being patched) or method 3 (due
+to that method requiring a rooted Android device).
-This method works by intercepting the data the Authy app receives while logging in for the first time, which contains your encrypted authenticator tokens. After the encrypted authenticator tokens are dumped, you can decrypt them using your backup password and convert them to an Ente token file.
+This method works by intercepting the data the Authy app receives while logging
+in for the first time, which contains your encrypted authenticator tokens. After
+the encrypted authenticator tokens are dumped, you can decrypt them using your
+backup password and convert them to an Ente token file.
-For an up-to-date guide of how to retrieve the encrypted authenticator tokens and decrypt them, please see [Authy-iOS-MiTM](https://github.com/AlexTech01/Authy-iOS-MiTM). To convert the `decrypted_tokens.json` file from that guide into a format Ente Authenticator can recognize, use [this](https://gist.github.com/gboudreau/94bb0c11a6209c82418d01a59d958c93?permalink_comment_id=5317087#gistcomment-5317087) Python script. Once you have the `ente_auth_import.plain` file from that script, transfer it to your device and follow the instructions below to import it into Ente Authenticator.
+For an up-to-date guide of how to retrieve the encrypted authenticator tokens
+and decrypt them, please see
+[Authy-iOS-MiTM](https://github.com/AlexTech01/Authy-iOS-MiTM). To convert the
+`decrypted_tokens.json` file from that guide into a format Ente Authenticator
+can recognize, use
+[this](https://gist.github.com/gboudreau/94bb0c11a6209c82418d01a59d958c93?permalink_comment_id=5317087#gistcomment-5317087)
+Python script. Once you have the `ente_auth_import.plain` file from that script,
+transfer it to your device and follow the instructions below to import it into
+Ente Authenticator.
## Importing to Ente Authenticator (Method 1, method 2.1, method 4)
diff --git a/docs/docs/de/auth/index.md b/docs/docs/de/auth/index.md
index 1948a9126d..cb96f33738 100644
--- a/docs/docs/de/auth/index.md
+++ b/docs/docs/de/auth/index.md
@@ -10,4 +10,4 @@ Ende-zu-Ende-verschlüsselte Authenticator-App für jedermann. Wir sind froh, da
du hier bist!
**Please note that this German translation is currently just a placeholder.**
-Know German? [Help us fill this in!](/about/contribute).
+Know German? [Help us fill this in!](/#contribute).
diff --git a/docs/docs/index.md b/docs/docs/index.md
index af5fd2cddf..6bf6d18275 100644
--- a/docs/docs/index.md
+++ b/docs/docs/index.md
@@ -1,15 +1,82 @@
---
title: Home
+description: >
+ Introduction to Ente: Products, Community and Support
---
# Welcome!
-This site contains documentation and help for Ente Photos and Ente Auth. It
-describes various features, and also offers various troubleshooting suggestions.
+{width=50% style="margin: 0 auto"}
-Use the **sidebar** menu to navigate to information about the product (Photos or
-Auth) you'd like to know more about. Or use the **search** at the top to try and
-jump directly to page that might contain the information you need.
+## Introduction
-To know more about Ente, see [about](/about/) or visit our website
-[ente.io](https://ente.io).
+Ente (pronounced en-_tay_) is a end-to-end encrypted platform for privately,
+reliably, and securely storing your data on the cloud, over which 2 applications
+have been developed and made available for mobile, web and desktop, namely:
+
+- **Ente Photos** - An alternative to Google Photos and Apple Photos
+- **Ente Auth** - A free 2FA alternative to Authy
+
+## History
+
+Ente was the founded by Vishnu Mohandas (he's also Ente's CEO) in response to
+privacy concerns with major tech companies. The underlying motivation was the
+understanding that big tech had no incentive to fix their act, but with
+end-to-end encrypted cross platform apps, there was a way for people to take
+back control over their own data without sacrificing on features.
+
+### Origin of the name
+
+In Malayalam, Vishnu's native language, "ente" means "mine", thus "Ente Photos"
+literally means "my photos".
+
+But one day, he discovered that "ente" means "duck" in German. This unexpected
+connection sealed the deal after looking for alternative names and led to the
+adoption of ["Ducky"](https://ente.io/blog/ducky/), representing the playfulness
+and friendly nature of the community and team.
+
+## Getting Started
+
+We recommend reading the documentation for [Ente Photos](/photos/) or
+[Ente Auth](/auth/) to get started with installation on the desired platform,
+explore available features and usage.
+
+If you are looking to self-host Ente, we recommend you to read the
+[official documentation](/self-hosting/) for updated information on getting
+started, installation, administration and maintenance.
+
+## Contributing
+
+There are many ways to support Ente and you don't have to be a programmer for
+that. You can spread the word, give feedback, report bugs, help us with
+translations, contribute documentation and community guides and more.
+
+To suggest new features and/or offer your perspective on how we should design
+(planned and upcoming features), use our
+[GitHub discussions](https://github.com/ente-io/ente/discussions)
+
+You can find our contribution guidelines
+[here](https://github.com/ente-io/ente/blob/main/CONTRIBUTING.md).
+
+You can always engage with our community and team to hang out, answer queries
+and stay updated:
+
+- Chat: [Discord](https://ente.io/discord)
+- Discussions: [GitHub](https://github.com/ente-io/ente/discussions)
+- Socials:
+ - Twitter: [enteio](https://twitter.com/enteio)
+ - Mastodon: [@ente@fosstodon.org](https://fosstodon.org/@ente)
+ - Bluesky: [ente.io](https://bsky.app/profile/ente.io)
+ - Instagram: [ente.app](https://www.instagram.com/ente.app)
+- Website:
+ - [Blog](https://ente.io/blog)
+ - [RSS](https://ente.io/blog/rss.xml)
+
+## Getting Help
+
+If you encounter any issues with any of the products that's not answered by our
+documentation, please reach out to our team by sending an email to
+[support@ente.io](mailto:support@ente.io)
+
+For community support, please post your queries on
+[Discord](https://discord.gg/z2YVKkycX3)
diff --git a/docs/docs/photos/faq/desktop.md b/docs/docs/photos/faq/desktop.md
index 71a575bdfb..c0ef805584 100644
--- a/docs/docs/photos/faq/desktop.md
+++ b/docs/docs/photos/faq/desktop.md
@@ -1,6 +1,7 @@
---
title: Desktop app FAQ
-description: An assortment of frequently asked questions about Ente Photos desktop app
+description:
+ An assortment of frequently asked questions about Ente Photos desktop app
---
# Desktop app FAQ
@@ -15,7 +16,8 @@ to manually update the software.
### Upload errors
-**How do I identify which files experienced upload issues within the desktop app?**
+**How do I identify which files experienced upload issues within the desktop
+app?**
Check the sections within the upload progress bar for "Failed Uploads," "Ignored
Uploads," and "Unsuccessful Uploads."
@@ -33,6 +35,5 @@ be specific to your distro (e.g. `xdg-desktop-menu forceupdate`).
> [!NOTE]
>
-> If you're using an AppImage and not seeing the icon, you'll need to [enable
-> AppImage desktop
-> integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration).
+> If you're using an AppImage and not seeing the icon, you'll need to
+> [enable AppImage desktop integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration).
diff --git a/docs/docs/photos/faq/export.md b/docs/docs/photos/faq/export.md
index 16879ee327..5f37640f83 100644
--- a/docs/docs/photos/faq/export.md
+++ b/docs/docs/photos/faq/export.md
@@ -7,9 +7,10 @@ description: Frequently asked questions about keeping extra backups of your data
## How can I backup my data in a local drive outside Ente?
-You can use our CLI tool or our desktop app to set up exports of your data
-to your local drive. This way, you can use Ente in your day to day use, with an additional guarantee that a copy of your original photos and videos are
-always available on your machine.
+You can use our CLI tool or our desktop app to set up exports of your data to
+your local drive. This way, you can use Ente in your day to day use, with an
+additional guarantee that a copy of your original photos and videos are always
+available on your machine.
- You can use [Ente's CLI](https://github.com/ente-io/ente/tree/main/cli#export)
to export your data in a cron job to a location of your choice. The exports
@@ -21,7 +22,7 @@ always available on your machine.
background without you needing to run any other cron jobs. See
[migration/export](/photos/migration/export/) for more details.
-## Does the exported data preserve folder structure?
+## Does the exported data preserve album structure?
Yes. When you export your data for local backup, it will maintain the exact
album structure how you have set up within Ente.
diff --git a/docs/docs/photos/faq/face-recognition.md b/docs/docs/photos/faq/face-recognition.md
index 24c9650345..8559bf310d 100644
--- a/docs/docs/photos/faq/face-recognition.md
+++ b/docs/docs/photos/faq/face-recognition.md
@@ -1,7 +1,6 @@
---
title: Face recognition
-description:
- Frequently asked questions about Ente's face recognition
+description: Frequently asked questions about Ente's face recognition
---
# Face recognition
diff --git a/docs/docs/photos/faq/general.md b/docs/docs/photos/faq/general.md
index d45bf292f7..040a7e1bfa 100644
--- a/docs/docs/photos/faq/general.md
+++ b/docs/docs/photos/faq/general.md
@@ -26,10 +26,6 @@ unsupported file format and we will do our best to help you out.
Yes, we currently do not support files larger than 4 GB.
-If this constraint is a concern for you, please write to
-[support@ente.io](mailto:support@ente.io) with your use case and we will do our
-best to help you.
-
## Does Ente support videos?
Ente supports backing up and downloading of videos in their original format and
@@ -104,29 +100,53 @@ clicking on "Your map" under "Locations" on the search screen.
## How to reset my password if I lost it?
-On the login page, enter your email and click on Forgot Password. Then, enter your recovery key and create a new password.
+On the login page, enter your email and click on Forgot Password. Then, enter
+your recovery key and create a new password.
- # iOS Album Backup and Organization in Ente
+## Can I search for photos using the descriptions I’ve added?
- ### How does Ente handle photos that are part of multiple iOS albums?
-When you select multiple albums for backup, Ente prioritizes uploading each photo to the album with the fewest photos. This means a photo will only be uploaded once, even if it exists in multiple albums on your device. If you create new albums on your device after the initial backup, those photos may not appear in the corresponding Ente album if they were already uploaded to a different album.
+Yes, descriptions are searchable, making it easier to find specific photos
+later. To do this, open the photo, tap the (i) button, and enter your
+description.
+## How does the deduplication feature work on the desktop app?
-### Why don’t all photos from a new iOS album appear in the corresponding Ente album?
-If you create a new album on your device after the initial backup, the photos in that album may have already been uploaded to another album in Ente. To fix this, go to the "On Device" album in Ente, select all photos, and manually add them to the corresponding album in Ente.
+If the app finds exact duplicates, it will show them in the deduplication. When
+you delete a duplicate, the app keeps one copy and creates a symlink for the
+other duplicate. This helps save storage space.
-### What happens if I reorganize my photos in the iOS Photos app after backing up?
-Reorganizing photos in the iOS Photos app (e.g., moving photos to new albums) won’t automatically reflect in Ente. You’ll need to manually add those photos to the corresponding albums in Ente to maintain consistency.
+## What happens if I lose access to my email address? Can I use my recovery key to bypass email verification?
-### Can I search for photos using the descriptions I’ve added?
-Yes, descriptions are searchable, making it easier to find specific photos later.
-To do this, open the photo, tap the (i) button, and enter your description.
-
-### How does the deduplication feature work on the desktop app?
-If the app finds exact duplicates, it will show them in the deduplication. When you delete a duplicate, the app keeps one copy and creates a symlink for the other duplicate. This helps save storage space.
-
-### What happens if I lose access to my email address? Can I use my recovery key to bypass email verification?
-No, the recovery key does not bypass email verification. For security reasons, we do not disable or bypass email verification unless the account owner reaches out to us and successfully verifies their identity by providing details about their account.
+No, the recovery key does not bypass email verification. For security reasons,
+we do not disable or bypass email verification unless the account owner reaches
+out to us and successfully verifies their identity by providing details about
+their account.
If you lose access to your email, please contact our support team at
support@ente.io
+
+---
+
+# iOS Album Backup and Organization in Ente
+
+## How does Ente handle photos that are part of multiple iOS albums?
+
+When you select multiple albums for backup, Ente prioritizes uploading each
+photo to the album with the fewest photos. This means a photo will only be
+uploaded once, even if it exists in multiple albums on your device. If you
+create new albums on your device after the initial backup, those photos may not
+appear in the corresponding Ente album if they were already uploaded to a
+different album.
+
+## Why don’t all photos from a new iOS album appear in the corresponding Ente album?
+
+If you create a new album on your device after the initial backup, the photos in
+that album may have already been uploaded to another album in Ente. To fix this,
+go to the "On Device" album in Ente, select all photos, and manually add them to
+the corresponding album in Ente.
+
+## What happens if I reorganize my photos in the iOS Photos app after backing up?
+
+Reorganizing photos in the iOS Photos app (e.g., moving photos to new albums)
+won’t automatically reflect in Ente. You’ll need to manually add those photos to
+the corresponding albums in Ente to maintain consistency.
diff --git a/docs/docs/photos/faq/metadata.md b/docs/docs/photos/faq/metadata.md
index 03cf10da65..c7e122301b 100644
--- a/docs/docs/photos/faq/metadata.md
+++ b/docs/docs/photos/faq/metadata.md
@@ -62,6 +62,7 @@ the upload time as the photo's creation time.
## Modifications
Ente supports modifications to the following metadata:
+
- File name
- Date & time
- Location
diff --git a/docs/docs/photos/faq/video-streaming.md b/docs/docs/photos/faq/video-streaming.md
index 59a34907f6..62d9764dbb 100644
--- a/docs/docs/photos/faq/video-streaming.md
+++ b/docs/docs/photos/faq/video-streaming.md
@@ -1,29 +1,49 @@
---
title: Video streaming FAQ
-description:
- Frequently asked questions about Ente's video streaming feature
+description: Frequently asked questions about Ente's video streaming feature
---
# Video streaming
> [!NOTE]
>
-> Video streaming is available in beta on mobile apps starting v0.9.98.
+> Video streaming is available in beta on mobile apps starting v0.9.98 and on
+> desktop starting v1.7.13.
### How to enable video streaming?
+#### On mobile
+
- Open Settings -> General -> Advanced
-- Switch on the toggle for `Video streaming`
+- Enable the toggle for `Streamable videos`
+
+#### On desktop
+
+- Open Settings -> Preferences
+- Enable the toggle for `Streamable videos`
### What happens when I enable video streaming?
+#### On mobile
+
Enabling video streaming will start processing videos captured in the last 30
days, generating streams for each. Both local and remote videos will be
processed, so this may consume bandwidth for downloading of remote files and
uploading of the generated streams.
+#### On desktop
+
+When enabled, the desktop app will generate streams both for new uploads, and
+also for all existing videos that were previously uploaded.
+
+Stream generation is CPU intensive and can take time so the app will continue
+processing them in the background. Clicking on search bar will show "Processing
+videos..." when stream generation is happening.
+
### How can I view video streams?
+### On mobile
+
Settings -> Backup > Backup status will show details regarding the processing
status for videos. Processed videos will have a green play button next to them.
You can open these videos by tapping on them.
@@ -34,6 +54,12 @@ play the stream.
Clicking on the `Info` icon within the original video will show details about
the generated stream.
+### On desktop and web
+
+Desktop and web app will automatically play the streaming version of a video if
+it has been already generated. The quality selector will show "Auto" when
+playing the stream.
+
### What is a stream?
Stream is an encrypted HLS file with an `.m3u8` playlist that helps play a video
@@ -51,6 +77,7 @@ generated stream.
While this feature is in beta, we will not count the storage consumed by your
streams against your storage quota. This may change in the future. If it does,
we will provide an option to opt-in to one of the following:
+
1. Original videos only
2. Compressed streams only
3. Both
diff --git a/docs/docs/photos/features/background.md b/docs/docs/photos/features/background.md
index ffed413f74..2decf9cb65 100644
--- a/docs/docs/photos/features/background.md
+++ b/docs/docs/photos/features/background.md
@@ -43,8 +43,8 @@ need to disable this "Optimize battery usage" mode in the system settings for
Ente if you wish for Ente to automatically back up your photos in the
background.
-On Android versions 15 and later, if an app is in private space and the private
-space is locked, Android doesn’t allow the app to run any background processes.
+On Android versions 15 and later, if an app is in private space and the private
+space is locked, Android doesn’t allow the app to run any background processes.
As a result, background sync will not work.
### Desktop
diff --git a/docs/docs/photos/features/deduplicate.md b/docs/docs/photos/features/deduplicate.md
index c1b55e4cc7..ea931d174d 100644
--- a/docs/docs/photos/features/deduplicate.md
+++ b/docs/docs/photos/features/deduplicate.md
@@ -52,6 +52,11 @@ Ente also provides a tool for manual de-duplication in _Settings → Backup →
Remove duplicates_. This is useful if you have an existing library with
duplicates across different albums, but wish to keep only one copy.
+During this operation, Ente will discard duplicates across all albums, retain a
+single copy, and add symlinks to this copy within all existing albums. So your
+existing album structure remains unchanged, while the space consumed by the
+duplicate data is freed up.
+
## Adding to Ente album creates symlinks
Note that once a file is in Ente, adding it to another Ente album will create a
diff --git a/docs/docs/photos/features/family-plans.md b/docs/docs/photos/features/family-plans.md
index 711b9e3094..cc5ee52aff 100644
--- a/docs/docs/photos/features/family-plans.md
+++ b/docs/docs/photos/features/family-plans.md
@@ -24,19 +24,19 @@ In brief,
## Storage Limits
-If you're an admin of a family, you will be able to set storage limits for the
+If you're an admin of a family, you will be able to set storage limits for the
members in your family plan.
-In brief,
+In brief,
-- For example, once you set a limit of 10GB for a member, their Storage
- quota for uploading photos will be limited to 10GB.
+- For example, once you set a limit of 10GB for a member, their Storage quota
+ for uploading photos will be limited to 10GB.
-- Once the invited member accepts the Family invite, you will be able to see
- an edit icon in the Members List. Click on it to setup a family limit.
+- Once the invited member accepts the Family invite, you will be able to see an
+ edit icon in the Members List. Click on it to setup a family limit.
- If the admin has set a limit for any user, that limit value will be prefilled
- in the input box.
+ in the input box.
-- If you want to remove any storage limit from a members account, you
- can click on the "Remove Limit" and they can upload photos without any limit.
+- If you want to remove any storage limit from a members account, you can click
+ on the "Remove Limit" and they can upload photos without any limit.
diff --git a/docs/docs/photos/features/machine-learning.md b/docs/docs/photos/features/machine-learning.md
index 215c1d98a8..e43edd5b43 100644
--- a/docs/docs/photos/features/machine-learning.md
+++ b/docs/docs/photos/features/machine-learning.md
@@ -47,8 +47,20 @@ device.
The indexes are synced across all your devices automatically using the same
end-to-end encrypted security that we use for syncing your photos.
-Note that the desktop app does not currently support modifying the face
-groupings, that is only supported by the mobile app.
+---
+
+#### Local indexing on mobile
+
+In general the machine learning is optimized to work well on most mobile device.
+However, devices with low RAM (4-6GB) and large photo libraries might struggle
+to complete the indexing without affecting performance of the app. In such case,
+you might want to disable local indexing and let the desktop run it instead.
+
+You can disable local indexing from the settings, under
+`General > Advanced > Machine learning > Configuration`. This way, you can
+continue to use the ML features without your phone performance taking any hit.
+
+---
For more information on how to use Machine Learning for face recognition please
check out [the FAQ](../faq/face-recognition).
diff --git a/docs/docs/photos/features/notifications.md b/docs/docs/photos/features/notifications.md
new file mode 100644
index 0000000000..0cf33a6e0e
--- /dev/null
+++ b/docs/docs/photos/features/notifications.md
@@ -0,0 +1,33 @@
+---
+title: Notifications
+description: Details about notifications in Ente
+---
+
+# Notifications
+
+The Ente app can send notifications to notify you of an update, or just to
+remind you of some sweet or helpful memory at the right time.
+
+## New shared photos
+
+Receive notifications when someone adds a photo to a shared album that you're a
+part of.
+
+## "On this day" memories
+
+Receive reminders about memories from this day in previous years. These
+reminders will only be shown if there are enough photos taken across previous
+years of the specific day.
+
+## Birthday notifications
+
+Receive reminders when it's someone's birthday. Tapping on the notification will
+take you to photos of the birthday person. This requires you to first add a
+birthday to a person, and will only be shown if there are enough photos of that
+person.
+
+## Notification permission
+
+By default all notification categories are enabled if you give notification
+permission. You can disable all of the above notification categories from
+`Settings > Notifications`. Notifications currently only work on mobile.
diff --git a/docs/docs/photos/migration/export/index.md b/docs/docs/photos/migration/export/index.md
index 39d14984ed..1e00623e54 100644
--- a/docs/docs/photos/migration/export/index.md
+++ b/docs/docs/photos/migration/export/index.md
@@ -66,5 +66,4 @@ If you run into any issues during your data export, please reach out to
Note that we also provide a
[CLI tool](https://github.com/ente-io/ente/tree/main/cli#export) to export your
-data. You can find more information about the export in the
-[export FAQ](/photos/faq/export).
+data.
diff --git a/docs/docs/photos/troubleshooting/nas.md b/docs/docs/photos/troubleshooting/nas.md
index 262d4c758d..c84463ce63 100644
--- a/docs/docs/photos/troubleshooting/nas.md
+++ b/docs/docs/photos/troubleshooting/nas.md
@@ -14,9 +14,21 @@ directly stream chunks of Google Takeout zips that are stored on network drives.
In particular, the folder watch functionality suffers a lot since the app needs
access to file system events to detect changes to the users files so that they
-can be uploaded whenever there are changes.
+can be uploaded whenever there are changes. Network drives are less reliable in
+providing these file change events correctly.
Since are high chances of the user having a subpar experience, we request
customers to avoid using the desktop app directly with network attached storage
and instead temporarily copy the files to their local storage for uploads, and
avoid watching folders that live on a network drive.
+
+## Exporting to UNC paths
+
+Generally, exports are likely to work better than imports, since the interaction
+with the file system is relatively simpler (Note that the app still needs to
+scan the folder to find existing files, esp. if the continuous export option is
+enabled).
+
+A special case is when exporting to a UNC path. In this case, the file
+separators will not work as expected and the export will not start. As a
+workaround, you can map your UNC path to a network drive and use that instead.
diff --git a/docs/docs/about/ducky.png b/docs/docs/public/ducky.png
similarity index 100%
rename from docs/docs/about/ducky.png
rename to docs/docs/public/ducky.png
diff --git a/docs/docs/self-hosting/creating-accounts.md b/docs/docs/self-hosting/creating-accounts.md
index 5c3a53d3a3..550409106e 100644
--- a/docs/docs/self-hosting/creating-accounts.md
+++ b/docs/docs/self-hosting/creating-accounts.md
@@ -3,7 +3,7 @@ title: Creating accounts
description: Creating accounts on your deployment
---
-# Creating accounts
+# Creating accounts
Once Ente is up and running, the Ente Photos web app will be accessible on
`http://localhost:3000`. Open this URL in your browser and proceed with creating
@@ -20,7 +20,7 @@ This code can be found in the server logs, which should already be shown in your
quickstart terminal. Alternatively, you can open the server logs with the
following command from inside the `my-ente` folder:
-```sh
+```sh
sudo docker compose logs
```
diff --git a/docs/docs/self-hosting/faq/environment.md b/docs/docs/self-hosting/faq/environment.md
new file mode 100644
index 0000000000..a8dcf18d06
--- /dev/null
+++ b/docs/docs/self-hosting/faq/environment.md
@@ -0,0 +1,52 @@
+---
+title: "Environment Variables and Ports"
+description:
+ "Information about all the Environment Variables needed to run Ente"
+---
+
+# Environment variables and ports
+
+A self-hosted Ente instance requires specific endpoints in both Museum (the
+server) and web apps. This document outlines the essential environment variables
+and port mappings of the web apps.
+
+Here's the list of important variables that a self hoster should know about:
+
+### Museum
+
+1. `NEXT_PUBLIC_ENTE_ENDPOINT`
+
+The above environment variable is used to configure Museums endpoint. Where
+Museum is running and which port it is listening on. This endpoint should be
+configured for all the apps to connect to your self hosted endpoint.
+
+All the apps (regardless of platform) by default connect to api.ente.io - which
+is our production instance of Museum.
+
+### Web Apps
+
+> [!IMPORTANT] Web apps don't need to be configured with the below endpoints.
+> Web app environment variables are being documented here just so that the users
+> know everything in detail. Checkout
+> [Configuring your Server](/self-hosting/museum) to configure endpoints for
+> particular app.
+
+In Ente, all the web apps are separate NextJS applications. Therefore, they are
+all configured via environment variables. The photos app (Ente Photos) has
+information about and connects to other web apps like albums, cast, etc.
+
+1. `NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT`
+
+This environment variable is used to configure and declare the endpoint for the
+Albums web app.
+
+## Ports
+
+The below format is according to how ports are mapped in Docker.
+Typically,`:`
+
+1. `8080:8080`: Museum (Ente's server)
+2. `3000:3000`: Ente Photos web app
+3. `3001:3001`: Ente Accounts web app
+4. `3003:3003`: [Ente Auth web app](https://ente.io/auth/)
+5. `3004:3004`: [Ente Cast web app](http://ente.io/cast)
diff --git a/docs/docs/self-hosting/guides/admin.md b/docs/docs/self-hosting/guides/admin.md
index 75048f2804..10d05fb4d0 100644
--- a/docs/docs/self-hosting/guides/admin.md
+++ b/docs/docs/self-hosting/guides/admin.md
@@ -3,32 +3,6 @@ title: Server admin
description: Administering your custom self-hosted Ente instance using the CLI
---
-# Administering your custom server
-
-You can use
-[Ente's CLI](https://github.com/ente-io/ente/releases?q=tag%3Acli-v0) to
-administer your self hosted server.
-
-First we need to get your CLI to connect to your custom server. Define a
-config.yaml and put it either in the same directory as CLI or path defined in
-env variable `ENTE_CLI_CONFIG_PATH`
-
-```yaml
-endpoint:
- api: "http://localhost:8080"
-```
-
-Now you should be able to
-[add an account](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_add.md),
-and subsequently increase the
-[storage and account validity](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_admin_update-subscription.md)
-using the CLI.
-
-> [!NOTE]
->
-> The CLI command to add an account does not create Ente accounts. It only adds
-> existing accounts to the list of (existing) accounts that the CLI can use.
-
## Becoming an admin
By default, the first user (and only the first user) created on the system is
@@ -78,6 +52,37 @@ You can use
[account list](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_list.md)
command to find the user id of any account.
+# Administering your custom server
+
+> [!NOTE] For the first user (admin) to perform administrative actions using the
+> CLI, their userID must be whitelisted in the `museum.yaml` configuration file
+> under `internal.admins`. While the first user is automatically granted admin
+> privileges on the server, this additional step is required for CLI operations.
+
+You can use
+[Ente's CLI](https://github.com/ente-io/ente/releases?q=tag%3Acli-v0) to
+administer your self hosted server.
+
+First we need to get your CLI to connect to your custom server. Define a
+config.yaml and put it either in the same directory as CLI or path defined in
+env variable `ENTE_CLI_CONFIG_PATH`
+
+```yaml
+endpoint:
+ api: "http://localhost:8080"
+```
+
+Now you should be able to
+[add an account](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_add.md),
+and subsequently increase the
+[storage and account validity](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_admin_update-subscription.md)
+using the CLI.
+
+> [!NOTE]
+>
+> The CLI command to add an account does not create Ente accounts. It only adds
+> existing accounts to the list of (existing) accounts that the CLI can use.
+
## Backups
See this [FAQ](/self-hosting/faq/backup).
diff --git a/docs/docs/self-hosting/guides/configuring-s3.md b/docs/docs/self-hosting/guides/configuring-s3.md
index 78f28d92ae..55f2f3b356 100644
--- a/docs/docs/self-hosting/guides/configuring-s3.md
+++ b/docs/docs/self-hosting/guides/configuring-s3.md
@@ -29,7 +29,7 @@ A file upload flows as follows:
The upshot of this is that _both_ the client and museum should be able to reach
your S3 bucket.
-## Configuring S3
+## Configuring S3
The URL for the S3 bucket is configured in
[scripts/compose/credentials.yaml](https://github.com/ente-io/ente/blob/main/server/scripts/compose/credentials.yaml#L10).
@@ -38,9 +38,8 @@ You can edit this file directly while testing, though it is more robust to
create a `museum.yaml` (in the same folder as the Docker compose file) and to
setup your custom configuration there.
-> [!TIP]
-> For more details about these configuration objects, see the documentation for
-> the `s3` object in
+> [!TIP] For more details about these configuration objects, see the
+> documentation for the `s3` object in
> [configurations/local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml).
By default, you only need to configure the endpoint for the first bucket.
@@ -56,13 +55,14 @@ components of the setup to communicate with each other seamlessly.
The same principle applies if you're deploying to your custom domain.
-## Replication
+## Replication

+
Community contributed diagram of Ente's replication process
> [!IMPORTANT]
->
+>
> As of now, replication works only if all the 3 storage type needs are
> fulfilled (1 hot, 1 cold and 1 glacier storage).
>
@@ -72,10 +72,10 @@ If you're wondering why there are 3 buckets on the MinIO UI - that's because our
production instance uses these to perform
[replication](https://ente.io/reliability/).
-If you're also wondering about why the bucket names are specifically what they are,
-it's because that is exactly what we are using on our production instance.
-We use `b2-eu-cen` as hot, `wasabi-eu-central-2-v3` as cold (also the secondary hot)
-and `scw-eu-fr-v3` as glacier storage. As of now, all of this is hardcoded.
+If you're also wondering about why the bucket names are specifically what they
+are, it's because that is exactly what we are using on our production instance.
+We use `b2-eu-cen` as hot, `wasabi-eu-central-2-v3` as cold (also the secondary
+hot) and `scw-eu-fr-v3` as glacier storage. As of now, all of this is hardcoded.
Hence, the same hardcoded configuration is applied when you self host Ente.
In a self hosted Ente instance replication is turned off by default. When
@@ -84,16 +84,15 @@ other two are ignored. Only the names here are specifically fixed, but in the
configuration body you can put any other keys. It does not have any relation
with `b2`, `wasabi` or even `scaleway`.
-Use the `s3.hot_storage.primary` option if you'd like to set one of the other
+Use the `s3.hot_storage.primary` option if you'd like to set one of the other
predefined buckets as the primary bucket.
-## SSL Configuration
+## SSL Configuration
> [!NOTE]
>
> If you need to configure SSL, you'll need to turn off `s3.are_local_buckets`
> (which disables SSL in the default starter compose template).
->
Disabling `s3.are_local_buckets` also switches to the subdomain style URLs for
the buckets. However, not all S3 providers support these. In particular, MinIO
@@ -122,45 +121,3 @@ s3:
region: eu-central-2
bucket: b2-eu-cen
```
-
-## Frequently encountered errors
-
-Here are some errors our community members frequently encountered with the
-context and potential fixes.
-
-In most situations, the problem is because of a minor mistakes or
-misconfiguration. Please make sure to `reverse_proxy` museum to a domain and
-check your S3 credentials and whole configuration file for any minor
-misconfigurations.
-
-It is also suggested that the user setups bucket CORS on MinIO or any external
-S3 service provider they are connecting to. To setup bucket CORS, please [read
-this](/self-hosting/guides/external-s3#_5-fix-potential-cors-issue-with-your-bucket).
-
-### 403 Forbidden
-
-If museum (`2`) is able to make a network connection to your S3 bucket (`3`) but
-uploads are still failing, it could be a credentials or permissions issue.
-
-A telltale sign of this is that in the museum logs you can see `403 Forbidden`
-errors about it not able to find the size of a file even though the
-corresponding object exists in the S3 bucket.
-
-This could be because
-
-1. The bucket CORS rules do not allow museum to access these objects. For
- uploading files from the browser, you will need to set `allowedOrigins` to
- `*`, and allow the `X-Auth-Token`, `X-Client-Package` headers configuration
- too. [Here is an example of a working
- configuration](https://github.com/ente-io/ente/discussions/1764#discussioncomment-9478204).
-
-2. The credentials are not being picked up (you might be setting the correct
- credentials, but not in the place where museum reads them from).
-
-### Mismatch in file size
-
-The "Mismatch in file size" error mostly occurs in a situation where the client
-(`1`) is re-uploading a file which is already in the bucket with a different
-file size. The reason for re-upload could be anything including network issue,
-sudden killing of app before the upload is complete and etc.
-
diff --git a/docs/docs/self-hosting/guides/custom-server/index.md b/docs/docs/self-hosting/guides/custom-server/index.md
index 86060ba909..63ba371eb8 100644
--- a/docs/docs/self-hosting/guides/custom-server/index.md
+++ b/docs/docs/self-hosting/guides/custom-server/index.md
@@ -111,5 +111,5 @@ network, you need to use the public IP or hostname.
> [!TIP]
>
> If you're having trouble uploading from your mobile app, it is likely that
-> museum is not able to connect to your S3 storage. See the [Configuring
-> S3](/self-hosting/guides/configuring-s3) guide for more details.
+> museum is not able to connect to your S3 storage. See the
+> [Configuring S3](/self-hosting/guides/configuring-s3) guide for more details.
diff --git a/docs/docs/self-hosting/guides/external-s3.md b/docs/docs/self-hosting/guides/external-s3.md
index 46b66769ce..0a919092c0 100644
--- a/docs/docs/self-hosting/guides/external-s3.md
+++ b/docs/docs/self-hosting/guides/external-s3.md
@@ -250,64 +250,6 @@ docker compose exec -i postgres psql -U pguser -d ente_db -c "INSERT INTO storag
After few reloads, you should see 1 To of quota.
-## 5. Fix potential CORS issue with your bucket
-
-### For AWS S3
-
-If you cannot upload a photo due to a CORS issue, you need to fix the CORS
-configuration of your bucket.
-
-Create a `cors.json` file with the following content:
-
-```json
-{
- "CORSRules": [
- {
- "AllowedOrigins": ["*"],
- "AllowedHeaders": ["*"],
- "AllowedMethods": ["GET", "HEAD", "POST", "PUT", "DELETE"],
- "MaxAgeSeconds": 3000,
- "ExposeHeaders": ["Etag"]
- }
- ]
-}
-```
-
-You may want to change the `AllowedOrigins` to a more restrictive value.
-
-If you are using AWS for S3, you can execute the below command to get rid of
-CORS. Make sure to enter the right path for the `cors.json` file.
-
-```bash
-aws s3api put-bucket-cors --bucket YOUR_S3_BUCKET --cors-configuration /path/to/cors.json
-```
-
-### For Self-hosted Minio Instance
-
-> Important: MinIO does not take JSON CORS file as the input, instead you will
-> have to build a CORS.xml file or just convert the above `cors.json` to XML.
-
-A minor requirement here is the tool `mc` for managing buckets via command line
-interface. Checkout the `mc set alias` document to configure alias for your
-instance and bucket. After this you will be prompted for your AccessKey and
-Secret, which is your username and password, go ahead and enter that.
-
-```sh
-mc cors set // api cors_allow_origin="*"
-```
-
-You can create also `.csv` file and dump the list of origins you would like to
-allow and replace the `*` with `path` to the CSV file.
-
-Now, uploads should be working fine.
-
## Related
Some other users have also shared their setups.
@@ -315,3 +257,5 @@ Some other users have also shared their setups.
- [Using Traefik](https://github.com/ente-io/ente/pull/3663)
- [Building custom images from source (Linux)](https://github.com/ente-io/ente/discussions/3778)
+
+- [Troubleshooting Bucket CORS](/self-hosting/troubleshooting/bucket-cors)
diff --git a/docs/docs/self-hosting/guides/from-source.md b/docs/docs/self-hosting/guides/from-source.md
index df3ec7e5fb..9d010190dc 100644
--- a/docs/docs/self-hosting/guides/from-source.md
+++ b/docs/docs/self-hosting/guides/from-source.md
@@ -3,13 +3,12 @@ title: Ente from Source
description: Getting started self hosting Ente Photos and/or Ente Auth
---
-
# Ente from Source
-> [!WARNING] NOTE
-> The below documentation will cover instructions about self-hosting the web app manually. If you
-> want to deploy Ente hassle free, use the [one line](https://ente.io/blog/self-hosting-quickstart/)
-> command to setup Ente. This guide might be deprecated in the near future.
+> [!WARNING] NOTE The below documentation will cover instructions about
+> self-hosting the web app manually. If you want to deploy Ente hassle free, use
+> the [one line](https://ente.io/blog/self-hosting-quickstart/) command to setup
+> Ente. This guide might be deprecated in the near future.
## Installing Docker
@@ -63,8 +62,9 @@ apps and configure them to use your
## Web app with Docker and Compose
-The instructoins in previous section were just a temporary way to run the web app locally.
-To run the web apps as services, the user has to build a docker image manually.
+The instructoins in previous section were just a temporary way to run the web
+app locally. To run the web apps as services, the user has to build a docker
+image manually.
> [!IMPORTANT]
>
@@ -144,7 +144,7 @@ docker build -t : --no-cache --progress plain .
You can always edit the Dockerfile and remove the steps for apps which you do
not intend to install on your system (like auth or cast) and opt out of those.
-Regarding Albums App, take a note that they are not apps with navigable pages,
+Regarding Albums App, take a note that they are not apps with navigable pages,
if accessed on the web-browser they will simply redirect to ente.web.io.
## compose.yaml
@@ -175,17 +175,17 @@ docker compose up -d # --build
docker compose logs
```
-## Configure App Endpoints
+## Configure App Endpoints
-> [!NOTE]
-> Previously, this was dependent on the env variables `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT`
-> and etc. Please check the below documentation to update your setup configurations
+> [!NOTE] Previously, this was dependent on the env variables
+> `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT` and etc. Please check the below
+> documentation to update your setup configurations
-You can configure the web endpoints for the other apps including Accounts, Albums
-Family and Cast in your `museum.yaml` configuration file. Checkout
+You can configure the web endpoints for the other apps including Accounts,
+Albums Family and Cast in your `museum.yaml` configuration file. Checkout
[`local.yaml`](https://github.com/ente-io/ente/blob/543411254b2bb55bd00a0e515dcafa12d12d3b35/server/configurations/local.yaml#L76-L89)
-to configure the endpoints. Make sure to setup up your DNS Records accordingly to the
-similar URL's you set up in `museum.yaml`.
+to configure the endpoints. Make sure to setup up your DNS Records accordingly
+to the similar URL's you set up in `museum.yaml`.
Next part is to configure the web server.
@@ -197,7 +197,7 @@ ports). The web server of choice in this guide is
[Caddy](https://caddyserver.com) because with caddy you don't have to manually
configure/setup SSL ceritifcates as caddy will take care of that.
-```sh
+```groovy
photos.yourdomain.com {
reverse_proxy http://localhost:3001
# for logging
@@ -219,6 +219,7 @@ Next, start the caddy server :).
sudo systemctl enable caddy
sudo systemctl daemon-reload
+
sudo systemctl start caddy
```
diff --git a/docs/docs/self-hosting/guides/Tailscale.md b/docs/docs/self-hosting/guides/tailscale.md
similarity index 60%
rename from docs/docs/self-hosting/guides/Tailscale.md
rename to docs/docs/self-hosting/guides/tailscale.md
index 1f0a7593ed..20983e8e7b 100644
--- a/docs/docs/self-hosting/guides/Tailscale.md
+++ b/docs/docs/self-hosting/guides/tailscale.md
@@ -2,39 +2,56 @@
title: Self Hosting with Tailscale (Community)
description: Guides for self-hosting Ente Photos and/or Ente Auth with Tailscale
---
+
# Guide
-This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale (TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot open any port on the internet but want to run their own selfhosted service for themselves, friends and family only.
+This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale
+(TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot
+open any port on the internet but want to run their own selfhosted service for
+themselves, friends and family only.
Before getting start keep the following NOTE in mind.
-> [!NOTE]
-> If someone is behind double or triple CGNAT; must install tailscale system wide by running `curl -fsSL https://tailscale.com/install.sh | sh` in your linux terminal and `sudo tailscale up` otherwise dns resolver will fail and uploading will not work. This is not necessary for those who are not behing CGNAT.
-> This guide also work on docker rootless and normal.
+> [!NOTE] If someone is behind double or triple CGNAT; must install tailscale
+> system wide by running `curl -fsSL https://tailscale.com/install.sh | sh` in
+> your linux terminal and `sudo tailscale up` otherwise dns resolver will fail
+> and uploading will not work. This is not necessary for those who are not
+> behing CGNAT. This guide also work on docker rootless and normal.
-> [!CAUTION]
-Remember that current docker update 28.0.0 has some bug and cannot connect to external network. Make sure to install docker-ce 27.5.0, docker-ce-rootless-extras 27.5.0 and docker-ce-cli 27.5.0. Hopefully docker 28.1.0 will resolve this issue in next week. Refrence links are [Moby Github Repo Issues 49511](https://github.com/moby/moby/issues/49511) and [Moby Github Repo Issues 49519](https://github.com/moby/moby/issues/49519)
-
-> [!IMPORTANT]
-> For Docker rootless, the user must have local permissions for all directories required by the Ente-photos self-hosted server. This can be achieved by running `sudo chown -R 1000:1000 /home/ubuntu/docker/ente`. In the Linux terminal, you can check the UID with `id -u` or simply `id`. The first user typically has UID 1000.
-> To allow listening and pinging on any port without root privileges, create a file called `/etc/sysctl.d/99-rootless.conf` with the following content:
+> [!IMPORTANT] For Docker rootless, the user must have local permissions for all
+> directories required by the Ente-photos self-hosted server. This can be
+> achieved by running `sudo chown -R 1000:1000 /home/ubuntu/docker/ente`. In the
+> Linux terminal, you can check the UID with `id -u` or simply `id`. The first
+> user typically has UID 1000. To allow listening and pinging on any port
+> without root privileges, create a file called `/etc/sysctl.d/99-rootless.conf`
+> with the following content:
+>
> ```
> net.ipv4.ip_unprivileged_port_start=0
> net.ipv4.ping_group_range = 0 2147483647
> ```
-> than run `sudo sysctl --system`.
-> Create `~/.config/systemd/user/docker.service.d/override.conf` with the following content:
+>
+> than run `sudo sysctl --system`. Create
+> `~/.config/systemd/user/docker.service.d/override.conf` with the following
+> content:
+>
> ```
> [Service]
> Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns"
> Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
> ```
-> and Restart the docker daemon
-> `systemctl --user restart docker`
-> Instead of `--volume /var/run/docker.sock:/var/run/docker.sock` in TSDPROXY compose.yaml, use `--volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock`
+>
+> and Restart the docker daemon `systemctl --user restart docker` Instead of
+> `--volume /var/run/docker.sock:/var/run/docker.sock` in TSDPROXY compose.yaml,
+> use `--volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock`
+
+## GETTING START WITH SETUP
+
+First of all create a directory
+`sudo mkdir -p /home/ubuntu/docker/tsdproxy/config` than `cd docker/tsdproxy`
+and create compose.yaml file by running `sudo nano compose.yaml`. Populate it
+with the following:
-## GETTING START WITH SETUP ##
-First of all create a directory `sudo mkdir -p /home/ubuntu/docker/tsdproxy/config` than `cd docker/tsdproxy` and create compose.yaml file by running `sudo nano compose.yaml`. Populate it with the following:
```
services:
tsdproxy:
@@ -62,9 +79,18 @@ networks:
proxy:
name: proxy
```
-Now login into your tailscale account admin counsle > settings > keys > Generate authkey. Give any description and must select resuable, because the key get purged if not selected after rebooting machine. It is advisable to create **Tags** in **ACLs settings** `tag: tsdproxy` `tag: ente` `tag: minio` as well. This will create a tag nodes with no key expirory. One is safe to reboot restart docker or machine.
-> Copy the generated authkey as it is shown only once.
-Make tsdproxy.yaml file in `cd docker/tsdproxy/config` by running `sudo nano tsdproxy.yaml` and pupolate it with the following contant:
+
+Now login into your tailscale account admin counsle > settings > keys > Generate
+authkey. Give any description and must select resuable, because the key get
+purged if not selected after rebooting machine. It is advisable to create
+**Tags** in **ACLs settings** `tag: tsdproxy` `tag: ente` `tag: minio` as well.
+This will create a tag nodes with no key expirory. One is safe to reboot restart
+docker or machine.
+
+> Copy the generated authkey as it is shown only once. Make tsdproxy.yaml file
+> in `cd docker/tsdproxy/config` by running `sudo nano tsdproxy.yaml` and
+> pupolate it with the following contant:
+
```
defaultproxyprovider: default
docker:
@@ -87,12 +113,20 @@ log:
json: false
proxyaccesslog: true
```
-In the same directory run `sudo nano authkey` and paste the authkey just copied earlier from tailscale admin counsel.
-> Here Tailscale (TSDPROXY) setup is complet in all respect. Just run `docker compose up -d`. Check your tailscale amdin counsel and you will see tsdproxy node up and running. Make sure that **HTTPS** is enabled in tailscale DNS settings.
-> You can visit the TSDPROXY web GUI by https://tsdproxy.xyz.ts.net. (xyz is change value for everyone)
-## ente Part ##
+In the same directory run `sudo nano authkey` and paste the authkey just copied
+earlier from tailscale admin counsel.
+
+> Here Tailscale (TSDPROXY) setup is complet in all respect. Just run
+> `docker compose up -d`. Check your tailscale amdin counsel and you will see
+> tsdproxy node up and running. Make sure that **HTTPS** is enabled in tailscale
+> DNS settings. You can visit the TSDPROXY web GUI by
+> https://tsdproxy.xyz.ts.net. (xyz is change value for everyone)
+
+## ente Part
+
First make the following necessary files/directories:
+
```
sudo mkdir -p /home/ubuntu/docker/ente/custom-logs
sudo mkdir -p /home/ubuntu/docker/ente/data
@@ -100,9 +134,14 @@ sudo mkdir -p /home/ubuntu/docker/ente/minio-data
sudo mkdir -p /home/ubuntu/docker/ente/postgres-data
sudo mkdir -p /home/ubuntu/docker/ente/scripts/compose
```
-Than give user permission for each of the above directory. `sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs` etc etc. Make sure not to skip `/home/ubuntu/docker/tsdproxy/config`
-`cd docker/ente/script/compose` and run `sudo nano credentials.yaml` than populate it with the following:
+Than give user permission for each of the above directory.
+`sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs` etc etc. Make
+sure not to skip `/home/ubuntu/docker/tsdproxy/config`
+
+`cd docker/ente/script/compose` and run `sudo nano credentials.yaml` than
+populate it with the following:
+
```
db:
host: postgres
@@ -134,7 +173,9 @@ s3:
bucket: scw-eu-fr-v3
```
-In the same directory run `sudo nano minio-provision.sh` and populate it with the following contant:
+In the same directory run `sudo nano minio-provision.sh` and populate it with
+the following contant:
+
```
#!/bin/sh
@@ -154,7 +195,9 @@ mc mb -p wasabi-eu-central-2-v3
mc mb -p scw-eu-fr-v3
```
-Now `cd docker/ente` and run `sudo nano docker-compose.yaml` and populate it with the following:
+Now `cd docker/ente` and run `sudo nano docker-compose.yaml` and populate it
+with the following:
+
```
services:
museum:
@@ -255,32 +298,52 @@ services:
networks:
ente:
name: ente
-
+
proxy:
external: true
```
-> Thats it. Run `docker compose up -d`. Wait till every container become healthy. Open web browser. Make sure tailscale is installed on the machine. Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it. First time it will take minute or two to get SSL cert. Downnload Desktop or mobile app. Tap 7 time on the screen, which will prompt developer mode. Add https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux terminal and run `docker logs ente-museum-1`. Search for userauth. Feed the six digit and Done.
+> Thats it. Run `docker compose up -d`. Wait till every container become
+> healthy. Open web browser. Make sure tailscale is installed on the machine.
+> Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it.
+> First time it will take minute or two to get SSL cert. Downnload Desktop or
+> mobile app. Tap 7 time on the screen, which will prompt developer mode. Add
+> https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux
+> terminal and run `docker logs ente-museum-1`. Search for userauth. Feed the
+> six digit and Done.
+
+> For getting 100TB (limitless) storage. Just Install ente-cli for windows.
+> Extract it and add folder. Name it **export**. Add config.yaml file along and
+> populate it with the following:
-> For getting 100TB (limitless) storage. Just Install ente-cli for windows. Extract it and add folder. Name it **export**. Add config.yaml file along and populate it with the following:
```
endpoint:
api: "https://ente.xyz.ts.net"
accounts: "http://localhost:3001"
-
+
log: false
```
-Right-Click in the directory where you have extracted ente-cli. Select `open in terminal`. Run
+
+Right-Click in the directory where you have extracted ente-cli. Select
+`open in terminal`. Run
+
```
.\ente.exe account bob # change bob to yours
```
-Hit Enter twice.
-For export directory, just write export. As already created **export** folder earlier.
-**Write email. The one which is already used befor when creating ente account in ente desktop app.**
-Type the same Password used before for the account.Run
+
+Hit Enter twice. For export directory, just write export. As already created
+**export** folder earlier. **Write email. The one which is already used befor
+when creating ente account in ente desktop app.** Type the same Password used
+before for the account.Run
+
```
.\ente.ext account list
```
+
This will list all account details. Copy Acount ID.
-> Navigate to museum.yaml file. `cd docker/ente`. Run `sudo nano museum.yaml` and add the account ID under Admins. Delete any previous entries.
-Restart ente-museum-1 container from linux terminal. Run `docker restart ente-museum-1`. All well, now you will have 100TB storage. Repeat if for any other accounts you want to give unlimited storage access.
+
+> Navigate to museum.yaml file. `cd docker/ente`. Run `sudo nano museum.yaml`
+> and add the account ID under Admins. Delete any previous entries. Restart
+> ente-museum-1 container from linux terminal. Run
+> `docker restart ente-museum-1`. All well, now you will have 100TB storage.
+> Repeat if for any other accounts you want to give unlimited storage access.
diff --git a/docs/docs/self-hosting/guides/web-app.md b/docs/docs/self-hosting/guides/web-app.md
index 015cb7d986..a3061e3004 100644
--- a/docs/docs/self-hosting/guides/web-app.md
+++ b/docs/docs/self-hosting/guides/web-app.md
@@ -5,22 +5,20 @@ description:
server
---
-
-> [!WARNING] NOTE
-> This page covers documentation around self-hosting the web app manually. If you
-> want to deploy Ente hassle free, please use the [one line](https://ente.io/blog/self-hosting-quickstart/)
-> command to setup Ente. This guide might be deprecated in the near future.
+> [!WARNING] NOTE This page covers documentation around self-hosting the web app
+> manually. If you want to deploy Ente hassle free, please use the
+> [one line](https://ente.io/blog/self-hosting-quickstart/) command to setup
+> Ente. This guide might be deprecated in the near future.
# Web app
The getting started instructions mention using `yarn dev` (which is an alias of
`yarn dev:photos`) to serve your web app.
->[!IMPORTANT]
-> Please note that Ente's Web App supports the Yarn version 1.22.xx or 1.22.22 specifically.
-> Make sure to install the right version or modify your yarn installation to meet the requirements.
-> The user might end up into unknown version and dependency related errors if yarn
-> is on different version.
+> [!IMPORTANT] Please note that Ente's Web App supports the Yarn version 1.22.xx
+> or 1.22.22 specifically. Make sure to install the right version or modify your
+> yarn installation to meet the requirements. The user might end up into unknown
+> version and dependency related errors if yarn is on different version.
```sh
cd ente/web
@@ -146,15 +144,15 @@ docker compose logs
## Configure App Endpoints
-> [!NOTE]
-> Previously, this was dependent on the env variables `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT`
-> and etc. Please check the below documentation to update your setup configurations
+> [!NOTE] Previously, this was dependent on the env variables
+> `NEXT_ENTE_PUBLIC_ACCOUNTS_ENDPOINT` and etc. Please check the below
+> documentation to update your setup configurations
-You can configure the web endpoints for the other apps including Accounts, Albums
-Family and Cast in your `museum.yaml` configuration file. Checkout
+You can configure the web endpoints for the other apps including Accounts,
+Albums Family and Cast in your `museum.yaml` configuration file. Checkout
[`local.yaml`](https://github.com/ente-io/ente/blob/543411254b2bb55bd00a0e515dcafa12d12d3b35/server/configurations/local.yaml#L76-L89)
-to configure the endpoints. Make sure to setup up your DNS Records accordingly to the
-similar URL's you set up in `museum.yaml`.
+to configure the endpoints. Make sure to setup up your DNS Records accordingly
+to the similar URL's you set up in `museum.yaml`.
Next part is to configure the web server.
diff --git a/docs/docs/self-hosting/index.md b/docs/docs/self-hosting/index.md
index c0eef22f2c..79afd831ba 100644
--- a/docs/docs/self-hosting/index.md
+++ b/docs/docs/self-hosting/index.md
@@ -5,20 +5,32 @@ description: Getting started self hosting Ente Photos and/or Ente Auth
# Self Hosting
-The entire source code for Ente is open source, including the servers. This is
+The entire source code for Ente is open source,
+[including the servers](https://ente.io/blog/open-sourcing-our-server/). This is
the same code we use for our own cloud service.
-> [!TIP]
->
-> You might find our [blog post](https://ente.io/blog/open-sourcing-our-server/)
-> announcing the open sourcing of our server useful.
+## Requirements
-## System requirements
+### Hardware
-The server has minimal resource requirements, running as a lightweight Go
-binary. It performs well on small cloud instances, old laptops, and even
+The server is capable of running on minimal resource requirements as a
+lightweight Go binary, since most of the intensive computational tasks are done
+on the client. It performs well on small cloud instances, old laptops, and even
[low-end embedded devices](https://github.com/ente-io/ente/discussions/594).
+### Software
+
+#### Operating System
+
+Any Linux or \*nix operating system, Ubuntu or Debian is recommended to have a
+good Docker experience. Non-Linux operating systems tend to provide poor
+experience with Docker and difficulty with troubleshooting and assistance.
+
+#### Docker
+
+Required for running Ente's server, web application and dependent services
+(database and object storage)
+
## Getting started
Run this command on your terminal to setup Ente.
@@ -28,7 +40,8 @@ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ente-io/ente/main/server/q
```
The above `curl` command pulls the Docker image, creates a directory `my-ente`
-in the current working directory and starts all containers required to run Ente.
+in the current working directory and prompts to start the cluster, which upon
+entering `y`, starts all the containers required to run Ente.

diff --git a/docs/docs/self-hosting/museum.md b/docs/docs/self-hosting/museum.md
index 4d1da34b0a..cb5263104f 100644
--- a/docs/docs/self-hosting/museum.md
+++ b/docs/docs/self-hosting/museum.md
@@ -16,10 +16,10 @@ If you used our quickstart script, your `my-ente` directory will include a
PostgreSQL and MinIO.
> [!TIP]
->
+>
> Always do `docker compose down` inside your `my-ente` directory. If you've
-> made changes to `museum.yaml`, restart the containers with `docker compose up
-> -d ` to see your changes in action.
+> made changes to `museum.yaml`, restart the containers with
+> `docker compose up -d ` to see your changes in action.
## S3 buckets
@@ -33,37 +33,45 @@ Check out [Configuring S3](/self-hosting/guides/configuring-s3.md) to understand
more about configuring S3 buckets.
MinIO uses the port `3200` for API Endpoints and their web app runs over
-`:3201`. You can login to MinIO Web Console by opening `localhost:3201` in your browser.
+`:3201`. You can login to MinIO Web Console by opening `localhost:3201` in your
+browser.
-If you face any issues related to uploads then checkout [Troubleshooting bucket
-CORS](/self-hosting/troubleshooting/bucket-cors) and [Frequently encountered S3
-errors](/self-hosting/guides/configuring-s3#frequently-encountered-errors).
+If you face any issues related to uploads then checkout
+[Troubleshooting bucket CORS](/self-hosting/troubleshooting/bucket-cors) and
+[Frequently encountered S3 errors](/self-hosting/guides/configuring-s3#frequently-encountered-errors).
## Web apps
The web apps for Ente Photos is divided into multiple sub-apps like albums,
-cast, auth, etc. These endpoints are configurable in the museum.yaml under the
+cast, auth, etc. These endpoints are configurable in `museum.yaml` under the
`apps.*` section.
-For example,
+For example,
```yaml
apps:
- public-albums: albums.myente.xyz
- cast: cast.myente.xyz
- accounts: accounts.myente.xyz
- family: family.myente.xyz
+ public-albums: https://albums.myente.xyz
+ cast: https://cast.myente.xyz
+ accounts: https://accounts.myente.xyz
+ family: https://family.myente.xyz
```
-By default, all the values redirect to our publicly hosted production services.
+> [!IMPORTANT] By default, all the values redirect to our publicly hosted
+> production services. For example, if `public-albums` is not configured your
+> shared album will use the `albums.ente.io` URL.
+
After you are done with filling the values, restart museum and the app will
start utilizing those endpoints instead of Ente's production instances.
Once you have configured all the necessary endpoints, `cd` into `my-ente` and
stop all the Docker containers with `docker compose down` and restart them with
-`docker compose up -d`.
+`docker compose up -d`.
Similarly, you can use the default
[`local.yaml`](https://github.com/ente-io/ente/tree/main/server/configurations/local.yaml)
as a reference for building a functioning `museum.yaml` for many other
functionalities like SMTP, Discord notifications, Hardcoded-OTTs, etc.
+
+## References
+
+- [Environment variables and ports](/self-hosting/faq/environment)
diff --git a/docs/docs/self-hosting/reverse-proxy.md b/docs/docs/self-hosting/reverse-proxy.md
index 7ef79ac412..97ef7da570 100644
--- a/docs/docs/self-hosting/reverse-proxy.md
+++ b/docs/docs/self-hosting/reverse-proxy.md
@@ -22,28 +22,32 @@ server on your machine.
Setting up a reverse proxy with Caddy is easy and straightforward.
-Firstly, install Caddy on your server.
+Firstly, install Caddy on your server.
```sh
sudo apt install caddy
-```
+```
After the installation is complete, a `Caddyfile` is created on the path
`/etc/caddy/`. This file is used to configure reverse proxies among other
things.
-```yaml
+```groovy
# Caddyfile - myente.xyz is just an example.
+
api.myente.xyz {
reverse_proxy http://localhost:8080
}
+
ente.myente.xyz {
reverse_proxy http://localhost:3000
}
+
#...and so on for other endpoints
```
-After a hard-reload, the Ente Photos web app should be up on https://ente.myente.xyz.
+After a hard-reload, the Ente Photos web app should be up on
+https://ente.myente.xyz.
If you are using a different tool for reverse proxy (like nginx), please check
out their documentation.
diff --git a/docs/docs/self-hosting/troubleshooting/bucket-cors.md b/docs/docs/self-hosting/troubleshooting/bucket-cors.md
index 19c1dbff47..8bab1f7012 100644
--- a/docs/docs/self-hosting/troubleshooting/bucket-cors.md
+++ b/docs/docs/self-hosting/troubleshooting/bucket-cors.md
@@ -37,13 +37,21 @@ aws s3api put-bucket-cors --bucket YOUR_S3_BUCKET --cors-configuration /path/to/
## For Self-hosted Minio Instance
-> Important: MinIO does not take JSON CORS file as the input, instead you will
-> have to build a CORS.xml file or just convert the above `cors.json` to XML.
+::: warning
+
+- MinIO does not support bucket CORS in the community edition which is used by
+ default. For more information, check
+ [this discussion](https://github.com/minio/minio/discussions/20841). However,
+ global CORS configuration is possible.
+- MinIO does not take JSON CORS file as the input, instead you will have to
+ build a CORS.xml file or just convert the above `cors.json` to XML.
+
+:::
A minor requirement here is the tool `mc` for managing buckets via command line
interface. Checkout the `mc set alias` document to configure alias for your
instance and bucket. After this you will be prompted for your AccessKey and
-Secret, which is your username and password, go ahead and enter that.
+Secret, which is your username and password.
```sh
mc cors set // api cors_allow_origin="*"
You can create also `.csv` file and dump the list of origins you would like to
allow and replace the `*` with `path` to the CSV file.
-Now, uploads should be working fine.
\ No newline at end of file
+Now, uploads should be working fine.
diff --git a/docs/docs/self-hosting/troubleshooting/docker.md b/docs/docs/self-hosting/troubleshooting/docker.md
index 6c80070b34..902e8c9cfd 100644
--- a/docs/docs/self-hosting/troubleshooting/docker.md
+++ b/docs/docs/self-hosting/troubleshooting/docker.md
@@ -1,5 +1,5 @@
---
-title: Docker errors
+title: Docker Errors
description: Fixing docker related errors when trying to self host Ente
---
@@ -34,30 +34,30 @@ perform the same configuration by removing the "post_start" hook, and adding a
new service definition:
```yaml
- minio-provision:
+minio-provision:
image: minio/mc
depends_on:
- - minio
+ - minio
volumes:
- - minio-data:/data
+ - minio-data:/data
networks:
- - internal
+ - internal
entrypoint: |
- sh -c '
- #!/bin/sh
+ sh -c '
+ #!/bin/sh
- while ! mc config host add h0 http://minio:3200 changeme changeme1234
- do
- echo "waiting for minio..."
- sleep 0.5
- done
+ while ! mc config host add h0 http://minio:3200 changeme changeme1234
+ do
+ echo "waiting for minio..."
+ sleep 0.5
+ done
- cd /data
+ cd /data
- mc mb -p b2-eu-cen
- mc mb -p wasabi-eu-central-2-v3
- mc mb -p scw-eu-fr-v3
- '
+ mc mb -p b2-eu-cen
+ mc mb -p wasabi-eu-central-2-v3
+ mc mb -p scw-eu-fr-v3
+ '
```
## start_interval
@@ -114,7 +114,7 @@ volumes.
If you're sure of what you're doing, the volumes can be deleted by
-```
+```sh
docker volume ls
```
@@ -124,6 +124,13 @@ to list them, and then delete the ones that begin with `my-ente` using
that'll delete all volumes (Ente or otherwise) on your machine that are not
currently in use by a running docker container.
+An alternative way is to delete the volumes along with removal of cluster's
+containers using `docker compose` inside `my-ente` directory.
+
+```sh
+docker compose down --volumes
+```
+
If you're unsure about removing volumes, another alternative is to rename your
`my-ente` folder. Docker uses the folder name to determine the volume name
prefix, so giving it a different name will cause Docker to create a volume
diff --git a/docs/docs/self-hosting/troubleshooting/keyring.md b/docs/docs/self-hosting/troubleshooting/keyring.md
index 399595ba3f..56a5807fa5 100644
--- a/docs/docs/self-hosting/troubleshooting/keyring.md
+++ b/docs/docs/self-hosting/troubleshooting/keyring.md
@@ -5,8 +5,8 @@ description: A quick hotfix for keyring errors while running Ente CLI.
# Ente CLI Secrets
-Ente CLI makes use of keyring for storing sensitive information like your
-passwords. And running the cli straight out of the box might give you some
+Ente CLI makes use of system keyring for storing sensitive information like your
+passwords. And running the CLI straight out of the box might give you some
errors related to keyrings in some case.
Follow the below steps to run Ente CLI and also avoid keyrings errors.
diff --git a/docs/docs/self-hosting/troubleshooting/misc.md b/docs/docs/self-hosting/troubleshooting/misc.md
index 65c1e7ffd1..ff6ceda762 100644
--- a/docs/docs/self-hosting/troubleshooting/misc.md
+++ b/docs/docs/self-hosting/troubleshooting/misc.md
@@ -3,14 +3,14 @@ title: General troubleshooting cases
description: Fixing various errors when trying to self host Ente
---
-## Functionality not working on self hosted
+## Functionality not working on self hosted instance
If some specific functionality (e.g. album listing, video playback) does not
work on your self hosted instance, it is possible that you have set _some_, but
not _all_ needed CSP headers (by default, CSP is not enabled).
To expand on it - by default, currently the generated build does not enable CSP
-headers. The generated build includes a _headers file that Cloudflare will use
+headers. The generated build includes a \_headers file that Cloudflare will use
to set HTTP response headers, but even these do not enable CSP, it is set to a
report only mode.
@@ -18,7 +18,7 @@ However, your web server might be setting some CSP policy. If so, then you will
need to ensure that all necessary CSP headers are set.
You can see the current
-[_headers](https://github.com/ente-io/ente/blob/main/web/apps/photos/public/_headers)
+[\_headers](https://github.com/ente-io/ente/blob/main/web/apps/photos/public/_headers)
file contents to use a template for your CSP policy. The
`Content-Security-Policy-Report-Only` value will show you the CSP headers in
"dry run" report-only mode we're setting - you can use that as a template,
@@ -28,8 +28,8 @@ How do you know if this is the problem you're facing? The browser console
_might_ be giving you errors when you try to open the page and perform the
corresponding function.
-> Refused to load https://subdomain.example.org/... because it does not appear
-> in the script-src directive of the Content Security Policy.
+> Refused to load https://subdomain.example.org/... because it does not appear
+> in the script-src directive of the Content Security Policy.
This is not guaranteed, each browsers handles CSP errors differently, and some
may silently swallow it.
diff --git a/docs/docs/self-hosting/troubleshooting/uploads.md b/docs/docs/self-hosting/troubleshooting/uploads.md
index 435a5e93c6..6cad97f201 100644
--- a/docs/docs/self-hosting/troubleshooting/uploads.md
+++ b/docs/docs/self-hosting/troubleshooting/uploads.md
@@ -1,13 +1,55 @@
---
-title: Uploads failing
+title: Uploads
description: Fixing upload errors when trying to self host Ente
---
-# Uploads failing
+# Troubleshooting upload failures
-If uploads to your minio are failing, you need to ensure that you've configured
-the S3 bucket `endpoint` in `credentials.yaml` (or `museum.yaml`) to, say,
-`yourserverip:3200`. This can be any host or port, it just need to be a value
-that is reachable from both your client and from museum.
+Here are some errors our community members frequently encountered with the
+context and potential fixes.
-For more details, see [configuring-s3](/self-hosting/guides/configuring-s3).
+Fundamentally in most situations, the problem is because of minor mistakes or
+misconfiguration. Please make sure to reverse proxy museum and MinIO API
+endpoint to a domain and check your S3 credentials and whole configuration file
+for any minor misconfigurations.
+
+It is also suggested that the user setups bucket CORS or global CORS on MinIO or
+any external S3 service provider they are connecting to. To setup bucket CORS,
+please [read this](/self-hosting/troubleshooting/bucket-cors).
+
+## What is S3 and how is it incorporated in Ente ?
+
+S3 is an cloud storage protocol made by Amazon (specifically AWS). S3 is
+designed to store files and data as objects inside buckets and it is mostly used
+for online backups and storing different types of files.
+
+Ente's Docker setup is shipped with [MinIO](https://min.io/) as its default S3
+provider. MinIO supports the Amazon S3 protocol and leverages your disk storage
+to dump all the uploaded files as encrypted object blobs.
+
+## 403 Forbidden
+
+If museum is able to make a network connection to your S3 bucket but uploads are
+still failing, it could be a credentials or permissions issue.
+
+A telltale sign of this is that in the museum logs you can see `403 Forbidden`
+errors about it not able to find the size of a file even though the
+corresponding object exists in the S3 bucket.
+
+This could be because
+
+1. The bucket CORS rules do not allow museum to access these objects. For
+ uploading files from the browser, you will need to set `allowedOrigins` to
+ `*`, and allow the `X-Auth-Token`, `X-Client-Package`, `X-Client-Version`
+ headers configuration too.
+ [Here is an example of a working configuration](https://github.com/ente-io/ente/discussions/1764#discussioncomment-9478204).
+
+2. The credentials are not being picked up (you might be setting the correct
+ credentials, but not in the place where museum reads them from).
+
+## Mismatch in file size
+
+The "Mismatch in file size" error mostly occurs in a situation where the client
+is re-uploading a file which is already in the bucket with a different file
+size. The reason for re-upload could be anything including network issue, sudden
+killing of app before the upload is complete and etc.
diff --git a/docs/docs/self-hosting/troubleshooting/yarn.md b/docs/docs/self-hosting/troubleshooting/yarn.md
index b4205beb0e..4cc62c405b 100644
--- a/docs/docs/self-hosting/troubleshooting/yarn.md
+++ b/docs/docs/self-hosting/troubleshooting/yarn.md
@@ -5,8 +5,8 @@ description: Fixing yarn install errors when trying to self host Ente
# Yarn
-If your `yarn install` is failing, make sure you are using Yarn v1 (also known
-as "Yarn Classic"):
+If `yarn install` is failing, make sure you are using Yarn v1 (also known as
+"Yarn Classic"):
- https://classic.yarnpkg.com/lang/en/docs/install
diff --git a/docs/package.json b/docs/package.json
index bd7635b126..a714aea110 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -5,7 +5,8 @@
"dev": "vitepress dev docs",
"build": "vitepress build docs",
"preview": "vitepress preview docs",
- "pretty": "prettier --write ."
+ "pretty": "prettier --write .",
+ "pretty:check": "prettier -c ."
},
"devDependencies": {
"prettier": "^3.3.4",
diff --git a/infra/copycat-db/src/backup.sh b/infra/copycat-db/src/backup.sh
index f197f4b0f0..bbd8a2bb9e 100755
--- a/infra/copycat-db/src/backup.sh
+++ b/infra/copycat-db/src/backup.sh
@@ -36,7 +36,7 @@ else
BACKUP_ID=$(scw rdb backup create instance-id=$SCW_RDB_INSTANCE_ID \
name=$BACKUP_NAME expires-at=$EXPIRY \
database-name=ente_db -o json | jq -r '.id')
- scw rdb backup wait $BACKUP_ID timeout=5h
+ scw rdb backup wait $BACKUP_ID timeout=8h
scw rdb backup download output=$BACKUP_FILE \
$(scw rdb backup export $BACKUP_ID --wait -o json | jq -r '.id')
fi
diff --git a/infra/staff/src/App.tsx b/infra/staff/src/App.tsx
index 2a754f3bd0..a1bf14d6c8 100644
--- a/infra/staff/src/App.tsx
+++ b/infra/staff/src/App.tsx
@@ -10,10 +10,10 @@ import "./App.css";
import FamilyTableComponent from "./components/FamilyComponentTable";
import StorageBonusTableComponent from "./components/StorageBonusTableComponent";
import TokensTableComponent from "./components/TokenTableComponent";
-import type { UserData } from "./components/UserComponent";
import UserComponent from "./components/UserComponent";
import duckieimage from "./components/duckie.png";
import { apiOrigin } from "./services/support";
+import type { UserData, UserResponse } from "./types";
export let email = "";
export let token = "";
@@ -29,38 +29,6 @@ export const setToken = (newToken: string) => {
export const getEmail = () => email;
export const getToken = () => token;
-interface User {
- ID: string;
- email: string;
- creationTime: number;
-}
-
-interface Subscription {
- productID: string;
- paymentProvider: string;
- expiryTime: number;
- storage: number;
-}
-
-interface Security {
- isEmailMFAEnabled: boolean;
- isTwoFactorEnabled: boolean;
- passkeys: string;
- passkeyCount: number;
- canDisableEmailMFA: boolean;
-}
-
-interface UserResponse {
- user: User;
- subscription: Subscription;
- authCodes?: number;
- details?: {
- usage?: number;
- storageBonus?: number;
- profileData: Security;
- };
-}
-
const App: React.FC = () => {
const [localEmail, setLocalEmail] = useState("");
const [localToken, setLocalToken] = useState("");
@@ -139,7 +107,7 @@ const App: React.FC = () => {
console.log("API Response:", userDataResponse);
const extractedUserData: UserData = {
- User: {
+ user: {
"User ID": userDataResponse.user.ID || "None",
Email: userDataResponse.user.email || "None",
"Creation time":
@@ -147,7 +115,7 @@ const App: React.FC = () => {
userDataResponse.user.creationTime / 1000,
).toLocaleString() || "None",
},
- Storage: {
+ storage: {
Total: userDataResponse.subscription.storage
? userDataResponse.subscription.storage >= 1024 ** 3
? `${(userDataResponse.subscription.storage / 1024 ** 3).toFixed(2)} GB`
@@ -166,7 +134,7 @@ const App: React.FC = () => {
: `${(userDataResponse.details.storageBonus / 1024 ** 2).toFixed(2)} MB`
: "None",
},
- Subscription: {
+ subscription: {
"Product ID":
userDataResponse.subscription.productID || "None",
Provider:
@@ -176,7 +144,7 @@ const App: React.FC = () => {
userDataResponse.subscription.expiryTime / 1000,
).toLocaleString() || "None",
},
- Security: {
+ security: {
"Email MFA": userDataResponse.details?.profileData
.isEmailMFAEnabled
? "Enabled"
diff --git a/infra/staff/src/components/ChangeEmail.tsx b/infra/staff/src/components/ChangeEmail.tsx
index 26407af50e..d3824babc4 100644
--- a/infra/staff/src/components/ChangeEmail.tsx
+++ b/infra/staff/src/components/ChangeEmail.tsx
@@ -10,10 +10,10 @@ import {
import React, { useEffect, useState } from "react";
import { getEmail, getToken } from "../App";
import { apiOrigin } from "../services/support";
-interface ErrorResponse {
- message: string;
-}
+import type { ErrorResponse } from "../types";
+// The below interfaces will only be used in this file
+// hence not including them into a sub-merged types file
interface ChangeEmailProps {
open: boolean;
onClose: () => void;
diff --git a/infra/staff/src/components/CloseFamily.tsx b/infra/staff/src/components/CloseFamily.tsx
index 145c11b505..5ab71bd474 100644
--- a/infra/staff/src/components/CloseFamily.tsx
+++ b/infra/staff/src/components/CloseFamily.tsx
@@ -10,14 +10,7 @@ import {
import React, { useState } from "react";
import { getEmail, getToken } from "../App"; // Import getEmail and getToken functions
import { apiOrigin } from "../services/support";
-
-interface UserData {
- subscription?: {
- userID: string;
- // Add other properties as per your API response structure
- };
- // Add other properties as per your API response structure
-}
+import type { UserData } from "../types";
interface CloseFamilyProps {
open: boolean;
diff --git a/infra/staff/src/components/Disable2FA.tsx b/infra/staff/src/components/Disable2FA.tsx
index 29a3a6cd5a..62166aef24 100644
--- a/infra/staff/src/components/Disable2FA.tsx
+++ b/infra/staff/src/components/Disable2FA.tsx
@@ -10,14 +10,7 @@ import {
import React, { useState } from "react";
import { getEmail, getToken } from "../App"; // Import getEmail and getToken functions
import { apiOrigin } from "../services/support";
-
-interface UserData {
- subscription?: {
- userID: string;
- // Add other properties as per your API response structure
- };
- // Add other properties as per your API response structure
-}
+import type { UserData } from "../types";
interface Disable2FAProps {
open: boolean;
diff --git a/infra/staff/src/components/DisablePasskeys.tsx b/infra/staff/src/components/DisablePasskeys.tsx
index 824b2f2f87..a2757a371d 100644
--- a/infra/staff/src/components/DisablePasskeys.tsx
+++ b/infra/staff/src/components/DisablePasskeys.tsx
@@ -10,20 +10,7 @@ import {
import React, { useState } from "react";
import { getEmail, getToken } from "../App"; // Import getEmail and getToken functions
import { apiOrigin } from "../services/support";
-
-interface UserData {
- subscription?: {
- userID: string;
- // Add other properties as per your API response structure
- };
- // Add other properties as per your API response structure
-}
-
-interface DisablePasskeysProps {
- open: boolean;
- handleClose: () => void;
- handleDisablePasskeys: () => void; // Callback to handle disabling passkeys
-}
+import type { DisablePasskeysProps, UserData } from "../types";
const DisablePasskeys: React.FC = ({
open,
diff --git a/infra/staff/src/components/FamilyComponentTable.tsx b/infra/staff/src/components/FamilyComponentTable.tsx
index 2171b3aeda..77e7a9ed44 100644
--- a/infra/staff/src/components/FamilyComponentTable.tsx
+++ b/infra/staff/src/components/FamilyComponentTable.tsx
@@ -13,23 +13,10 @@ import * as React from "react";
import { useEffect, useState } from "react";
import { getEmail, getToken } from "../App";
import { apiOrigin } from "../services/support";
+import type { FamilyMember, UserData } from "../types";
+import { formatUsageToGB } from "../utils/";
import CloseFamily from "./CloseFamily";
-interface FamilyMember {
- id: string;
- email: string;
- status: string;
- usage: number;
-}
-
-interface UserData {
- details: {
- familyData: {
- members: FamilyMember[];
- };
- };
-}
-
const FamilyTableComponent: React.FC = () => {
const [familyMembers, setFamilyMembers] = useState([]);
const [closeFamilyOpen, setCloseFamilyOpen] = useState(false);
@@ -54,7 +41,7 @@ const FamilyTableComponent: React.FC = () => {
}
const userData = (await response.json()) as UserData; // Typecast to UserData interface
const members: FamilyMember[] =
- userData.details.familyData.members;
+ userData.details?.familyData.members ?? [];
setFamilyMembers(members);
} catch (error) {
console.error("Error fetching family data:", error);
@@ -69,11 +56,6 @@ const FamilyTableComponent: React.FC = () => {
);
}, []);
- const formatUsageToGB = (usage: number): string => {
- const usageInGB = (usage / (1024 * 1024 * 1024)).toFixed(2);
- return `${usageInGB} GB`;
- };
-
const handleOpenCloseFamily = () => {
setCloseFamilyOpen(true);
};
@@ -111,6 +93,9 @@ const FamilyTableComponent: React.FC = () => {
+
+ ID
+
User
@@ -121,13 +106,14 @@ const FamilyTableComponent: React.FC = () => {
Usage
- ID
+ Quota
{familyMembers.map((member) => (
+ {member.id}
{member.email}
{
{formatUsageToGB(member.usage)}
- {member.id}
+
+ {member.status !== "SELF"
+ ? (member.storageLimit &&
+ formatUsageToGB(
+ member.storageLimit,
+ )) ||
+ "NA"
+ : ""}
+
))}
diff --git a/infra/staff/src/components/ToggleEmailMFA.tsx b/infra/staff/src/components/ToggleEmailMFA.tsx
index 0e0a469a73..82e3f28015 100644
--- a/infra/staff/src/components/ToggleEmailMFA.tsx
+++ b/infra/staff/src/components/ToggleEmailMFA.tsx
@@ -10,14 +10,7 @@ import {
import React, { useState } from "react";
import { getEmail, getToken } from "../App"; // Import getEmail and getToken functions
import { apiOrigin } from "../services/support";
-
-interface UserData {
- subscription?: {
- userID: string;
- // Add other properties as per your API response structure
- };
- // Add other properties as per your API response structure
-}
+import type { UserData } from "../types";
interface ToggleEmailMFAProps {
open: boolean;
diff --git a/infra/staff/src/components/UpdateSubscription.tsx b/infra/staff/src/components/UpdateSubscription.tsx
index b1bf7dfea1..1b1806b59a 100644
--- a/infra/staff/src/components/UpdateSubscription.tsx
+++ b/infra/staff/src/components/UpdateSubscription.tsx
@@ -62,8 +62,8 @@ const UpdateSubscription: React.FC = ({
expiryTime: "",
userId: "",
attributes: {
- "customerID": "",
- "stripeAccountCountry": ""
+ customerID: "",
+ stripeAccountCountry: "",
},
});
@@ -108,9 +108,13 @@ const UpdateSubscription: React.FC = ({
expiryTime: expiryTime,
userId: userDataResponse.subscription.userID || "",
attributes: {
- customerID: userDataResponse.subscription.attributes.customerID || "",
- stripeAccountCountry: userDataResponse.subscription.attributes.stripeAccountCountry || ""
- }
+ customerID:
+ userDataResponse.subscription.attributes
+ .customerID || "",
+ stripeAccountCountry:
+ userDataResponse.subscription.attributes
+ .stripeAccountCountry || "",
+ },
});
} catch (error) {
console.error("Error fetching data:", error);
@@ -174,8 +178,9 @@ const UpdateSubscription: React.FC = ({
transactionId: values.transactionId,
attributes: {
customerID: values.attributes.customerID,
- stripeAccountCountry: values.attributes.stripeAccountCountry
- }
+ stripeAccountCountry:
+ values.attributes.stripeAccountCountry,
+ },
};
try {
diff --git a/infra/staff/src/components/UserComponent.tsx b/infra/staff/src/components/UserComponent.tsx
index bc93101960..be2b1afb11 100644
--- a/infra/staff/src/components/UserComponent.tsx
+++ b/infra/staff/src/components/UserComponent.tsx
@@ -13,6 +13,7 @@ import TableContainer from "@mui/material/TableContainer";
import TableRow from "@mui/material/TableRow";
import Typography from "@mui/material/Typography";
import * as React from "react";
+import type { UserComponentProps } from "../types";
import ChangeEmail from "./ChangeEmail";
import DeleteAccount from "./DeleteAccont";
import Disable2FA from "./Disable2FA";
@@ -20,17 +21,6 @@ import DisablePasskeys from "./DisablePasskeys";
import ToggleEmailMFA from "./ToggleEmailMFA";
import UpdateSubscription from "./UpdateSubscription";
-export interface UserData {
- User: Record;
- Storage: Record;
- Subscription: Record;
- Security: Record;
-}
-
-interface UserComponentProps {
- userData: UserData | null;
-}
-
const UserComponent: React.FC = ({ userData }) => {
const [deleteAccountOpen, setDeleteAccountOpen] = React.useState(false);
const [email2FAEnabled, setEmail2FAEnabled] = React.useState(false);
@@ -44,10 +34,10 @@ const UserComponent: React.FC = ({ userData }) => {
const [disablePasskeysOpen, setDisablePasskeysOpen] = React.useState(false);
React.useEffect(() => {
- setTwoFactorEnabled(userData?.Security["Two factor 2FA"] === "Enabled");
- setEmail2FAEnabled(userData?.Security["Email MFA"] === "Enabled");
+ setTwoFactorEnabled(userData?.security["Two factor 2FA"] === "Enabled");
+ setEmail2FAEnabled(userData?.security["Email MFA"] === "Enabled");
setCanDisableEmailMFA(
- userData?.Security["Can Disable EmailMFA"] === "Yes",
+ userData?.security["Can Disable EmailMFA"] === "Yes",
);
}, [userData]);
@@ -148,14 +138,10 @@ const DataTable: React.FC = ({
minHeight: 300,
display: "flex",
flexDirection: "column",
- marginBottom: "20px",
height: "100%",
width: "100%",
- padding: "13px",
+ padding: "10px",
overflowX: "hidden",
- "&:not(:last-child)": {
- marginBottom: "40px",
- },
}}
>
= ({
width: "100%",
}}
>
- {title}
+ {title.charAt(0).toUpperCase() + title.slice(1)}
- {title === "User" && (
+ {title === "user" && (
= ({
)}
- {title === "Subscription" && (
+ {title === "subscription" && (
;
+ storage: Record;
+ subscription?: Record;
+ security: Record;
+ details?: {
+ familyData: {
+ members: FamilyMember[];
+ };
+ };
+}
+
+export interface UserComponentProps {
+ userData: UserData | null;
+}
+
+// Error Response Interface
+export interface ErrorResponse {
+ message: string;
+}
+
+// Types related to Subscriptions
+export interface Subscription {
+ productID: string;
+ paymentProvider: string;
+ expiryTime: number;
+ storage: number;
+}
+
+export interface Security {
+ isEmailMFAEnabled: boolean;
+ isTwoFactorEnabled: boolean;
+ passkeys: string;
+ passkeyCount: number;
+ canDisableEmailMFA: boolean;
+}
+
+// Types related Family
+export interface FamilyMember {
+ id: string;
+ email: string;
+ status: string;
+ usage: number;
+ storageLimit: number;
+}
+
+// Types related to passkeys
+export interface DisablePasskeysProps {
+ open: boolean;
+ handleClose: () => void;
+ handleDisablePasskeys: () => void; // Callback to handle disabling passkeys
+}
diff --git a/infra/staff/src/utils/index.ts b/infra/staff/src/utils/index.ts
new file mode 100644
index 0000000000..46a4bc3fcf
--- /dev/null
+++ b/infra/staff/src/utils/index.ts
@@ -0,0 +1,5 @@
+// Common utilities
+export function formatUsageToGB(usage: number): string {
+ const usageInGB = (usage / (1024 * 1024 * 1024)).toFixed(2);
+ return `${usageInGB} GB`;
+}
diff --git a/infra/staff/src/utils/strings.ts b/infra/staff/src/utils/strings.ts
deleted file mode 100644
index 39b22fcd76..0000000000
--- a/infra/staff/src/utils/strings.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * User facing strings in the app.
- *
- * By keeping them separate, we make our lives easier if/when we need to
- * localize the corresponding pages. Right now, these are just the values in the
- * default language, English.
- */
-const S = {
- hello: "Hello Ente!",
- error_generic: "Oops, something went wrong.",
-};
-
-export default S;
diff --git a/infra/workers/cast-albums/src/index.ts b/infra/workers/cast-albums/src/index.ts
index 5111d446cd..fc93d93443 100644
--- a/infra/workers/cast-albums/src/index.ts
+++ b/infra/workers/cast-albums/src/index.ts
@@ -22,7 +22,8 @@ const handleOPTIONS = (request: Request) => {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Max-Age": "86400",
- "Access-Control-Allow-Headers": "X-Cast-Access-Token",
+ "Access-Control-Allow-Headers":
+ "X-Cast-Access-Token, X-Client-Package, X-Client-Version",
},
});
};
@@ -60,8 +61,15 @@ const handleGET = async (request: Request) => {
const pathname = url.pathname;
const params = new URLSearchParams({ castToken });
+ const headers = {
+ "X-Client-Package": request.headers.get("X-Client-Package") ?? "",
+ "X-Client-Version": request.headers.get("X-Client-Version") ?? "",
+ "User-Agent": request.headers.get("User-Agent") ?? "",
+ };
+
let response = await fetch(
`https://api.ente.io/cast/files${pathname}${fileID}?${params.toString()}`,
+ { headers },
);
if (!response.ok) console.log("Upstream error", response.status);
diff --git a/infra/workers/cast-albums/wrangler.toml b/infra/workers/cast-albums/wrangler.toml
index f81f8b52bf..3496aebe7a 100644
--- a/infra/workers/cast-albums/wrangler.toml
+++ b/infra/workers/cast-albums/wrangler.toml
@@ -1,6 +1,6 @@
name = "cast-albums"
main = "src/index.ts"
-compatibility_date = "2024-06-14"
+compatibility_date = "2025-06-03"
routes = [
{ pattern = "cast-albums.ente.io", custom_domain = true }
diff --git a/infra/workers/csp-reporter/package.json b/infra/workers/csp-reporter/package.json
new file mode 100644
index 0000000000..80c9a9d516
--- /dev/null
+++ b/infra/workers/csp-reporter/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "csp-reporter",
+ "version": "0.0.0",
+ "private": true
+}
diff --git a/infra/workers/csp-reporter/src/index.ts b/infra/workers/csp-reporter/src/index.ts
new file mode 100644
index 0000000000..34af4cd68e
--- /dev/null
+++ b/infra/workers/csp-reporter/src/index.ts
@@ -0,0 +1,23 @@
+/**
+ * Log CSP reports.
+ *
+ * See _headers in the web app source.
+ */
+
+export default {
+ async fetch(request: Request) {
+ switch (request.method) {
+ case "POST":
+ return handlePOST(request);
+ default:
+ console.log(`Unsupported HTTP method ${request.method}`);
+ return new Response(null, { status: 405 });
+ }
+ },
+} satisfies ExportedHandler;
+
+const handlePOST = async (request: Request) => {
+ // {job="worker"} |= `[csp-report]` | json log="logs[0]" | keep log
+ console.log("[csp-report]", await request.text());
+ return new Response(null, { status: 200 });
+};
diff --git a/infra/workers/csp-reporter/tsconfig.json b/infra/workers/csp-reporter/tsconfig.json
new file mode 100644
index 0000000000..a65b752070
--- /dev/null
+++ b/infra/workers/csp-reporter/tsconfig.json
@@ -0,0 +1 @@
+{ "extends": "../tsconfig.base.json", "include": ["src"] }
diff --git a/infra/workers/csp-reporter/wrangler.toml b/infra/workers/csp-reporter/wrangler.toml
new file mode 100644
index 0000000000..8cdc2f9682
--- /dev/null
+++ b/infra/workers/csp-reporter/wrangler.toml
@@ -0,0 +1,9 @@
+name = "csp-reporter"
+main = "src/index.ts"
+compatibility_date = "2025-05-19"
+
+routes = [
+ { pattern = "csp-reporter.ente.io", custom_domain = true }
+]
+
+tail_consumers = [{ service = "tail" }]
diff --git a/infra/workers/files/src/index.ts b/infra/workers/files/src/index.ts
index e855dca243..904a669acc 100644
--- a/infra/workers/files/src/index.ts
+++ b/infra/workers/files/src/index.ts
@@ -21,7 +21,8 @@ const handleOPTIONS = (request: Request) => {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
- "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
+ "Access-Control-Allow-Headers":
+ "X-Auth-Token, X-Client-Package, X-Client-Version, Range",
"Access-Control-Max-Age": "86400",
},
});
@@ -71,13 +72,16 @@ const handleGET = async (request: Request) => {
const params = new URLSearchParams();
if (token) params.set("token", token);
+ const headers = {
+ "X-Client-Package": request.headers.get("X-Client-Package") ?? "",
+ "X-Client-Version": request.headers.get("X-Client-Version") ?? "",
+ "User-Agent": request.headers.get("User-Agent") ?? "",
+ "Range": request.headers.get("Range") ?? "",
+ };
+
let response = await fetch(
`https://api.ente.io/files/download/${fileID}?${params.toString()}`,
- {
- headers: {
- "User-Agent": request.headers.get("User-Agent") ?? "",
- },
- },
+ { headers },
);
if (!response.ok) console.log("Upstream error", response.status);
diff --git a/infra/workers/files/wrangler.toml b/infra/workers/files/wrangler.toml
index 52349d8d03..12e27ade88 100644
--- a/infra/workers/files/wrangler.toml
+++ b/infra/workers/files/wrangler.toml
@@ -1,6 +1,6 @@
name = "files"
main = "src/index.ts"
-compatibility_date = "2024-06-14"
+compatibility_date = "2025-06-03"
routes = [
{ pattern = "files.ente.io", custom_domain = true }
diff --git a/infra/workers/package.json b/infra/workers/package.json
index d9a555362f..7b61f25bd8 100644
--- a/infra/workers/package.json
+++ b/infra/workers/package.json
@@ -2,10 +2,10 @@
"name": "workers",
"private": true,
"devDependencies": {
- "@cloudflare/workers-types": "^4.20240614.0",
- "typescript": "^5",
- "wrangler": "^3",
- "prettier": "^3.3.4"
+ "@cloudflare/workers-types": "^4.20250603.0",
+ "typescript": "^5.8.3",
+ "wrangler": "^4.18.0",
+ "prettier": "^3.5.3"
},
"workspaces": [
"*"
diff --git a/infra/workers/public-albums/src/index.ts b/infra/workers/public-albums/src/index.ts
index 505a474635..75751a867a 100644
--- a/infra/workers/public-albums/src/index.ts
+++ b/infra/workers/public-albums/src/index.ts
@@ -22,7 +22,7 @@ const handleOPTIONS = (request: Request) => {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers":
- "X-Auth-Access-Token, X-Auth-Access-Token-JWT, X-Client-Package",
+ "X-Auth-Access-Token, X-Auth-Access-Token-JWT, X-Client-Package, X-Client-Version",
"Access-Control-Max-Age": "86400",
},
});
@@ -70,8 +70,15 @@ const handleGET = async (request: Request) => {
if (accessToken) params.set("accessToken", accessToken);
if (accessTokenJWT) params.set("accessTokenJWT", accessTokenJWT);
+ const headers = {
+ "X-Client-Package": request.headers.get("X-Client-Package") ?? "",
+ "X-Client-Version": request.headers.get("X-Client-Version") ?? "",
+ "User-Agent": request.headers.get("User-Agent") ?? "",
+ };
+
let response = await fetch(
`https://api.ente.io/public-collection/files${pathname}${fileID}?${params.toString()}`,
+ { headers },
);
if (!response.ok) console.log("Upstream error", response.status);
diff --git a/infra/workers/public-albums/wrangler.toml b/infra/workers/public-albums/wrangler.toml
index 9adad20f04..4643736fd6 100644
--- a/infra/workers/public-albums/wrangler.toml
+++ b/infra/workers/public-albums/wrangler.toml
@@ -1,6 +1,6 @@
name = "public-albums"
main = "src/index.ts"
-compatibility_date = "2024-06-14"
+compatibility_date = "2025-06-03"
routes = [
{ pattern = "public-albums.ente.io", custom_domain = true }
diff --git a/infra/workers/thumbnails/src/index.ts b/infra/workers/thumbnails/src/index.ts
index 9fc23fa52b..2e2bd89733 100644
--- a/infra/workers/thumbnails/src/index.ts
+++ b/infra/workers/thumbnails/src/index.ts
@@ -21,7 +21,8 @@ const handleOPTIONS = (request: Request) => {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
- "Access-Control-Allow-Headers": "X-Auth-Token, X-Client-Package",
+ "Access-Control-Allow-Headers":
+ "X-Auth-Token, X-Client-Package, X-Client-Version",
"Access-Control-Max-Age": "86400",
},
});
@@ -64,8 +65,15 @@ const handleGET = async (request: Request) => {
const params = new URLSearchParams();
if (token) params.set("token", token);
+ const headers = {
+ "X-Client-Package": request.headers.get("X-Client-Package") ?? "",
+ "X-Client-Version": request.headers.get("X-Client-Version") ?? "",
+ "User-Agent": request.headers.get("User-Agent") ?? "",
+ };
+
let response = await fetch(
`https://api.ente.io/files/preview/${fileID}?${params.toString()}`,
+ { headers },
);
if (!response.ok) console.log("Upstream error", response.status);
diff --git a/infra/workers/thumbnails/wrangler.toml b/infra/workers/thumbnails/wrangler.toml
index 8f45b859e8..8c7117c848 100644
--- a/infra/workers/thumbnails/wrangler.toml
+++ b/infra/workers/thumbnails/wrangler.toml
@@ -1,6 +1,6 @@
name = "thumbnails"
main = "src/index.ts"
-compatibility_date = "2024-06-14"
+compatibility_date = "2025-06-03"
routes = [
{ pattern = "thumbnails.ente.io", custom_domain = true }
diff --git a/infra/workers/uploader/src/index.ts b/infra/workers/uploader/src/index.ts
index fb811924be..62396e5c8d 100644
--- a/infra/workers/uploader/src/index.ts
+++ b/infra/workers/uploader/src/index.ts
@@ -28,7 +28,7 @@ const handleOPTIONS = (request: Request) => {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, PUT, OPTIONS",
"Access-Control-Allow-Headers":
- "Content-Type, UPLOAD-URL, X-Client-Package",
+ "Content-Type, UPLOAD-URL, X-Client-Package, X-Client-Version",
"Access-Control-Expose-Headers": "X-Request-Id, CF-Ray",
"Access-Control-Max-Age": "86400",
},
diff --git a/mobile/analysis_options.yaml b/mobile/analysis_options.yaml
index a5fe360712..2d1fb835f0 100644
--- a/mobile/analysis_options.yaml
+++ b/mobile/analysis_options.yaml
@@ -53,7 +53,7 @@ analyzer:
sort_child_properties_last: warning
sort_pub_dependencies: warning
library_private_types_in_public_api: warning
- constant_identifier_names: warning
+ constant_identifier_names: ignore
prefer_const_constructors: warning
prefer_const_declarations: warning
prefer_const_constructors_in_immutables: warning
diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml
index 60f760e2c4..4583051e80 100644
--- a/mobile/android/app/src/main/AndroidManifest.xml
+++ b/mobile/android/app/src/main/AndroidManifest.xml
@@ -8,7 +8,10 @@
android:requestLegacyExternalStorage="true"
android:allowBackup="false"
android:fullBackupContent="false"
- android:largeHeap="true">
+ android:dataExtractionRules="@xml/data_extraction_rules"
+ android:largeHeap="true"
+ android:networkSecurityConfig="@xml/network_security_config"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -177,4 +203,6 @@
+
+
\ No newline at end of file
diff --git a/mobile/android/app/src/main/kotlin/io/ente/photos/EnteAlbumsWidgetProvider.kt b/mobile/android/app/src/main/kotlin/io/ente/photos/EnteAlbumsWidgetProvider.kt
new file mode 100644
index 0000000000..147d5ddea6
--- /dev/null
+++ b/mobile/android/app/src/main/kotlin/io/ente/photos/EnteAlbumsWidgetProvider.kt
@@ -0,0 +1,195 @@
+package io.ente.photos
+
+import android.appwidget.AppWidgetManager
+import android.content.Context
+import android.content.SharedPreferences
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.drawable.BitmapDrawable
+import android.net.Uri
+import android.util.Log
+import android.view.View
+import android.widget.RemoteViews
+import androidx.core.content.ContextCompat
+import es.antonborri.home_widget.HomeWidgetLaunchIntent
+import es.antonborri.home_widget.HomeWidgetProvider
+import java.io.File
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.json.Json
+
+@Serializable
+data class AlbumsFileData(
+ val title: String?,
+ val subText: String?,
+ val generatedId: Int?,
+ val mainKey: String?
+)
+
+class EnteAlbumsWidgetProvider : HomeWidgetProvider() {
+ override fun onUpdate(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetIds: IntArray,
+ widgetData: SharedPreferences
+ ) {
+ appWidgetIds.forEach { widgetId ->
+ val views =
+ RemoteViews(context.packageName, R.layout.albums_widget_layout)
+ .apply {
+ val totalAlbums =
+ widgetData.getInt("totalAlbums", 0)
+ var randomNumber = -1
+ var imagePath: String? = null
+ if (totalAlbums > 0) {
+ randomNumber =
+ (0 until totalAlbums!!).random()
+ imagePath =
+ widgetData.getString(
+ "albums_widget_" +
+ randomNumber,
+ null
+ )
+ }
+ var imageExists: Boolean = false
+ if (imagePath != null) {
+ val imageFile = File(imagePath)
+ imageExists = imageFile.exists()
+ }
+ if (imageExists) {
+ val data =
+ widgetData.getString(
+ "albums_widget_${randomNumber}_data",
+ null
+ )
+ val decoded: AlbumsFileData? =
+ data?.let {
+ Json.decodeFromString<
+ AlbumsFileData>(it)
+ }
+ val title = decoded?.title
+ val subText = decoded?.subText
+ val generatedId = decoded?.generatedId
+ val mainKey = decoded?.mainKey
+
+ val deepLinkUri =
+ Uri.parse(
+ "albumwidget://message?generatedId=${generatedId}&mainKey=${mainKey}&homeWidget"
+ )
+
+ val pendingIntent =
+ HomeWidgetLaunchIntent.getActivity(
+ context,
+ MainActivity::class.java,
+ deepLinkUri
+ )
+
+ setOnClickPendingIntent(
+ R.id.widget_container,
+ pendingIntent
+ )
+
+ Log.d(
+ "EnteAlbumsWidgetProvider",
+ "Image exists: $imagePath"
+ )
+ setViewVisibility(
+ R.id.widget_img,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_subtitle,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_title,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_overlay,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_text,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_container,
+ View.GONE
+ )
+
+ val bitmap: Bitmap =
+ BitmapFactory.decodeFile(imagePath)
+ setImageViewBitmap(R.id.widget_img, bitmap)
+ setTextViewText(R.id.widget_title, title)
+ setTextViewText(
+ R.id.widget_subtitle,
+ subText
+ )
+ } else {
+ // Open App on Widget Click
+ val pendingIntent =
+ HomeWidgetLaunchIntent.getActivity(
+ context,
+ MainActivity::class.java
+ )
+ setOnClickPendingIntent(
+ R.id.widget_container,
+ pendingIntent
+ )
+
+ Log.d(
+ "EnteAlbumsWidgetProvider",
+ "Image doesn't exists"
+ )
+ setViewVisibility(
+ R.id.widget_img,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_subtitle,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_title,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_overlay,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_text,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_container,
+ View.VISIBLE
+ )
+
+ val drawable =
+ ContextCompat.getDrawable(
+ context,
+ R.drawable.ic_albums_widget
+ )
+ val bitmap =
+ (drawable as BitmapDrawable).bitmap
+ setImageViewBitmap(
+ R.id.widget_placeholder,
+ bitmap
+ )
+ }
+ }
+
+ appWidgetManager.updateAppWidget(widgetId, views)
+ }
+ }
+}
diff --git a/mobile/android/app/src/main/kotlin/io/ente/photos/EnteMemoryWidgetProvider.kt b/mobile/android/app/src/main/kotlin/io/ente/photos/EnteMemoryWidgetProvider.kt
index a2a4e09bf7..8e9c0f9d4a 100644
--- a/mobile/android/app/src/main/kotlin/io/ente/photos/EnteMemoryWidgetProvider.kt
+++ b/mobile/android/app/src/main/kotlin/io/ente/photos/EnteMemoryWidgetProvider.kt
@@ -91,10 +91,6 @@ class EnteMemoryWidgetProvider : HomeWidgetProvider() {
R.id.widget_img,
View.VISIBLE
)
- setViewVisibility(
- R.id.widget_placeholder_container,
- View.VISIBLE
- )
setViewVisibility(
R.id.widget_subtitle,
View.VISIBLE
@@ -148,10 +144,6 @@ class EnteMemoryWidgetProvider : HomeWidgetProvider() {
R.id.widget_img,
View.GONE
)
- setViewVisibility(
- R.id.widget_placeholder_container,
- View.GONE
- )
setViewVisibility(
R.id.widget_subtitle,
View.GONE
@@ -181,7 +173,7 @@ class EnteMemoryWidgetProvider : HomeWidgetProvider() {
ContextCompat.getDrawable(
context,
R.drawable
- .ic_home_widget_default
+ .ic_memories_widget
)
val bitmap =
(drawable as BitmapDrawable).bitmap
diff --git a/mobile/android/app/src/main/kotlin/io/ente/photos/EntePeopleWidgetProvider.kt b/mobile/android/app/src/main/kotlin/io/ente/photos/EntePeopleWidgetProvider.kt
new file mode 100644
index 0000000000..70f15a518c
--- /dev/null
+++ b/mobile/android/app/src/main/kotlin/io/ente/photos/EntePeopleWidgetProvider.kt
@@ -0,0 +1,195 @@
+package io.ente.photos
+
+import android.appwidget.AppWidgetManager
+import android.content.Context
+import android.content.SharedPreferences
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.drawable.BitmapDrawable
+import android.net.Uri
+import android.util.Log
+import android.view.View
+import android.widget.RemoteViews
+import androidx.core.content.ContextCompat
+import es.antonborri.home_widget.HomeWidgetLaunchIntent
+import es.antonborri.home_widget.HomeWidgetProvider
+import java.io.File
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.json.Json
+
+@Serializable
+data class PeopleFileData(
+ val title: String?,
+ val subText: String?,
+ val generatedId: Int?,
+ val mainKey: String?
+)
+
+class EntePeopleWidgetProvider : HomeWidgetProvider() {
+ override fun onUpdate(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetIds: IntArray,
+ widgetData: SharedPreferences
+ ) {
+ appWidgetIds.forEach { widgetId ->
+ val views =
+ RemoteViews(context.packageName, R.layout.people_widget_layout)
+ .apply {
+ val totalPeople =
+ widgetData.getInt("totalPeople", 0)
+ var randomNumber = -1
+ var imagePath: String? = null
+ if (totalPeople > 0) {
+ randomNumber =
+ (0 until totalPeople!!).random()
+ imagePath =
+ widgetData.getString(
+ "people_widget_" +
+ randomNumber,
+ null
+ )
+ }
+ var imageExists: Boolean = false
+ if (imagePath != null) {
+ val imageFile = File(imagePath)
+ imageExists = imageFile.exists()
+ }
+ if (imageExists) {
+ val data =
+ widgetData.getString(
+ "people_widget_${randomNumber}_data",
+ null
+ )
+ val decoded: PeopleFileData? =
+ data?.let {
+ Json.decodeFromString<
+ PeopleFileData>(it)
+ }
+ val title = decoded?.title
+ val subText = decoded?.subText
+ val generatedId = decoded?.generatedId
+ val mainKey = decoded?.mainKey
+
+ val deepLinkUri =
+ Uri.parse(
+ "peoplewidget://message?generatedId=${generatedId}&mainKey=${mainKey}&homeWidget"
+ )
+
+ val pendingIntent =
+ HomeWidgetLaunchIntent.getActivity(
+ context,
+ MainActivity::class.java,
+ deepLinkUri
+ )
+
+ setOnClickPendingIntent(
+ R.id.widget_container,
+ pendingIntent
+ )
+
+ Log.d(
+ "EntePeopleWidgetProvider",
+ "Image exists: $imagePath"
+ )
+ setViewVisibility(
+ R.id.widget_img,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_subtitle,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_title,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_overlay,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_text,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_container,
+ View.GONE
+ )
+
+ val bitmap: Bitmap =
+ BitmapFactory.decodeFile(imagePath)
+ setImageViewBitmap(R.id.widget_img, bitmap)
+ setTextViewText(R.id.widget_title, title)
+ setTextViewText(
+ R.id.widget_subtitle,
+ subText
+ )
+ } else {
+ // Open App on Widget Click
+ val pendingIntent =
+ HomeWidgetLaunchIntent.getActivity(
+ context,
+ MainActivity::class.java
+ )
+ setOnClickPendingIntent(
+ R.id.widget_container,
+ pendingIntent
+ )
+
+ Log.d(
+ "EntePeopleWidgetProvider",
+ "Image doesn't exists"
+ )
+ setViewVisibility(
+ R.id.widget_img,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_subtitle,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_title,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_overlay,
+ View.GONE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_text,
+ View.VISIBLE
+ )
+ setViewVisibility(
+ R.id.widget_placeholder_container,
+ View.VISIBLE
+ )
+
+ val drawable =
+ ContextCompat.getDrawable(
+ context,
+ R.drawable.ic_people_widget
+ )
+ val bitmap =
+ (drawable as BitmapDrawable).bitmap
+ setImageViewBitmap(
+ R.id.widget_placeholder,
+ bitmap
+ )
+ }
+ }
+
+ appWidgetManager.updateAppWidget(widgetId, views)
+ }
+ }
+}
diff --git a/mobile/android/app/src/main/res/drawable-hdpi/ic_albums_widget.png b/mobile/android/app/src/main/res/drawable-hdpi/ic_albums_widget.png
new file mode 100644
index 0000000000..41ba0108a9
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-hdpi/ic_albums_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-hdpi/ic_home_widget_default.png b/mobile/android/app/src/main/res/drawable-hdpi/ic_home_widget_default.png
deleted file mode 100644
index 449ea27a83..0000000000
Binary files a/mobile/android/app/src/main/res/drawable-hdpi/ic_home_widget_default.png and /dev/null differ
diff --git a/mobile/android/app/src/main/res/drawable-hdpi/ic_memories_widget.png b/mobile/android/app/src/main/res/drawable-hdpi/ic_memories_widget.png
new file mode 100644
index 0000000000..a5f302a320
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-hdpi/ic_memories_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-hdpi/ic_people_widget.png b/mobile/android/app/src/main/res/drawable-hdpi/ic_people_widget.png
new file mode 100644
index 0000000000..644b416026
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-hdpi/ic_people_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-mdpi/ic_albums_widget.png b/mobile/android/app/src/main/res/drawable-mdpi/ic_albums_widget.png
new file mode 100644
index 0000000000..a9b5792d31
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-mdpi/ic_albums_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-mdpi/ic_home_widget_default.png b/mobile/android/app/src/main/res/drawable-mdpi/ic_home_widget_default.png
deleted file mode 100644
index 4ae54e4339..0000000000
Binary files a/mobile/android/app/src/main/res/drawable-mdpi/ic_home_widget_default.png and /dev/null differ
diff --git a/mobile/android/app/src/main/res/drawable-mdpi/ic_memories_widget.png b/mobile/android/app/src/main/res/drawable-mdpi/ic_memories_widget.png
new file mode 100644
index 0000000000..fdaa8e7d53
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-mdpi/ic_memories_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-mdpi/ic_people_widget.png b/mobile/android/app/src/main/res/drawable-mdpi/ic_people_widget.png
new file mode 100644
index 0000000000..1044dc6b02
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-mdpi/ic_people_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/ic_albums_widget.png b/mobile/android/app/src/main/res/drawable-xhdpi/ic_albums_widget.png
new file mode 100644
index 0000000000..b590f07b24
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xhdpi/ic_albums_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/ic_home_widget_default.png b/mobile/android/app/src/main/res/drawable-xhdpi/ic_home_widget_default.png
deleted file mode 100644
index f158f6a086..0000000000
Binary files a/mobile/android/app/src/main/res/drawable-xhdpi/ic_home_widget_default.png and /dev/null differ
diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/ic_memories_widget.png b/mobile/android/app/src/main/res/drawable-xhdpi/ic_memories_widget.png
new file mode 100644
index 0000000000..25db5c73b6
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xhdpi/ic_memories_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/ic_people_widget.png b/mobile/android/app/src/main/res/drawable-xhdpi/ic_people_widget.png
new file mode 100644
index 0000000000..04e74c6d0b
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xhdpi/ic_people_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/ic_albums_widget.png b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_albums_widget.png
new file mode 100644
index 0000000000..e501c7552b
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_albums_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/ic_home_widget_default.png b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_home_widget_default.png
deleted file mode 100644
index 224d849f3b..0000000000
Binary files a/mobile/android/app/src/main/res/drawable-xxhdpi/ic_home_widget_default.png and /dev/null differ
diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/ic_memories_widget.png b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_memories_widget.png
new file mode 100644
index 0000000000..f42319fb19
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_memories_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/ic_people_widget.png b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_people_widget.png
new file mode 100644
index 0000000000..4a9122ab54
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_people_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_albums_widget.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_albums_widget.png
new file mode 100644
index 0000000000..7ffe666ae9
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_albums_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_home_widget_default.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_home_widget_default.png
deleted file mode 100644
index 066e6e362a..0000000000
Binary files a/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_home_widget_default.png and /dev/null differ
diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_memories_widget.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_memories_widget.png
new file mode 100644
index 0000000000..616d6f3148
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_memories_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_people_widget.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_people_widget.png
new file mode 100644
index 0000000000..f935479c04
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_people_widget.png differ
diff --git a/mobile/android/app/src/main/res/drawable/albums_widget_preview.png b/mobile/android/app/src/main/res/drawable/albums_widget_preview.png
new file mode 100644
index 0000000000..5a7d069ed0
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable/albums_widget_preview.png differ
diff --git a/mobile/android/app/src/main/res/drawable/people_widget_preview.png b/mobile/android/app/src/main/res/drawable/people_widget_preview.png
new file mode 100644
index 0000000000..7501d68098
Binary files /dev/null and b/mobile/android/app/src/main/res/drawable/people_widget_preview.png differ
diff --git a/mobile/android/app/src/main/res/layout/albums_widget_layout.xml b/mobile/android/app/src/main/res/layout/albums_widget_layout.xml
new file mode 100644
index 0000000000..aa63ca753f
--- /dev/null
+++ b/mobile/android/app/src/main/res/layout/albums_widget_layout.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/android/app/src/main/res/layout/memory_widget_layout.xml b/mobile/android/app/src/main/res/layout/memory_widget_layout.xml
index abda81b191..71a7b44089 100644
--- a/mobile/android/app/src/main/res/layout/memory_widget_layout.xml
+++ b/mobile/android/app/src/main/res/layout/memory_widget_layout.xml
@@ -65,15 +65,15 @@
android:id="@+id/widget_placeholder"
android:layout_width="120dp"
android:layout_height="120dp"
- android:src="@drawable/ic_home_widget_default"
+ android:src="@drawable/ic_memories_widget"
android:scaleType="fitCenter" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/android/app/src/main/res/xml/albums_widget.xml b/mobile/android/app/src/main/res/xml/albums_widget.xml
new file mode 100644
index 0000000000..464b74db66
--- /dev/null
+++ b/mobile/android/app/src/main/res/xml/albums_widget.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/mobile/android/app/src/main/res/xml/data_extraction_rules.xml b/mobile/android/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000000..16da40e6d4
--- /dev/null
+++ b/mobile/android/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mobile/android/app/src/main/res/xml/network_security_config.xml b/mobile/android/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000000..a7a11ec732
--- /dev/null
+++ b/mobile/android/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ ente.io
+
+
+
+
+
diff --git a/mobile/android/app/src/main/res/xml/people_widget.xml b/mobile/android/app/src/main/res/xml/people_widget.xml
new file mode 100644
index 0000000000..a6c37ba398
--- /dev/null
+++ b/mobile/android/app/src/main/res/xml/people_widget.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle
index d4d4693541..5f335a8ac0 100644
--- a/mobile/android/build.gradle
+++ b/mobile/android/build.gradle
@@ -12,6 +12,9 @@ allprojects {
maven {
url "${project(':background_fetch').projectDir}/libs"
}
+ maven {
+ url "${project(':ffmpeg_kit_flutter').projectDir}/libs"
+ }
}
}
diff --git a/mobile/assets/2.0x/albums-widget-static.png b/mobile/assets/2.0x/albums-widget-static.png
new file mode 100644
index 0000000000..00bb2ba52a
Binary files /dev/null and b/mobile/assets/2.0x/albums-widget-static.png differ
diff --git a/mobile/assets/2.0x/memories-widget-static.png b/mobile/assets/2.0x/memories-widget-static.png
new file mode 100644
index 0000000000..1e079f1e99
Binary files /dev/null and b/mobile/assets/2.0x/memories-widget-static.png differ
diff --git a/mobile/assets/2.0x/people-widget-static.png b/mobile/assets/2.0x/people-widget-static.png
new file mode 100644
index 0000000000..1e619b26e9
Binary files /dev/null and b/mobile/assets/2.0x/people-widget-static.png differ
diff --git a/mobile/assets/3.0x/albums-widget-static.png b/mobile/assets/3.0x/albums-widget-static.png
new file mode 100644
index 0000000000..9826a8d8c2
Binary files /dev/null and b/mobile/assets/3.0x/albums-widget-static.png differ
diff --git a/mobile/assets/3.0x/memories-widget-static.png b/mobile/assets/3.0x/memories-widget-static.png
new file mode 100644
index 0000000000..dc0cdef537
Binary files /dev/null and b/mobile/assets/3.0x/memories-widget-static.png differ
diff --git a/mobile/assets/3.0x/people-widget-static.png b/mobile/assets/3.0x/people-widget-static.png
new file mode 100644
index 0000000000..aac3ee642c
Binary files /dev/null and b/mobile/assets/3.0x/people-widget-static.png differ
diff --git a/mobile/assets/albums-widget-static.png b/mobile/assets/albums-widget-static.png
new file mode 100644
index 0000000000..9e6ddcf832
Binary files /dev/null and b/mobile/assets/albums-widget-static.png differ
diff --git a/mobile/assets/icons/albums-widget-icon.svg b/mobile/assets/icons/albums-widget-icon.svg
new file mode 100644
index 0000000000..d42448bcef
--- /dev/null
+++ b/mobile/assets/icons/albums-widget-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/mobile/assets/icons/memories-widget-icon.svg b/mobile/assets/icons/memories-widget-icon.svg
new file mode 100644
index 0000000000..7a72222cc7
--- /dev/null
+++ b/mobile/assets/icons/memories-widget-icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/mobile/assets/icons/past-year-memory-icon.svg b/mobile/assets/icons/past-year-memory-icon.svg
new file mode 100644
index 0000000000..4c50152714
--- /dev/null
+++ b/mobile/assets/icons/past-year-memory-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/mobile/assets/icons/people-widget-icon.svg b/mobile/assets/icons/people-widget-icon.svg
new file mode 100644
index 0000000000..3cd1ee3972
--- /dev/null
+++ b/mobile/assets/icons/people-widget-icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/mobile/assets/icons/smart-memory-icon.svg b/mobile/assets/icons/smart-memory-icon.svg
new file mode 100644
index 0000000000..cdc2d89b59
--- /dev/null
+++ b/mobile/assets/icons/smart-memory-icon.svg
@@ -0,0 +1,11 @@
+
diff --git a/mobile/assets/memories-widget-static.png b/mobile/assets/memories-widget-static.png
new file mode 100644
index 0000000000..4f7f546ad7
Binary files /dev/null and b/mobile/assets/memories-widget-static.png differ
diff --git a/mobile/assets/people-widget-static.png b/mobile/assets/people-widget-static.png
new file mode 100644
index 0000000000..038f8eeb81
Binary files /dev/null and b/mobile/assets/people-widget-static.png differ
diff --git a/mobile/fastlane/metadata/android/id/full_description.txt b/mobile/fastlane/metadata/android/id/full_description.txt
index dc5c077a52..7b3deb7985 100644
--- a/mobile/fastlane/metadata/android/id/full_description.txt
+++ b/mobile/fastlane/metadata/android/id/full_description.txt
@@ -1,4 +1,4 @@
-ente merupakan app sederhana yang memungkinkanmu untuk mencadangkan serta membagikan foto dan video.
+ente adalah aplikasi sederhana untuk mencadangkan serta membagikan foto dan video anda.
Jika kamu ingin alternatif Google Photos yang ramah privasi, kamu menemukan app yang tepat. Dengan ente, kenanganmu terenkripsi dari ujung ke ujung (e2ee). Sehingga, hanya kamu yang dapat melihatnya.
diff --git a/mobile/fastlane/metadata/android/pt_PT/full_description.txt b/mobile/fastlane/metadata/android/pt_PT/full_description.txt
index 38a7c1b83f..9cd11069c4 100644
--- a/mobile/fastlane/metadata/android/pt_PT/full_description.txt
+++ b/mobile/fastlane/metadata/android/pt_PT/full_description.txt
@@ -4,33 +4,33 @@ Se busca por uma alternativa do Google Fotos baseada em privacidade, chegaste ao
Temos aplicações de fonte aberta para Android, iOS, sítio web e desktop, e as fotos serão perfeitamente sincronizadas entre todas elas numa maneira de encriptação de ponta a ponta (e2ee).
-Ente também simplifica a partilha dos seus álbuns com os seus entes queridos, mesmo que estes não estejam no ente. Pode partilhar ligações visíveis publicamente, onde podem ver o seu álbum e colaborar adicionando fotografias ao mesmo, mesmo sem uma conta ou aplicação.
+Ente facilita o partilhamento dos seus álbuns com entes queridos, mesmo se não estiverem no ente. Pode partilhar ligações visíveis a público, onde eles podem ver o seu álbum e colaborar a adicionar fotos, mesmo sem uma conta ou a aplicação.
-Os seus dados encriptados são replicados em 3 locais diferentes, incluindo um abrigo de emergência em Paris. Levamos a posteridade a sério e facilitamos a tarefa de garantir que as suas memórias perdurem para além de si.
+Os dados são replicados em 3 localizações diferentes, incluindo um posto em Paris. Levamos a nossa postura a sério e facilitamos para certificarmos que as suas memórias revivam-no.
-Estamos aqui para criar a aplicação de fotografias mais segura de sempre, junte-se à nossa viagem!
+Estamos aqui para fazer a aplicação mais segura do mundo, venha e adere a nossa jornada!
-RECURSOS
-- Cópias de segurança de qualidade original, porque cada pixel é importante
-- Planos familiares, para que possa partilhar o armazenamento com a sua família
-- Álbuns colaborativos, para que possa reunir fotos depois de uma viagem
-- Pastas partilhadas, caso queira que o seu parceiro desfrute dos seus cliques na “Câmara”
-- Links para álbuns, que podem ser protegidas com uma palavra-passe
-- Capacidade de libertar espaço, removendo ficheiros dos quais foi feita uma cópia de segurança segura
-- Apoio humano, porque vale a pena
-- Descrições, para que possa legendar as suas memórias e encontrá-las facilmente
-- Editor de imagens, para dar os retoques finais
-- Favoritar, ocultar e reviver suas memórias, pois elas são preciosas
-- Importação com um clique do Google, da Apple, do seu disco rígido e muito mais
-- Tema escuro, porque as suas fotos ficam bem com ele
+FUNCIONALIDADES
+- Backups com qualidade original, por cada píxel valer a pena
+- Planos em família, para poder partilhar armazenamento com familiares
+- Álbuns de colaboração, para unir fotos depois de uma caminhada
+- Pastas partilhadas, se quiser que o seu parceiro desfrute dos seus cliques na "Câmara"
+- Ligações para álbuns, que podem ser protegidos com uma palavra-passe
+- Possibilidade de liberar espaço, removendo ficheiros que já foram feitos backup
+- Suporte físico, por valer a pena
+- Descrições, para entender as suas memórias e encontrá-las facilmente
+- Editor de imagens, para dar retoques finais
+- Adicionar aos favoritos, obscurecer e reviver as suas memórias, para aqueles tão preciosos
+- Importar num só clique do Google, Apple, e o seu disco rígido e mais
+- Tema escuro, para as suas fotos encaixarem melhor
- 2FA, 3FA, autenticação biométrica
-- e MUITO mais!
+- e MAIS além!
PERMISSÕES
-ente solicita determinadas permissões para servir o objetivo de um fornecedor de armazenamento de fotografias, que pode ser consultado aqui: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+Ente pede por certas permissões para servir o propósito dum provedor de armazenamento de foto, onde pode ser revisto aqui: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
PREÇO
-Não oferecemos planos gratuitos para sempre, porque é importante para nós mantermo-nos sustentáveis e resistirmos ao teste do tempo. Em vez disso, oferecemos planos acessíveis que pode partilhar livremente com a sua família. Pode encontrar mais informações em ente.io.
+Não garantimos planos gratuitos para sempre, já que é importante a nós mantermo-nos sustentáveis e conseguirmos superar o desafio do tempo. Ao invés, garantimos planos acessíveis para poder partilhar livremente com os seus familiares. Para mais informações, consulte "ente.io"
-SUPPORT
-Orgulhamo-nos de oferecer um apoio humano Se for nosso cliente pago, pode contactar team@ente.io e esperar uma resposta da nossa equipa no prazo de 24 horas.
+SUPORTE
+Estamos orgulhosos ao oferecer suporte físico. Se for um cliente pago, pode contactar a nossa equipa através de "team@ente.io" e esperar uma resposta nossa dentro de um dia.
diff --git a/mobile/fastlane/metadata/android/sr/full_description.txt b/mobile/fastlane/metadata/android/sr/full_description.txt
new file mode 100644
index 0000000000..9ba4fe3143
--- /dev/null
+++ b/mobile/fastlane/metadata/android/sr/full_description.txt
@@ -0,0 +1,36 @@
+ente is a simple app to backup and share your photos and videos.
+
+If you've been looking for a privacy-friendly alternative to Google Photos, you've come to the right place. With ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
+
+We have open-source apps across Android, iOS, web and desktop, and your photos will seamlessly sync between all of them in an end-to-end encrypted (e2ee) manner.
+
+ente also makes it simple to share your albums with your loved ones, even if they aren't on ente. You can share publicly viewable links, where they can view your album and collaborate by adding photos to it, even without an account or app.
+
+Your encrypted data is replicated to 3 different locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
+
+We are here to make the safest photos app ever, come join our journey!
+
+FEATURES
+- Original quality backups, because every pixel is important
+- Family plans, so you can share storage with your family
+- Collaborative albums, so you can pool together photos after a trip
+- Shared folders, in case you want your partner to enjoy your "Camera" clicks
+- Album links, that can be protected with a password
+- Ability to free up space, by removing files that have been safely backed up
+- Human support, because you're worth it
+- Descriptions, so you can caption your memories and find them easily
+- Image editor, to add finishing touches
+- Favorite, hide and relive your memories, for they are precious
+- One-click import from Google, Apple, your hard drive and more
+- Dark theme, because your photos look good in it
+- 2FA, 3FA, biometric auth
+- and a LOT more!
+
+PERMISSIONS
+ente requests for certain permissions to serve the purpose of a photo storage provider, which can be reviewed here: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+
+PRICING
+We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
+
+SUPPORT
+We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
diff --git a/mobile/fastlane/metadata/android/sr/short_description.txt b/mobile/fastlane/metadata/android/sr/short_description.txt
new file mode 100644
index 0000000000..7a5fe973db
--- /dev/null
+++ b/mobile/fastlane/metadata/android/sr/short_description.txt
@@ -0,0 +1 @@
+ente is an end-to-end encrypted photo storage app
\ No newline at end of file
diff --git a/mobile/fastlane/metadata/android/sr/title.txt b/mobile/fastlane/metadata/android/sr/title.txt
new file mode 100644
index 0000000000..3a4fed48fe
--- /dev/null
+++ b/mobile/fastlane/metadata/android/sr/title.txt
@@ -0,0 +1 @@
+ente - encrypted photo storage
\ No newline at end of file
diff --git a/mobile/fastlane/metadata/android/tr/full_description.txt b/mobile/fastlane/metadata/android/tr/full_description.txt
index a978db8478..b3da5caaee 100644
--- a/mobile/fastlane/metadata/android/tr/full_description.txt
+++ b/mobile/fastlane/metadata/android/tr/full_description.txt
@@ -15,7 +15,7 @@ ente ayrıca, ente'de olmasalar bile albümlerinizi sevdiklerinizle paylaşmanı
- Aile planları, böylece depolama alanını ailenizle paylaşabilirsiniz
- Seyahatten sonra fotoğrafları bir araya toplayabilmeniz için ortak albümler
- Partnerinizin "Kamera" tıklamalarınızın keyfini çıkarmasını istemeniz durumunda paylaşılan klasörler
-- Parola ile korunabilen ve süresi dolacak şekilde ayarlanabilen albüm bağlantıları
+- Albüm bağlantıları, parolayla korunabilir
- Güvenli bir şekilde yedeklenmiş dosyaları kaldırarak alan boşaltma yeteneği
- İnsan desteği, çünkü sen buna değersin
- Açıklamalar, böylece anılarınıza başlık yazabilir ve onları kolayca bulabilirsiniz
@@ -27,10 +27,10 @@ ente ayrıca, ente'de olmasalar bile albümlerinizi sevdiklerinizle paylaşmanı
- ve çok daha fazlası!
İZİNLER
-bir fotoğraf depolama sağlayıcısının amacına hizmet etmek için belirli izinlere yönelik taleplerde bulunulabilir; bu izinler burada incelenebilir: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
+ente, burada gözden geçirilebilecek bir fotoğraf depolama sağlayıcısının amacına hizmet etmek için belirli izinler ister: https://github.com/ente-io/ente/blob/f-droid/mobile/android/permissions.md
FİYATLANDIRMA
Sonsuza kadar ücretsiz planlar sunmuyoruz, çünkü sürdürülebilir kalmamız ve zamanın testine dayanmamız bizim için önemli. Bunun yerine, ailenizle özgürce paylaşabileceğiniz uygun fiyatlı planlar sunuyoruz. Daha fazla bilgiyi ente.io adresinde bulabilirsiniz.
-🙋DESTEK
+DESTEK
İnsan desteği sunmaktan gurur duyuyoruz. Ücretli müşterimiz iseniz team@ente.io adresine ulaşabilir ve ekibimizden 24 saat içinde yanıt bekleyebilirsiniz.
diff --git a/mobile/fastlane/metadata/ios/sr/description.txt b/mobile/fastlane/metadata/ios/sr/description.txt
new file mode 100644
index 0000000000..a98a74300a
--- /dev/null
+++ b/mobile/fastlane/metadata/ios/sr/description.txt
@@ -0,0 +1,33 @@
+Ente is a simple app to automatically backup and organize your photos and videos.
+
+If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
+
+We have apps across all platforms, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner.
+
+Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links.
+
+Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
+
+We are here to make the safest photos app ever, come join our journey!
+
+FEATURES
+- Original quality backups, because every pixel is important
+- Family plans, so you can share storage with your family
+- Shared folders, in case you want your partner to enjoy your "Camera" clicks
+- Album links, that can be protected with a password and set to expire
+- Ability to free up space, by removing files that have been safely backed up
+- Image editor, to add finishing touches
+- Favorite, hide and relive your memories, for they are precious
+- One-click import from all major storage providers
+- Dark theme, because your photos look good in it
+- 2FA, 3FA, biometric auth
+- and a LOT more!
+
+PRICING
+We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
+
+SUPPORT
+We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
+
+TERMS
+https://ente.io/terms
diff --git a/mobile/fastlane/metadata/ios/sr/keywords.txt b/mobile/fastlane/metadata/ios/sr/keywords.txt
new file mode 100644
index 0000000000..e1462baf51
--- /dev/null
+++ b/mobile/fastlane/metadata/ios/sr/keywords.txt
@@ -0,0 +1 @@
+photos,photography,family,privacy,cloud,backup,videos,photo,encryption,storage,album,alternative
diff --git a/mobile/fastlane/metadata/ios/sr/name.txt b/mobile/fastlane/metadata/ios/sr/name.txt
new file mode 100644
index 0000000000..3a991c4abc
--- /dev/null
+++ b/mobile/fastlane/metadata/ios/sr/name.txt
@@ -0,0 +1 @@
+Ente Photos
diff --git a/mobile/fastlane/metadata/ios/sr/subtitle.txt b/mobile/fastlane/metadata/ios/sr/subtitle.txt
new file mode 100644
index 0000000000..958a35f1c9
--- /dev/null
+++ b/mobile/fastlane/metadata/ios/sr/subtitle.txt
@@ -0,0 +1 @@
+Encrypted photo storage
diff --git a/mobile/fastlane/metadata/ios/tr/description.txt b/mobile/fastlane/metadata/ios/tr/description.txt
index 9ee96f2770..9894ba4860 100644
--- a/mobile/fastlane/metadata/ios/tr/description.txt
+++ b/mobile/fastlane/metadata/ios/tr/description.txt
@@ -14,7 +14,7 @@ Ente, albümlerinizi sevdiklerinizle paylaşmanızı da kolaylaştırıyor. Bunl
- Orijinal kalitede yedekler, çünkü her piksel önemlidir
- Aile planları, böylece depolama alanını ailenizle paylaşabilirsiniz
- Partnerinizin "Kamera" tıklamalarınızın keyfini çıkarmasını istemeniz durumunda paylaşılan klasörler
-- Parola ile korunabilen ve süresi dolacak şekilde ayarlanabilen albüm bağlantıları
+- Albüm bağlantıları, parolayla korunabilir ve son kullanma tarihi ayarlanabilir
- Güvenli bir şekilde yedeklenmiş dosyaları kaldırarak alan boşaltma yeteneği
- Son rötuşları eklemek için görüntü düzenleyici
- Favori, sakla ve anılarını yeniden yaşa, çünkü onlar değerlidir
@@ -26,7 +26,7 @@ Ente, albümlerinizi sevdiklerinizle paylaşmanızı da kolaylaştırıyor. Bunl
FİYATLANDIRMA
Sonsuza kadar ücretsiz planlar sunmuyoruz, çünkü sürdürülebilir kalmamız ve zamanın testine dayanmamız bizim için önemli. Bunun yerine, ailenizle özgürce paylaşabileceğiniz uygun fiyatlı planlar sunuyoruz. Daha fazla bilgiyi ente.io adresinde bulabilirsiniz.
-🙋DESTEK
+DESTEK
İnsan desteği sunmaktan gurur duyuyoruz. Ücretli müşterimiz iseniz team@ente.io adresine ulaşabilir ve ekibimizden 24 saat içinde yanıt bekleyebilirsiniz.
ŞARTLAR
diff --git a/mobile/fastlane/metadata/ios/tr/subtitle.txt b/mobile/fastlane/metadata/ios/tr/subtitle.txt
index e0b41db095..a9dc451727 100644
--- a/mobile/fastlane/metadata/ios/tr/subtitle.txt
+++ b/mobile/fastlane/metadata/ios/tr/subtitle.txt
@@ -1 +1 @@
-Ente - şifrelenmiş depolama sistemi
+Ente şifrelenmiş depolama sistemi
diff --git a/mobile/fastlane/metadata/playstore/sr/full_description.txt b/mobile/fastlane/metadata/playstore/sr/full_description.txt
new file mode 100644
index 0000000000..ec999a783c
--- /dev/null
+++ b/mobile/fastlane/metadata/playstore/sr/full_description.txt
@@ -0,0 +1,30 @@
+Ente is a simple app to automatically backup and organize your photos and videos.
+
+If you've been looking for a privacy-friendly alternative to preserve your memories, you've come to the right place. With Ente, they are stored end-to-end encrypted (e2ee). This means that only you can view them.
+
+We have apps across Android, iOS, web and Desktop, and your photos will seamlessly sync between all your devices in an end-to-end encrypted (e2ee) manner.
+
+Ente also makes it simple to share your albums with your loved ones. You can either share them directly with other Ente users, end-to-end encrypted; or with publicly viewable links.
+
+Your encrypted data is stored across multiple locations, including a fall-out shelter in Paris. We take posterity seriously and make it easy to ensure that your memories outlive you.
+
+We are here to make the safest photos app ever, come join our journey!
+
+✨ FEATURES
+- Original quality backups, because every pixel is important
+- Family plans, so you can share storage with your family
+- Shared folders, in case you want your partner to enjoy your "Camera" clicks
+- Album links, that can be protected with a password and set to expire
+- Ability to free up space, by removing files that have been safely backed up
+- Image editor, to add finishing touches
+- Favorite, hide and relive your memories, for they are precious
+- One-click import from Google, Apple, your hard drive and more
+- Dark theme, because your photos look good in it
+- 2FA, 3FA, biometric auth
+- and a LOT more!
+
+💲 PRICING
+We don't offer forever free plans, because it is important to us that we remain sustainable and withstand the test of time. Instead we offer affordable plans that you can freely share with your family. You can find more information at ente.io.
+
+🙋 SUPPORT
+We take pride in offering human support. If you are our paid customer, you can reach out to team@ente.io and expect a response from our team within 24 hours.
\ No newline at end of file
diff --git a/mobile/fastlane/metadata/playstore/sr/short_description.txt b/mobile/fastlane/metadata/playstore/sr/short_description.txt
new file mode 100644
index 0000000000..6c00229894
--- /dev/null
+++ b/mobile/fastlane/metadata/playstore/sr/short_description.txt
@@ -0,0 +1 @@
+Encrypted photo storage - backup, organize and share your photos and videos
\ No newline at end of file
diff --git a/mobile/fastlane/metadata/playstore/sr/title.txt b/mobile/fastlane/metadata/playstore/sr/title.txt
new file mode 100644
index 0000000000..97fdef3be7
--- /dev/null
+++ b/mobile/fastlane/metadata/playstore/sr/title.txt
@@ -0,0 +1 @@
+Ente Photos
\ No newline at end of file
diff --git a/mobile/fastlane/metadata/playstore/tr/full_description.txt b/mobile/fastlane/metadata/playstore/tr/full_description.txt
index b13229830d..2f66882d32 100644
--- a/mobile/fastlane/metadata/playstore/tr/full_description.txt
+++ b/mobile/fastlane/metadata/playstore/tr/full_description.txt
@@ -14,7 +14,7 @@ Ente, albümlerinizi sevdiklerinizle paylaşmanızı da kolaylaştırıyor. Bunl
- Orijinal kalitede yedekler, çünkü her piksel önemlidir
- Aile planları, böylece depolama alanını ailenizle paylaşabilirsiniz
- Partnerinizin "Kamera" tıklamalarınızın keyfini çıkarmasını istemeniz durumunda paylaşılan klasörler
-- Parola ile korunabilen ve süresi dolacak şekilde ayarlanabilen albüm bağlantıları
+- Albüm bağlantıları, parolayla korunabilir ve son kullanma tarihi ayarlanabilir
- Güvenli bir şekilde yedeklenmiş dosyaları kaldırarak alan boşaltma yeteneği
- Son rötuşları eklemek için görüntü düzenleyici
- Favori, sakla ve anılarını yeniden yaşa, çünkü onlar değerlidir
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AccentColor.colorset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 0000000000..eb87897008
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/AlbumsWidgetDefault.png b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/AlbumsWidgetDefault.png
new file mode 100644
index 0000000000..7ffe666ae9
Binary files /dev/null and b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/AlbumsWidgetDefault.png differ
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/Contents.json
new file mode 100644
index 0000000000..4ed24e6d76
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetDefault.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "AlbumsWidgetDefault.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/AlbumsWidgetPreview.png b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/AlbumsWidgetPreview.png
new file mode 100644
index 0000000000..a0ad77e39c
Binary files /dev/null and b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/AlbumsWidgetPreview.png differ
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/Contents.json
new file mode 100644
index 0000000000..de3cb3c542
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/AlbumsWidgetPreview.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "AlbumsWidgetPreview.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/Contents.json
new file mode 100644
index 0000000000..73c00596a7
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/IconGreen.appiconset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/IconGreen.appiconset/Contents.json
new file mode 100644
index 0000000000..2305880107
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/IconGreen.appiconset/Contents.json
@@ -0,0 +1,35 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EnteAlbumWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/mobile/ios/EnteAlbumWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json
new file mode 100644
index 0000000000..c47b5f2f12
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info": {
+ "author": "xcode",
+ "version": 1
+ }
+}
\ No newline at end of file
diff --git a/mobile/ios/EnteAlbumWidget/EnteAlbumWidget.swift b/mobile/ios/EnteAlbumWidget/EnteAlbumWidget.swift
new file mode 100644
index 0000000000..c6712c7289
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/EnteAlbumWidget.swift
@@ -0,0 +1,261 @@
+//
+// EnteAlbumWidget.swift
+// EnteAlbumWidget
+
+import SwiftUI
+import UIKit
+import WidgetKit
+
+private let widgetGroupId = "group.io.ente.frame.EnteMemoryWidget"
+
+struct Provider: TimelineProvider {
+ let minutes = 15
+ let data = UserDefaults(suiteName: widgetGroupId)
+
+ func placeholder(in _: Context) -> FileEntry {
+ FileEntry(
+ date: Date(), index: nil, imageData: nil, title: "Title", subTitle: "Sub Title",
+ generatedId: nil, mainKey: nil)
+ }
+
+ func getSnapshot(in _: Context, completion: @escaping (FileEntry) -> Void) {
+ let entry = FileEntry(
+ date: Date(), index: -2, imageData: nil, title: "Favorites",
+ subTitle: "May 3, 2021",
+ generatedId: nil, mainKey: nil)
+ completion(entry)
+ }
+
+ func getTimeline(in _: Context, completion: @escaping (Timeline) -> Void) {
+ var entries: [FileEntry] = []
+
+ // Generate a timeline consisting of five entries an hour apart, starting from the current date.
+ let currentDate = Calendar.current.nextDate(
+ after: Date(), matching: DateComponents(second: 0), matchingPolicy: .nextTime,
+ direction: .backward
+ )!
+
+ var totalAlbums =
+ data?.integer(forKey: "totalAlbums")
+
+ if totalAlbums != nil && totalAlbums! > 0 {
+ let count = totalAlbums! > 5 ? 5 : totalAlbums
+ for offset in 0.. WidgetRelevances {
+ // // Generate a list containing the contexts this widget is relevant in.
+ // }
+}
+
+struct FileEntry: TimelineEntry {
+ let date: Date
+ let index: Int?
+ let imageData: String?
+ let title: String?
+ let subTitle: String?
+ var generatedId: Int?
+ var mainKey: String?
+}
+
+struct EnteAlbumWidgetEntryView: View {
+ var entry: Provider.Entry
+ let data = UserDefaults.init(suiteName: widgetGroupId)
+
+ var body: some View {
+ GeometryReader { geometry in
+ ZStack {
+ if let imageData = entry.imageData,
+ let uiImage = UIImage(contentsOfFile: imageData)
+ {
+ Image(uiImage: uiImage)
+ .resizable()
+ .backwardWidgetFullColorRenderingMode()
+ .aspectRatio(contentMode: .fill)
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ .overlay(
+ LinearGradient(
+ gradient: Gradient(colors: [Color.black.opacity(0.7), Color.clear]),
+ startPoint: .bottom,
+ endPoint: .top
+ )
+
+ .frame(height: geometry.size.height * 0.4)
+ .frame(maxHeight: .infinity, alignment: .bottom)
+ .backwardWidgetAccentable(true)
+ )
+ .overlay(
+ VStack(alignment: .leading, spacing: 2) {
+ Text(entry.title ?? "").font(
+ .custom("Inter", size: 14, relativeTo: .caption)
+ ) // Custom with fallback
+ .bold()
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ Text(entry.subTitle ?? "")
+ .font(.custom("Inter", size: 12, relativeTo: .caption2))
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ }
+ .padding(.leading, geometry.size.width * 0.05)
+ .padding(.bottom, geometry.size.height * 0.05),
+ alignment: .bottomLeading
+ )
+ } else if entry.index == -2 {
+ if let uiImage = UIImage(named: "AlbumsWidgetPreview") {
+ Image(uiImage: uiImage)
+ .resizable()
+ .backwardWidgetFullColorRenderingMode()
+ .aspectRatio(contentMode: .fill)
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ .overlay(
+ LinearGradient(
+ gradient: Gradient(colors: [
+ Color.black.opacity(0.7), Color.clear,
+ ]),
+ startPoint: .bottom,
+ endPoint: .top
+ )
+
+ .frame(height: geometry.size.height * 0.4)
+ .frame(maxHeight: .infinity, alignment: .bottom)
+ .backwardWidgetAccentable(true)
+ )
+ .overlay(
+ VStack(alignment: .leading, spacing: 2) {
+ Text(entry.title ?? "").font(
+ .custom("Inter", size: 14, relativeTo: .caption)
+ ) // Custom with fallback
+ .bold()
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ Text(entry.subTitle ?? "")
+ .font(.custom("Inter", size: 12, relativeTo: .caption2))
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ }
+ .padding(.leading, geometry.size.width * 0.05)
+ .padding(.bottom, geometry.size.height * 0.05),
+ alignment: .bottomLeading
+ )
+ }
+ } else if let uiImage = UIImage(named: "AlbumsWidgetDefault") {
+ VStack(spacing: 8) {
+ Spacer()
+ Image(uiImage: uiImage)
+ .resizable()
+ .backwardWidgetFullColorRenderingMode()
+ .aspectRatio(contentMode: .fit)
+ .padding(8)
+
+ Text("Go to Settings -> General to customise the widget")
+ .font(.custom("Inter", size: 12, relativeTo: .caption))
+ .foregroundStyle(.white) // Tint-aware color
+ .multilineTextAlignment(.center)
+ .padding(.bottom, 12)
+ .padding(.horizontal, 8)
+ .backwardWidgetAccentable(true)
+ Spacer()
+ }
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ } else {
+ Color.gray
+ }
+ }
+ .clipped()
+ .edgesIgnoringSafeArea(.all)
+ .widgetURL(
+ URL(
+ string:
+ "albumwidget://message?generatedId=\(entry.generatedId != nil ? String(entry.generatedId!) : "nan")&mainKey=\(entry.mainKey != nil ? entry.mainKey! : "nan")&homeWidget"
+ )
+ )
+ }
+ }
+}
+
+struct EnteAlbumWidget: Widget {
+ let kind: String = "EnteAlbumWidget"
+
+ var body: some WidgetConfiguration {
+ StaticConfiguration(kind: kind, provider: Provider()) { entry in
+ if #available(iOS 17.0, *) {
+ EnteAlbumWidgetEntryView(entry: entry)
+ .containerBackground(.fill.tertiary, for: .widget)
+ } else {
+ EnteAlbumWidgetEntryView(entry: entry)
+ .padding()
+ .background()
+ }
+ }
+ .configurationDisplayName("Albums")
+ .description("See photos from selected albums including your favorites")
+ .contentMarginsDisabled()
+ }
+}
+
+#Preview(as: .systemSmall) {
+ EnteAlbumWidget()
+} timeline: {
+ FileEntry(
+ date: .now, index: -2, imageData: nil, title: nil, subTitle: nil, generatedId: nil,
+ mainKey: nil)
+ FileEntry(
+ date: .now, index: -2, imageData: nil, title: nil, subTitle: nil, generatedId: nil,
+ mainKey: nil)
+}
+
+extension View {
+ @ViewBuilder
+ func backwardWidgetAccentable(_ accentable: Bool = true) -> some View {
+ if #available(iOS 16.0, *) {
+ self.widgetAccentable(accentable)
+ } else {
+ self
+ }
+ }
+}
+
+extension Image {
+ @ViewBuilder
+ func backwardWidgetAccentedRenderingMode(_ isAccentedRenderingMode: Bool = true) -> some View {
+ if #available(iOS 18.0, *) {
+ self.widgetAccentedRenderingMode(isAccentedRenderingMode ? .accented : .fullColor)
+ } else {
+ self
+ }
+ }
+
+ @ViewBuilder
+ func backwardWidgetFullColorRenderingMode() -> some View {
+ backwardWidgetAccentedRenderingMode(false)
+ }
+}
diff --git a/mobile/ios/EnteAlbumWidget/EnteAlbumWidgetBundle.swift b/mobile/ios/EnteAlbumWidget/EnteAlbumWidgetBundle.swift
new file mode 100644
index 0000000000..447511b8ae
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/EnteAlbumWidgetBundle.swift
@@ -0,0 +1,17 @@
+//
+// EnteAlbumWidgetBundle.swift
+// EnteAlbumWidget
+//
+// Created by Prateek Sunal on 5/15/25.
+// Copyright © 2025 The Chromium Authors. All rights reserved.
+//
+
+import WidgetKit
+import SwiftUI
+
+@main
+struct EnteAlbumWidgetBundle: WidgetBundle {
+ var body: some Widget {
+ EnteAlbumWidget()
+ }
+}
diff --git a/mobile/ios/EnteAlbumWidget/Info.plist b/mobile/ios/EnteAlbumWidget/Info.plist
new file mode 100644
index 0000000000..0f118fb75e
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidget/Info.plist
@@ -0,0 +1,11 @@
+
+
+
+
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.widgetkit-extension
+
+
+
diff --git a/mobile/ios/EnteAlbumWidgetExtension.entitlements b/mobile/ios/EnteAlbumWidgetExtension.entitlements
new file mode 100644
index 0000000000..866b9602db
--- /dev/null
+++ b/mobile/ios/EnteAlbumWidgetExtension.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.io.ente.frame.EnteMemoryWidget
+
+
+
diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/Contents.json b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/Contents.json
new file mode 100644
index 0000000000..6939b024f5
--- /dev/null
+++ b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "MemoriesWidgetDefault.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/MemoriesWidgetDefault.png b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/MemoriesWidgetDefault.png
new file mode 100644
index 0000000000..616d6f3148
Binary files /dev/null and b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetDefault.imageset/MemoriesWidgetDefault.png differ
diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/Contents.json b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/Contents.json
new file mode 100644
index 0000000000..b0162fa9b2
--- /dev/null
+++ b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "MemoriesWidgetPreview.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/MemoriesWidgetPreview.png b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/MemoriesWidgetPreview.png
new file mode 100644
index 0000000000..b32ee34731
Binary files /dev/null and b/mobile/ios/EnteMemoryWidget/Assets.xcassets/MemoriesWidgetPreview.imageset/MemoriesWidgetPreview.png differ
diff --git a/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift b/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift
index 0d7d3790e1..8a5e06abe8 100644
--- a/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift
+++ b/mobile/ios/EnteMemoryWidget/EnteMemoryWidget.swift
@@ -1,10 +1,6 @@
//
// EnteMemoryWidget.swift
// EnteMemoryWidget
-//
-// Created by Prateek Sunal on 3/7/25.
-// Copyright © 2025 The Chromium Authors. All rights reserved.
-//
import SwiftUI
import UIKit
@@ -13,7 +9,7 @@ import WidgetKit
private let widgetGroupId = "group.io.ente.frame.EnteMemoryWidget"
struct Provider: TimelineProvider {
- let X = 15
+ let minutes = 15
let data = UserDefaults(suiteName: widgetGroupId)
func placeholder(in _: Context) -> FileEntry {
@@ -47,7 +43,7 @@ struct Provider: TimelineProvider {
for offset in 0.. General to customise the widget")
+ .font(.custom("Inter", size: 12, relativeTo: .caption))
.foregroundStyle(.white) // Tint-aware color
.multilineTextAlignment(.center)
.padding(.bottom, 12)
+ .padding(.horizontal, 8)
.backwardWidgetAccentable(true)
Spacer()
}
@@ -229,8 +213,8 @@ struct EnteMemoryWidget: Widget {
.background()
}
}
- .configurationDisplayName("Your memories")
- .description("See special moments from the past.")
+ .configurationDisplayName("Memories")
+ .description("See special moments from the past")
.contentMarginsDisabled()
}
}
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/AccentColor.colorset/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 0000000000..eb87897008
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/Contents.json
new file mode 100644
index 0000000000..73c00596a7
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/IconGreen.appiconset/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/IconGreen.appiconset/Contents.json
new file mode 100644
index 0000000000..2305880107
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/IconGreen.appiconset/Contents.json
@@ -0,0 +1,35 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/Contents.json
new file mode 100644
index 0000000000..69d59a1081
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "PeopleWidgetDefault.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/PeopleWidgetDefault.png b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/PeopleWidgetDefault.png
new file mode 100644
index 0000000000..f935479c04
Binary files /dev/null and b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetDefault.imageset/PeopleWidgetDefault.png differ
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/Contents.json
new file mode 100644
index 0000000000..47b392a1ff
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "PeopleWidgetPreview.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/PeopleWidgetPreview.png b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/PeopleWidgetPreview.png
new file mode 100644
index 0000000000..b2e27c654c
Binary files /dev/null and b/mobile/ios/EntePeopleWidget/Assets.xcassets/PeopleWidgetPreview.imageset/PeopleWidgetPreview.png differ
diff --git a/mobile/ios/EntePeopleWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/mobile/ios/EntePeopleWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json
new file mode 100644
index 0000000000..eb87897008
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/EntePeopleWidget.swift b/mobile/ios/EntePeopleWidget/EntePeopleWidget.swift
new file mode 100644
index 0000000000..35537c5c1a
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/EntePeopleWidget.swift
@@ -0,0 +1,261 @@
+//
+// EntePeopleWidget.swift
+// EntePeopleWidget
+
+import SwiftUI
+import UIKit
+import WidgetKit
+
+private let widgetGroupId = "group.io.ente.frame.EnteMemoryWidget"
+
+struct Provider: TimelineProvider {
+ let minutes = 15
+ let data = UserDefaults(suiteName: widgetGroupId)
+
+ func placeholder(in _: Context) -> FileEntry {
+ FileEntry(
+ date: Date(), index: nil, imageData: nil, title: "Title", subTitle: "Sub Title",
+ generatedId: nil, mainKey: nil)
+ }
+
+ func getSnapshot(in _: Context, completion: @escaping (FileEntry) -> Void) {
+ let entry = FileEntry(
+ date: Date(), index: -2, imageData: nil, title: "Jane Fonda",
+ subTitle: "Sep 23, 2021",
+ generatedId: nil, mainKey: nil)
+ completion(entry)
+ }
+
+ func getTimeline(in _: Context, completion: @escaping (Timeline) -> Void) {
+ var entries: [FileEntry] = []
+
+ // Generate a timeline consisting of five entries an hour apart, starting from the current date.
+ let currentDate = Calendar.current.nextDate(
+ after: Date(), matching: DateComponents(second: 0), matchingPolicy: .nextTime,
+ direction: .backward
+ )!
+
+ var totalPeople =
+ data?.integer(forKey: "totalPeople")
+
+ if totalPeople != nil && totalPeople! > 0 {
+ let count = totalPeople! > 5 ? 5 : totalPeople
+ for offset in 0.. WidgetRelevances {
+ // // Generate a list containing the contexts this widget is relevant in.
+ // }
+}
+
+struct FileEntry: TimelineEntry {
+ let date: Date
+ let index: Int?
+ let imageData: String?
+ let title: String?
+ let subTitle: String?
+ var generatedId: Int?
+ var mainKey: String?
+}
+
+struct EntePeopleWidgetEntryView: View {
+ var entry: Provider.Entry
+ let data = UserDefaults.init(suiteName: widgetGroupId)
+
+ var body: some View {
+ GeometryReader { geometry in
+ ZStack {
+ if let imageData = entry.imageData,
+ let uiImage = UIImage(contentsOfFile: imageData)
+ {
+ Image(uiImage: uiImage)
+ .resizable()
+ .backwardWidgetFullColorRenderingMode()
+ .aspectRatio(contentMode: .fill)
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ .overlay(
+ LinearGradient(
+ gradient: Gradient(colors: [Color.black.opacity(0.7), Color.clear]),
+ startPoint: .bottom,
+ endPoint: .top
+ )
+
+ .frame(height: geometry.size.height * 0.4)
+ .frame(maxHeight: .infinity, alignment: .bottom)
+ .backwardWidgetAccentable(true)
+ )
+ .overlay(
+ VStack(alignment: .leading, spacing: 2) {
+ Text(entry.title ?? "").font(
+ .custom("Inter", size: 14, relativeTo: .caption)
+ ) // Custom with fallback
+ .bold()
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ Text(entry.subTitle ?? "")
+ .font(.custom("Inter", size: 12, relativeTo: .caption2))
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ }
+ .padding(.leading, geometry.size.width * 0.05)
+ .padding(.bottom, geometry.size.height * 0.05),
+ alignment: .bottomLeading
+ )
+ } else if entry.index == -2 {
+ if let uiImage = UIImage(named: "PeopleWidgetPreview") {
+ Image(uiImage: uiImage)
+ .resizable()
+ .backwardWidgetFullColorRenderingMode()
+ .aspectRatio(contentMode: .fill)
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ .overlay(
+ LinearGradient(
+ gradient: Gradient(colors: [
+ Color.black.opacity(0.7), Color.clear,
+ ]),
+ startPoint: .bottom,
+ endPoint: .top
+ )
+
+ .frame(height: geometry.size.height * 0.4)
+ .frame(maxHeight: .infinity, alignment: .bottom)
+ .backwardWidgetAccentable(true)
+ )
+ .overlay(
+ VStack(alignment: .leading, spacing: 2) {
+ Text(entry.title ?? "").font(
+ .custom("Inter", size: 14, relativeTo: .caption)
+ ) // Custom with fallback
+ .bold()
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ Text(entry.subTitle ?? "")
+ .font(.custom("Inter", size: 12, relativeTo: .caption2))
+ .foregroundStyle(.white)
+ .shadow(radius: 20)
+ }
+ .padding(.leading, geometry.size.width * 0.05)
+ .padding(.bottom, geometry.size.height * 0.05),
+ alignment: .bottomLeading
+ )
+ }
+ } else if let uiImage = UIImage(named: "PeopleWidgetDefault") {
+ VStack(spacing: 8) {
+ Spacer()
+ Image(uiImage: uiImage)
+ .resizable()
+ .backwardWidgetFullColorRenderingMode()
+ .aspectRatio(contentMode: .fit)
+ .padding(8)
+
+ Text("Go to Settings -> General to customise the widget")
+ .font(.custom("Inter", size: 12, relativeTo: .caption))
+ .foregroundStyle(.white) // Tint-aware color
+ .multilineTextAlignment(.center)
+ .padding(.bottom, 12)
+ .padding(.horizontal, 8)
+ .backwardWidgetAccentable(true)
+ Spacer()
+ }
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ } else {
+ Color.gray
+ }
+ }
+ .clipped()
+ .edgesIgnoringSafeArea(.all)
+ .widgetURL(
+ URL(
+ string:
+ "peoplewidget://message?generatedId=\(entry.generatedId != nil ? String(entry.generatedId!) : "nan")&mainKey=\(entry.mainKey != nil ? entry.mainKey! : "nan")&homeWidget"
+ )
+ )
+ }
+ }
+}
+
+struct EntePeopleWidget: Widget {
+ let kind: String = "EntePeopleWidget"
+
+ var body: some WidgetConfiguration {
+ StaticConfiguration(kind: kind, provider: Provider()) { entry in
+ if #available(iOS 17.0, *) {
+ EntePeopleWidgetEntryView(entry: entry)
+ .containerBackground(.fill.tertiary, for: .widget)
+ } else {
+ EntePeopleWidgetEntryView(entry: entry)
+ .padding()
+ .background()
+ }
+ }
+ .configurationDisplayName("People Widget")
+ .description("See photos of your favorite people")
+ .contentMarginsDisabled()
+ }
+}
+
+#Preview(as: .systemSmall) {
+ EntePeopleWidget()
+} timeline: {
+ FileEntry(
+ date: .now, index: -2, imageData: nil, title: nil, subTitle: nil, generatedId: nil,
+ mainKey: nil)
+ FileEntry(
+ date: .now, index: -2, imageData: nil, title: nil, subTitle: nil, generatedId: nil,
+ mainKey: nil)
+}
+
+extension View {
+ @ViewBuilder
+ func backwardWidgetAccentable(_ accentable: Bool = true) -> some View {
+ if #available(iOS 16.0, *) {
+ self.widgetAccentable(accentable)
+ } else {
+ self
+ }
+ }
+}
+
+extension Image {
+ @ViewBuilder
+ func backwardWidgetAccentedRenderingMode(_ isAccentedRenderingMode: Bool = true) -> some View {
+ if #available(iOS 18.0, *) {
+ self.widgetAccentedRenderingMode(isAccentedRenderingMode ? .accented : .fullColor)
+ } else {
+ self
+ }
+ }
+
+ @ViewBuilder
+ func backwardWidgetFullColorRenderingMode() -> some View {
+ backwardWidgetAccentedRenderingMode(false)
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/EntePeopleWidgetBundle.swift b/mobile/ios/EntePeopleWidget/EntePeopleWidgetBundle.swift
new file mode 100644
index 0000000000..e68b752d45
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/EntePeopleWidgetBundle.swift
@@ -0,0 +1,17 @@
+//
+// EntePeopleWidgetBundle.swift
+// EntePeopleWidget
+//
+// Created by Prateek Sunal on 5/15/25.
+// Copyright © 2025 The Chromium Authors. All rights reserved.
+//
+
+import WidgetKit
+import SwiftUI
+
+@main
+struct EntePeopleWidgetBundle: WidgetBundle {
+ var body: some Widget {
+ EntePeopleWidget()
+ }
+}
diff --git a/mobile/ios/EntePeopleWidget/Info.plist b/mobile/ios/EntePeopleWidget/Info.plist
new file mode 100644
index 0000000000..0f118fb75e
--- /dev/null
+++ b/mobile/ios/EntePeopleWidget/Info.plist
@@ -0,0 +1,11 @@
+
+
+
+
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.widgetkit-extension
+
+
+
diff --git a/mobile/ios/EntePeopleWidgetExtension.entitlements b/mobile/ios/EntePeopleWidgetExtension.entitlements
new file mode 100644
index 0000000000..866b9602db
--- /dev/null
+++ b/mobile/ios/EntePeopleWidgetExtension.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.application-groups
+
+ group.io.ente.frame.EnteMemoryWidget
+
+
+
diff --git a/mobile/ios/Flutter/ephemeral/flutter_lldb_helper.py b/mobile/ios/Flutter/ephemeral/flutter_lldb_helper.py
new file mode 100644
index 0000000000..a88caf99df
--- /dev/null
+++ b/mobile/ios/Flutter/ephemeral/flutter_lldb_helper.py
@@ -0,0 +1,32 @@
+#
+# Generated file, do not edit.
+#
+
+import lldb
+
+def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
+ """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
+ base = frame.register["x0"].GetValueAsAddress()
+ page_len = frame.register["x1"].GetValueAsUnsigned()
+
+ # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
+ # first page to see if handled it correctly. This makes diagnosing
+ # misconfiguration (e.g. missing breakpoint) easier.
+ data = bytearray(page_len)
+ data[0:8] = b'IHELPED!'
+
+ error = lldb.SBError()
+ frame.GetThread().GetProcess().WriteMemory(base, data, error)
+ if not error.Success():
+ print(f'Failed to write into {base}[+{page_len}]', error)
+ return
+
+def __lldb_init_module(debugger: lldb.SBDebugger, _):
+ target = debugger.GetDummyTarget()
+ # Caveat: must use BreakpointCreateByRegEx here and not
+ # BreakpointCreateByName. For some reasons callback function does not
+ # get carried over from dummy target for the later.
+ bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
+ bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
+ bp.SetAutoContinue(True)
+ print("-- LLDB integration loaded --")
diff --git a/mobile/ios/Flutter/ephemeral/flutter_lldbinit b/mobile/ios/Flutter/ephemeral/flutter_lldbinit
new file mode 100644
index 0000000000..e3ba6fbedc
--- /dev/null
+++ b/mobile/ios/Flutter/ephemeral/flutter_lldbinit
@@ -0,0 +1,5 @@
+#
+# Generated file, do not edit.
+#
+
+command script import --relative-to-command-file flutter_lldb_helper.py
diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock
index d76dd0c63d..a72d5beab2 100644
--- a/mobile/ios/Podfile.lock
+++ b/mobile/ios/Podfile.lock
@@ -1,7 +1,7 @@
PODS:
- app_links (0.0.2):
- Flutter
- - background_fetch (1.3.7):
+ - background_fetch (1.3.8):
- Flutter
- battery_info (0.0.1):
- Flutter
@@ -20,31 +20,31 @@ PODS:
- Flutter
- file_saver (0.0.1):
- Flutter
- - Firebase/CoreOnly (11.8.0):
- - FirebaseCore (~> 11.8.0)
- - Firebase/Messaging (11.8.0):
+ - Firebase/CoreOnly (11.10.0):
+ - FirebaseCore (~> 11.10.0)
+ - Firebase/Messaging (11.10.0):
- Firebase/CoreOnly
- - FirebaseMessaging (~> 11.8.0)
- - firebase_core (3.12.0):
- - Firebase/CoreOnly (= 11.8.0)
+ - FirebaseMessaging (~> 11.10.0)
+ - firebase_core (3.13.1):
+ - Firebase/CoreOnly (= 11.10.0)
- Flutter
- - firebase_messaging (15.2.3):
- - Firebase/Messaging (= 11.8.0)
+ - firebase_messaging (15.2.6):
+ - Firebase/Messaging (= 11.10.0)
- firebase_core
- Flutter
- - FirebaseCore (11.8.1):
- - FirebaseCoreInternal (~> 11.8.0)
+ - FirebaseCore (11.10.0):
+ - FirebaseCoreInternal (~> 11.10.0)
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/Logger (~> 8.0)
- - FirebaseCoreInternal (11.8.0):
+ - FirebaseCoreInternal (11.10.0):
- "GoogleUtilities/NSData+zlib (~> 8.0)"
- - FirebaseInstallations (11.8.0):
- - FirebaseCore (~> 11.8.0)
+ - FirebaseInstallations (11.10.0):
+ - FirebaseCore (~> 11.10.0)
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4)
- - FirebaseMessaging (11.8.0):
- - FirebaseCore (~> 11.8.0)
+ - FirebaseMessaging (11.10.0):
+ - FirebaseCore (~> 11.10.0)
- FirebaseInstallations (~> 11.0)
- GoogleDataTransport (~> 10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
@@ -75,33 +75,35 @@ PODS:
- Flutter
- flutter_sodium (0.0.1):
- Flutter
+ - flutter_timezone (0.0.1):
+ - Flutter
- fluttertoast (0.0.2):
- Flutter
- GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
- - GoogleUtilities/AppDelegateSwizzler (8.0.2):
+ - GoogleUtilities/AppDelegateSwizzler (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Privacy
- - GoogleUtilities/Environment (8.0.2):
+ - GoogleUtilities/Environment (8.1.0):
- GoogleUtilities/Privacy
- - GoogleUtilities/Logger (8.0.2):
+ - GoogleUtilities/Logger (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- - GoogleUtilities/Network (8.0.2):
+ - GoogleUtilities/Network (8.1.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Privacy
- GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (8.0.2)":
+ - "GoogleUtilities/NSData+zlib (8.1.0)":
- GoogleUtilities/Privacy
- - GoogleUtilities/Privacy (8.0.2)
- - GoogleUtilities/Reachability (8.0.2):
+ - GoogleUtilities/Privacy (8.1.0)
+ - GoogleUtilities/Reachability (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- - GoogleUtilities/UserDefaults (8.0.2):
+ - GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- home_widget (0.0.1):
@@ -127,9 +129,6 @@ PODS:
- libwebp/sharpyuv (1.5.0)
- libwebp/webp (1.5.0):
- libwebp/sharpyuv
- - local_auth_darwin (0.0.1):
- - Flutter
- - FlutterMacOS
- local_auth_ios (0.0.1):
- Flutter
- Mantle (2.2.0):
@@ -154,7 +153,7 @@ PODS:
- nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- - native_video_player (1.0.0):
+ - native_video_player (4.0.0):
- Flutter
- objective_c (0.0.1):
- Flutter
@@ -176,7 +175,7 @@ PODS:
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- - photo_manager (2.0.0):
+ - photo_manager (3.7.1):
- Flutter
- FlutterMacOS
- privacy_screen (0.0.1):
@@ -191,7 +190,7 @@ PODS:
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
- Sentry/HybridSDK (8.46.0)
- - sentry_flutter (8.14.1):
+ - sentry_flutter (8.14.2):
- Flutter
- FlutterMacOS
- Sentry/HybridSDK (= 8.46.0)
@@ -203,27 +202,32 @@ PODS:
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- - sqlite3 (3.49.1):
- - sqlite3/common (= 3.49.1)
- - sqlite3/common (3.49.1)
- - sqlite3/dbstatvtab (3.49.1):
+ - sqlite3 (3.49.2):
+ - sqlite3/common (= 3.49.2)
+ - sqlite3/common (3.49.2)
+ - sqlite3/dbstatvtab (3.49.2):
- sqlite3/common
- - sqlite3/fts5 (3.49.1):
+ - sqlite3/fts5 (3.49.2):
- sqlite3/common
- - sqlite3/perf-threadsafe (3.49.1):
+ - sqlite3/math (3.49.2):
- sqlite3/common
- - sqlite3/rtree (3.49.1):
+ - sqlite3/perf-threadsafe (3.49.2):
+ - sqlite3/common
+ - sqlite3/rtree (3.49.2):
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- Flutter
- FlutterMacOS
- - sqlite3 (~> 3.49.0)
+ - sqlite3 (~> 3.49.2)
- sqlite3/dbstatvtab
- sqlite3/fts5
+ - sqlite3/math
- sqlite3/perf-threadsafe
- sqlite3/rtree
- system_info_plus (0.0.1):
- Flutter
+ - thermal (0.0.1):
+ - Flutter
- ua_client_hints (1.4.1):
- Flutter
- url_launcher_ios (0.0.1):
@@ -259,13 +263,13 @@ DEPENDENCIES:
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- flutter_sodium (from `.symlinks/plugins/flutter_sodium/ios`)
+ - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- home_widget (from `.symlinks/plugins/home_widget/ios`)
- image_editor_common (from `.symlinks/plugins/image_editor_common/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- launcher_icon_switcher (from `.symlinks/plugins/launcher_icon_switcher/ios`)
- - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
- maps_launcher (from `.symlinks/plugins/maps_launcher/ios`)
- media_extension (from `.symlinks/plugins/media_extension/ios`)
@@ -290,6 +294,7 @@ DEPENDENCIES:
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
- system_info_plus (from `.symlinks/plugins/system_info_plus/ios`)
+ - thermal (from `.symlinks/plugins/thermal/ios`)
- ua_client_hints (from `.symlinks/plugins/ua_client_hints/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
@@ -359,6 +364,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
flutter_sodium:
:path: ".symlinks/plugins/flutter_sodium/ios"
+ flutter_timezone:
+ :path: ".symlinks/plugins/flutter_timezone/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
home_widget:
@@ -371,8 +378,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/integration_test/ios"
launcher_icon_switcher:
:path: ".symlinks/plugins/launcher_icon_switcher/ios"
- local_auth_darwin:
- :path: ".symlinks/plugins/local_auth_darwin/darwin"
local_auth_ios:
:path: ".symlinks/plugins/local_auth_ios/ios"
maps_launcher:
@@ -421,6 +426,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
system_info_plus:
:path: ".symlinks/plugins/system_info_plus/ios"
+ thermal:
+ :path: ".symlinks/plugins/thermal/ios"
ua_client_hints:
:path: ".symlinks/plugins/ua_client_hints/ios"
url_launcher_ios:
@@ -436,40 +443,40 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7
- background_fetch: 94b36ee293e82972852dba8ede1fbcd3bd3d9d57
+ background_fetch: 851122c99dc3f25a011a6aebec5379ccdf4ab5eb
battery_info: 83f3aae7be2fccefab1d2bf06b8aa96f11c8bcdd
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
cupertino_http: 94ac07f5ff090b8effa6c5e2c47871d48ab7c86c
dart_ui_isolate: 46f6714abe6891313267153ef6f9748d8ecfcab1
- device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
+ device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
ffmpeg_kit_custom: 682b4f2f1ff1f8abae5a92f6c3540f2441d5be99
ffmpeg_kit_flutter: 915b345acc97d4142e8a9a8549d177ff10f043f5
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
- Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf
- firebase_core: 6cbed78b4f298ed103a9fd034e6dbc846320480f
- firebase_messaging: 5e0adf2eb18b0ee59aa0c109314c091a0497ecac
- FirebaseCore: 99fe0c4b44a39f37d99e6404e02009d2db5d718d
- FirebaseCoreInternal: df24ce5af28864660ecbd13596fc8dd3a8c34629
- FirebaseInstallations: 6c963bd2a86aca0481eef4f48f5a4df783ae5917
- FirebaseMessaging: 487b634ccdf6f7b7ff180fdcb2a9935490f764e8
+ Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
+ firebase_core: ba71b44041571da878cb624ce0d80250bcbe58ad
+ firebase_messaging: 13129fe2ca166d1ed2d095062d76cee88943d067
+ FirebaseCore: 8344daef5e2661eb004b177488d6f9f0f24251b7
+ FirebaseCoreInternal: ef4505d2afb1d0ebbc33162cb3795382904b5679
+ FirebaseInstallations: 9980995bdd06ec8081dfb6ab364162bdd64245c3
+ FirebaseMessaging: 2b9f56aa4ed286e1f0ce2ee1d413aabb8f9f5cb9
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_email_sender: aa1e9772696691d02cd91fea829856c11efb8e58
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
- flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
+ flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145
- flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
+ flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
flutter_sodium: 7e4621538491834eba53bd524547854bcbbd6987
+ flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
- GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
+ GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
image_editor_common: 3de87e7c4804f4ae24c8f8a998362b98c105cac1
in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
launcher_icon_switcher: 84c218d233505aa7d8655d8fa61a3ba802c022da
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
- local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
local_auth_ios: f7a1841beef3151d140a967c2e46f30637cdf451
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45
@@ -480,7 +487,7 @@ SPEC CHECKSUMS:
motionphoto: 23e2aeb5c6380112f69468d71f970fa7438e5ed1
move_to_background: 7e3467dd2a1d1013e98c9c1cb93fd53cd7ef9d84
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
- native_video_player: e363dd14f6a498ad8a8f7e6486a0db046ad19f13
+ native_video_player: 6809dec117e8997161dbfb42a6f90d6df71a504d
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
onnxruntime: f9b296392c96c42882be020a59dbeac6310d81b2
onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c
@@ -490,26 +497,27 @@ SPEC CHECKSUMS:
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
- photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413
+ photo_manager: 1d80ae07a89a67dfbcae95953a1e5a24af7c3e62
privacy_screen: 3159a541f5d3a31bea916cfd4e58f9dc722b3fd4
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Sentry: da60d980b197a46db0b35ea12cb8f39af48d8854
- sentry_flutter: 942017adbe00f963061cb11ec260414a990b7a42
+ sentry_flutter: 27892878729f42701297c628eb90e7c6529f3684
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
- sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
- sqlite3_flutter_libs: 3c323550ef3b928bc0aa9513c841e45a7d242832
+ sqlite3: 3c950dc86011117c307eb0b28c4a7bb449dce9f1
+ sqlite3_flutter_libs: 74334e3ef2dbdb7d37e50859bb45da43935779c4
system_info_plus: 555ce7047fbbf29154726db942ae785c29211740
+ thermal: d4c48be750d1ddbab36b0e2dcb2471531bc8df41
ua_client_hints: 92fe0d139619b73ec9fcb46cc7e079a26178f586
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
video_thumbnail: 584ccfa55d8fd2f3d5507218b0a18d84c839c620
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
- wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
+ wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
PODFILE CHECKSUM: a8ef88ad74ba499756207e7592c6071a96756d18
diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj
index 678d1e3446..caaa39afbc 100644
--- a/mobile/ios/Runner.xcodeproj/project.pbxproj
+++ b/mobile/ios/Runner.xcodeproj/project.pbxproj
@@ -16,6 +16,12 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ CEE166242DD5E7820012CF61 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83C2B755B0600BA9516 /* WidgetKit.framework */; };
+ CEE166252DD5E7820012CF61 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83E2B755B0600BA9516 /* SwiftUI.framework */; };
+ CEE166302DD5E7830012CF61 /* EnteAlbumWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = CEE166232DD5E7820012CF61 /* EnteAlbumWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ CEE1667C2DD5F6F20012CF61 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83C2B755B0600BA9516 /* WidgetKit.framework */; };
+ CEE1667D2DD5F6F20012CF61 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83E2B755B0600BA9516 /* SwiftUI.framework */; };
+ CEE166882DD5F6F30012CF61 /* EntePeopleWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = CEE1667B2DD5F6F20012CF61 /* EntePeopleWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
CEE6BE702D7AE7FD00E4048B /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83C2B755B0600BA9516 /* WidgetKit.framework */; };
CEE6BE712D7AE7FD00E4048B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DACD83E2B755B0600BA9516 /* SwiftUI.framework */; };
CEE6BE7C2D7AE7FE00E4048B /* EnteMemoryWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = CEE6BE6F2D7AE7FD00E4048B /* EnteMemoryWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
@@ -23,6 +29,20 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
+ CEE1662E2DD5E7830012CF61 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = CEE166222DD5E7820012CF61;
+ remoteInfo = EnteAlbumWidgetExtension;
+ };
+ CEE166862DD5F6F30012CF61 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = CEE1667A2DD5F6F20012CF61;
+ remoteInfo = EntePeopleWidgetExtension;
+ };
CEE6BE7A2D7AE7FE00E4048B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
@@ -39,7 +59,9 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
+ CEE166302DD5E7830012CF61 /* EnteAlbumWidgetExtension.appex in Embed Foundation Extensions */,
CEE6BE7C2D7AE7FE00E4048B /* EnteMemoryWidgetExtension.appex in Embed Foundation Extensions */,
+ CEE166882DD5F6F30012CF61 /* EntePeopleWidgetExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
@@ -79,6 +101,10 @@
A78E51A260432466D4C456A9 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
BB097BB5EB0EEB41344338D2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
CE93A9062D808893005CD942 /* EnteMemoryWidgetExtensionDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EnteMemoryWidgetExtensionDebug.entitlements; sourceTree = ""; };
+ CEE166232DD5E7820012CF61 /* EnteAlbumWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EnteAlbumWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ CEE166362DD5E7950012CF61 /* EnteAlbumWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EnteAlbumWidgetExtension.entitlements; sourceTree = ""; };
+ CEE1667B2DD5F6F20012CF61 /* EntePeopleWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EntePeopleWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ CEE1668E2DD5F70F0012CF61 /* EntePeopleWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EntePeopleWidgetExtension.entitlements; sourceTree = ""; };
CEE6BE6F2D7AE7FD00E4048B /* EnteMemoryWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = EnteMemoryWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
CEE6BE822D7AE8C700E4048B /* EnteMemoryWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EnteMemoryWidgetExtension.entitlements; sourceTree = ""; };
DA8D6672273BBB59007651D4 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; };
@@ -86,6 +112,20 @@
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
+ CEE166342DD5E7830012CF61 /* Exceptions for "EnteAlbumWidget" folder in "EnteAlbumWidgetExtension" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ Info.plist,
+ );
+ target = CEE166222DD5E7820012CF61 /* EnteAlbumWidgetExtension */;
+ };
+ CEE1668C2DD5F6F30012CF61 /* Exceptions for "EntePeopleWidget" folder in "EntePeopleWidgetExtension" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ Info.plist,
+ );
+ target = CEE1667A2DD5F6F20012CF61 /* EntePeopleWidgetExtension */;
+ };
CEE6BE802D7AE7FE00E4048B /* Exceptions for "EnteMemoryWidget" folder in "EnteMemoryWidgetExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
@@ -96,6 +136,30 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
+ CEE166262DD5E7820012CF61 /* EnteAlbumWidget */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ exceptions = (
+ CEE166342DD5E7830012CF61 /* Exceptions for "EnteAlbumWidget" folder in "EnteAlbumWidgetExtension" target */,
+ );
+ explicitFileTypes = {
+ };
+ explicitFolders = (
+ );
+ path = EnteAlbumWidget;
+ sourceTree = "";
+ };
+ CEE1667E2DD5F6F20012CF61 /* EntePeopleWidget */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ exceptions = (
+ CEE1668C2DD5F6F30012CF61 /* Exceptions for "EntePeopleWidget" folder in "EntePeopleWidgetExtension" target */,
+ );
+ explicitFileTypes = {
+ };
+ explicitFolders = (
+ );
+ path = EntePeopleWidget;
+ sourceTree = "";
+ };
CEE6BE722D7AE7FD00E4048B /* EnteMemoryWidget */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
@@ -120,6 +184,24 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ CEE166202DD5E7820012CF61 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CEE166252DD5E7820012CF61 /* SwiftUI.framework in Frameworks */,
+ CEE166242DD5E7820012CF61 /* WidgetKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CEE166782DD5F6F20012CF61 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CEE1667D2DD5F6F20012CF61 /* SwiftUI.framework in Frameworks */,
+ CEE1667C2DD5F6F20012CF61 /* WidgetKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
CEE6BE6C2D7AE7FD00E4048B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -146,12 +228,16 @@
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
+ CEE1668E2DD5F70F0012CF61 /* EntePeopleWidgetExtension.entitlements */,
+ CEE166362DD5E7950012CF61 /* EnteAlbumWidgetExtension.entitlements */,
CE93A9062D808893005CD942 /* EnteMemoryWidgetExtensionDebug.entitlements */,
CEE6BE822D7AE8C700E4048B /* EnteMemoryWidgetExtension.entitlements */,
2772189F270F596900FFE3CC /* GoogleService-Info.plist */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
CEE6BE722D7AE7FD00E4048B /* EnteMemoryWidget */,
+ CEE166262DD5E7820012CF61 /* EnteAlbumWidget */,
+ CEE1667E2DD5F6F20012CF61 /* EntePeopleWidget */,
97C146EF1CF9000F007C117D /* Products */,
AC6CA265BB505D982CB00391 /* Pods */,
C6A22658E77FF012720BEDDA /* Frameworks */,
@@ -163,6 +249,8 @@
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
CEE6BE6F2D7AE7FD00E4048B /* EnteMemoryWidgetExtension.appex */,
+ CEE166232DD5E7820012CF61 /* EnteAlbumWidgetExtension.appex */,
+ CEE1667B2DD5F6F20012CF61 /* EntePeopleWidgetExtension.appex */,
);
name = Products;
sourceTree = "";
@@ -235,12 +323,54 @@
);
dependencies = (
CEE6BE7B2D7AE7FE00E4048B /* PBXTargetDependency */,
+ CEE1662F2DD5E7830012CF61 /* PBXTargetDependency */,
+ CEE166872DD5F6F30012CF61 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
+ CEE166222DD5E7820012CF61 /* EnteAlbumWidgetExtension */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = CEE166352DD5E7830012CF61 /* Build configuration list for PBXNativeTarget "EnteAlbumWidgetExtension" */;
+ buildPhases = (
+ CEE1661F2DD5E7820012CF61 /* Sources */,
+ CEE166202DD5E7820012CF61 /* Frameworks */,
+ CEE166212DD5E7820012CF61 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ CEE166262DD5E7820012CF61 /* EnteAlbumWidget */,
+ );
+ name = EnteAlbumWidgetExtension;
+ productName = EnteAlbumWidgetExtension;
+ productReference = CEE166232DD5E7820012CF61 /* EnteAlbumWidgetExtension.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
+ CEE1667A2DD5F6F20012CF61 /* EntePeopleWidgetExtension */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = CEE1668D2DD5F6F30012CF61 /* Build configuration list for PBXNativeTarget "EntePeopleWidgetExtension" */;
+ buildPhases = (
+ CEE166772DD5F6F20012CF61 /* Sources */,
+ CEE166782DD5F6F20012CF61 /* Frameworks */,
+ CEE166792DD5F6F20012CF61 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ CEE1667E2DD5F6F20012CF61 /* EntePeopleWidget */,
+ );
+ name = EntePeopleWidgetExtension;
+ productName = EntePeopleWidgetExtension;
+ productReference = CEE1667B2DD5F6F20012CF61 /* EntePeopleWidgetExtension.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
CEE6BE6E2D7AE7FD00E4048B /* EnteMemoryWidgetExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = CEE6BE812D7AE7FE00E4048B /* Build configuration list for PBXNativeTarget "EnteMemoryWidgetExtension" */;
@@ -267,7 +397,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastSwiftUpdateCheck = 1620;
+ LastSwiftUpdateCheck = 1630;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
@@ -276,6 +406,12 @@
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
};
+ CEE166222DD5E7820012CF61 = {
+ CreatedOnToolsVersion = 16.3;
+ };
+ CEE1667A2DD5F6F20012CF61 = {
+ CreatedOnToolsVersion = 16.3;
+ };
CEE6BE6E2D7AE7FD00E4048B = {
CreatedOnToolsVersion = 16.2;
};
@@ -296,6 +432,8 @@
targets = (
97C146ED1CF9000F007C117D /* Runner */,
CEE6BE6E2D7AE7FD00E4048B /* EnteMemoryWidgetExtension */,
+ CEE166222DD5E7820012CF61 /* EnteAlbumWidgetExtension */,
+ CEE1667A2DD5F6F20012CF61 /* EntePeopleWidgetExtension */,
);
};
/* End PBXProject section */
@@ -314,6 +452,20 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ CEE166212DD5E7820012CF61 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CEE166792DD5F6F20012CF61 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
CEE6BE6D2D7AE7FD00E4048B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -389,6 +541,7 @@
"${BUILT_PRODUCTS_DIR}/flutter_native_splash/flutter_native_splash.framework",
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
"${BUILT_PRODUCTS_DIR}/flutter_sodium/flutter_sodium.framework",
+ "${BUILT_PRODUCTS_DIR}/flutter_timezone/flutter_timezone.framework",
"${BUILT_PRODUCTS_DIR}/fluttertoast/fluttertoast.framework",
"${BUILT_PRODUCTS_DIR}/home_widget/home_widget.framework",
"${BUILT_PRODUCTS_DIR}/image_editor_common/image_editor_common.framework",
@@ -396,7 +549,6 @@
"${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework",
"${BUILT_PRODUCTS_DIR}/launcher_icon_switcher/launcher_icon_switcher.framework",
"${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework",
- "${BUILT_PRODUCTS_DIR}/local_auth_darwin/local_auth_darwin.framework",
"${BUILT_PRODUCTS_DIR}/local_auth_ios/local_auth_ios.framework",
"${BUILT_PRODUCTS_DIR}/maps_launcher/maps_launcher.framework",
"${BUILT_PRODUCTS_DIR}/media_extension/media_extension.framework",
@@ -421,6 +573,7 @@
"${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework",
"${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework",
"${BUILT_PRODUCTS_DIR}/system_info_plus/system_info_plus.framework",
+ "${BUILT_PRODUCTS_DIR}/thermal/thermal.framework",
"${BUILT_PRODUCTS_DIR}/ua_client_hints/ua_client_hints.framework",
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
"${BUILT_PRODUCTS_DIR}/video_player_avfoundation/video_player_avfoundation.framework",
@@ -483,6 +636,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_native_splash.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_sodium.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_timezone.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/home_widget.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_editor_common.framework",
@@ -490,7 +644,6 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/launcher_icon_switcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework",
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth_darwin.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/maps_launcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/media_extension.framework",
@@ -515,6 +668,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/system_info_plus.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/thermal.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ua_client_hints.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player_avfoundation.framework",
@@ -607,6 +761,20 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ CEE1661F2DD5E7820012CF61 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CEE166772DD5F6F20012CF61 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
CEE6BE6B2D7AE7FD00E4048B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -617,6 +785,16 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
+ CEE1662F2DD5E7830012CF61 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = CEE166222DD5E7820012CF61 /* EnteAlbumWidgetExtension */;
+ targetProxy = CEE1662E2DD5E7830012CF61 /* PBXContainerItemProxy */;
+ };
+ CEE166872DD5F6F30012CF61 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = CEE1667A2DD5F6F20012CF61 /* EntePeopleWidgetExtension */;
+ targetProxy = CEE166862DD5F6F30012CF61 /* PBXContainerItemProxy */;
+ };
CEE6BE7B2D7AE7FE00E4048B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = CEE6BE6E2D7AE7FD00E4048B /* EnteMemoryWidgetExtension */;
@@ -949,6 +1127,250 @@
};
name = Release;
};
+ CEE166312DD5E7830012CF61 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = EnteAlbumWidgetExtension.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6Z68YJY9Q2;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = EnteAlbumWidget/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = EnteAlbumWidget;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.debug.EnteAlbumWidget;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ CEE166322DD5E7830012CF61 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = EnteAlbumWidgetExtension.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6Z68YJY9Q2;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = EnteAlbumWidget/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = EnteAlbumWidget;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.EnteAlbumWidget;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ CEE166332DD5E7830012CF61 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = EnteAlbumWidgetExtension.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6Z68YJY9Q2;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = EnteAlbumWidget/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = EnteAlbumWidget;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.EnteAlbumWidget;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Profile;
+ };
+ CEE166892DD5F6F30012CF61 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = EntePeopleWidgetExtension.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6Z68YJY9Q2;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = EntePeopleWidget/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = EntePeopleWidget;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.debug.EntePeopleWidget;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ CEE1668A2DD5F6F30012CF61 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = EntePeopleWidgetExtension.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6Z68YJY9Q2;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = EntePeopleWidget/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = EntePeopleWidget;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.EntePeopleWidget;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ CEE1668B2DD5F6F30012CF61 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = EntePeopleWidgetExtension.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 6Z68YJY9Q2;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = EntePeopleWidget/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = EntePeopleWidget;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 The Chromium Authors. All rights reserved.";
+ IPHONEOS_DEPLOYMENT_TARGET = 18.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = io.ente.frame.EntePeopleWidget;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Profile;
+ };
CEE6BE7D2D7AE7FE00E4048B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -1094,6 +1516,26 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ CEE166352DD5E7830012CF61 /* Build configuration list for PBXNativeTarget "EnteAlbumWidgetExtension" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ CEE166312DD5E7830012CF61 /* Debug */,
+ CEE166322DD5E7830012CF61 /* Release */,
+ CEE166332DD5E7830012CF61 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ CEE1668D2DD5F6F30012CF61 /* Build configuration list for PBXNativeTarget "EntePeopleWidgetExtension" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ CEE166892DD5F6F30012CF61 /* Debug */,
+ CEE1668A2DD5F6F30012CF61 /* Release */,
+ CEE1668B2DD5F6F30012CF61 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
CEE6BE812D7AE7FE00E4048B /* Build configuration list for PBXNativeTarget "EnteMemoryWidgetExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 5e31d3d342..9c12df59c6 100644
--- a/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/mobile/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
diff --git a/mobile/l10n.yaml b/mobile/l10n.yaml
deleted file mode 100644
index b522046b57..0000000000
--- a/mobile/l10n.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-arb-dir: lib/l10n
-template-arb-file: intl_en.arb
-output-localization-file: app_localizations.dart
\ No newline at end of file
diff --git a/mobile/lib/app.dart b/mobile/lib/app.dart
index 3b8e3346d8..3f309bd886 100644
--- a/mobile/lib/app.dart
+++ b/mobile/lib/app.dart
@@ -6,23 +6,26 @@ import 'package:background_fetch/background_fetch.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import "package:flutter_localizations/flutter_localizations.dart";
import 'package:home_widget/home_widget.dart' as hw;
import 'package:logging/logging.dart';
import 'package:media_extension/media_extension_action_types.dart';
import "package:photos/core/event_bus.dart";
import 'package:photos/ente_theme_data.dart';
import "package:photos/events/memories_changed_event.dart";
+import "package:photos/events/people_changed_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/l10n/l10n.dart";
import "package:photos/service_locator.dart";
import 'package:photos/services/app_lifecycle_service.dart';
import "package:photos/services/home_widget_service.dart";
import "package:photos/services/memory_home_widget_service.dart";
+import "package:photos/services/people_home_widget_service.dart";
import 'package:photos/services/sync/sync_service.dart';
import 'package:photos/ui/tabs/home_widget.dart';
import "package:photos/ui/viewer/actions/file_viewer.dart";
import "package:photos/utils/intent_util.dart";
+import "package:photos/utils/standalone/debouncer.dart";
class EnteApp extends StatefulWidget {
final Future Function(String) runBackgroundTask;
@@ -51,6 +54,8 @@ class _EnteAppState extends State with WidgetsBindingObserver {
final _logger = Logger("EnteAppState");
late Locale? locale;
late StreamSubscription _memoriesChangedSubscription;
+ late StreamSubscription _peopleChangedSubscription;
+ late Debouncer _changeCallbackDebouncer;
@override
void initState() {
@@ -69,6 +74,15 @@ class _EnteAppState extends State with WidgetsBindingObserver {
await MemoryHomeWidgetService.instance.memoryChanged();
},
);
+ _changeCallbackDebouncer = Debouncer(const Duration(milliseconds: 1500));
+ _peopleChangedSubscription = Bus.instance.on().listen(
+ (event) async {
+ _changeCallbackDebouncer.run(
+ () async =>
+ unawaited(PeopleHomeWidgetService.instance.peopleChanged()),
+ );
+ },
+ );
}
@override
@@ -107,7 +121,7 @@ class _EnteAppState extends State with WidgetsBindingObserver {
if (Platform.isAndroid || kDebugMode) {
return Listener(
onPointerDown: (event) {
- machineLearningController.onUserInteraction();
+ computeController.onUserInteraction();
},
child: AdaptiveTheme(
light: lightThemeData,
@@ -133,8 +147,10 @@ class _EnteAppState extends State with WidgetsBindingObserver {
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [
- ...AppLocalizations.localizationsDelegates,
S.delegate,
+ GlobalMaterialLocalizations.delegate,
+ GlobalCupertinoLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
],
),
),
@@ -142,7 +158,7 @@ class _EnteAppState extends State with WidgetsBindingObserver {
} else {
return Listener(
onPointerDown: (event) {
- machineLearningController.onUserInteraction();
+ computeController.onUserInteraction();
},
child: MaterialApp(
title: "ente",
@@ -156,8 +172,10 @@ class _EnteAppState extends State with WidgetsBindingObserver {
supportedLocales: appSupportedLocales,
localeListResolutionCallback: localResolutionCallBack,
localizationsDelegates: const [
- ...AppLocalizations.localizationsDelegates,
S.delegate,
+ GlobalMaterialLocalizations.delegate,
+ GlobalCupertinoLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
],
),
);
@@ -168,6 +186,7 @@ class _EnteAppState extends State with WidgetsBindingObserver {
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_memoriesChangedSubscription.cancel();
+ _peopleChangedSubscription.cancel();
super.dispose();
}
diff --git a/mobile/lib/core/constants.dart b/mobile/lib/core/constants.dart
index 78f3db6bad..6215ebc7d7 100644
--- a/mobile/lib/core/constants.dart
+++ b/mobile/lib/core/constants.dart
@@ -71,7 +71,7 @@ const kSearchSectionLimit = 9;
const maxPickAssetLimit = 50;
-const iOSGroupID = "group.io.ente.frame.EnteMemoryWidget";
+const iOSGroupIDMemory = "group.io.ente.frame.EnteMemoryWidget";
const blackThumbnailBase64 = '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB'
'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQ'
@@ -101,12 +101,9 @@ const blackThumbnailBase64 = '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEB'
'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAo'
'AKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgD/9k=';
-const localFileServer =
- String.fromEnvironment("localFileServer", defaultValue: "");
-
const uploadTempFilePrefix = "upload_file_";
final tempDirCleanUpInterval = kDebugMode
- ? const Duration(seconds: 30).inMicroseconds
+ ? const Duration(hours: 1).inMicroseconds
: const Duration(hours: 6).inMicroseconds;
const kFilterChipHeight = 32.0;
diff --git a/mobile/lib/core/error-reporting/super_logging.dart b/mobile/lib/core/error-reporting/super_logging.dart
index 31cd3d9137..50950d342f 100644
--- a/mobile/lib/core/error-reporting/super_logging.dart
+++ b/mobile/lib/core/error-reporting/super_logging.dart
@@ -1,5 +1,3 @@
-library super_logging;
-
import 'dart:async';
import 'dart:collection';
import 'dart:core';
diff --git a/mobile/lib/core/network/network.dart b/mobile/lib/core/network/network.dart
index ba2540b401..2179dc7850 100644
--- a/mobile/lib/core/network/network.dart
+++ b/mobile/lib/core/network/network.dart
@@ -39,7 +39,6 @@ class NetworkClient {
),
);
- _dio.httpClientAdapter = NativeAdapter();
_enteDio.httpClientAdapter = NativeAdapter();
_setupInterceptors(endpoint);
diff --git a/mobile/lib/db/files_db.dart b/mobile/lib/db/files_db.dart
index ae702d92b4..1d46bff519 100644
--- a/mobile/lib/db/files_db.dart
+++ b/mobile/lib/db/files_db.dart
@@ -640,7 +640,6 @@ class FilesDB with SqlDbBase {
int visibility = visibleVisibility,
DBFilterOptions? filterOptions,
bool applyOwnerCheck = false,
- bool ignoreSharedFiles = false,
}) async {
final stopWatch = EnteWatch('getAllPendingOrUploadedFiles')..start();
final order = (asc ?? false ? 'ASC' : 'DESC');
@@ -663,7 +662,7 @@ class FilesDB with SqlDbBase {
subQueries.add(' AND $columnMMdVisibility = ?');
args.add(visibility);
- if (ignoreSharedFiles == true) {
+ if (filterOptions?.ignoreSharedItems ?? false) {
subQueries.add(' AND $columnOwnerID = ?');
args.add(ownerID);
}
@@ -696,7 +695,6 @@ class FilesDB with SqlDbBase {
int ownerID, {
int? limit,
bool? asc,
- bool ignoreSharedFiles = false,
required DBFilterOptions filterOptions,
}) async {
final db = await instance.sqliteAsyncDB;
@@ -708,7 +706,7 @@ class FilesDB with SqlDbBase {
'SELECT * FROM $filesTable WHERE $columnCreationTime >= ? AND $columnCreationTime <= ? AND ($columnMMdVisibility IS NULL OR $columnMMdVisibility = ?)'
' AND ($columnLocalID IS NOT NULL OR ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1))');
- if (ignoreSharedFiles == true) {
+ if (filterOptions.ignoreSharedItems) {
subQueries.add(' AND $columnOwnerID = ?');
args.add(ownerID);
}
@@ -1685,8 +1683,8 @@ class FilesDB with SqlDbBase {
AND $columnUploadedFileID != -1
AND $columnOwnerID = $userID
AND $columnLocalID IS NOT NULL
- AND ($columnFileSize IS NULL OR $columnFileSize <= 524288000)
- AND ($columnDuration IS NULL OR $columnDuration <= 60)
+ AND ($columnFileSize IS NOT NULL AND $columnFileSize <= 524288000)
+ AND ($columnDuration IS NOT NULL AND ($columnDuration <= 60 AND $columnDuration > 0))
ORDER BY $columnCreationTime DESC
''',
[getInt(fileType), beginDate.microsecondsSinceEpoch],
diff --git a/mobile/lib/db/ml/db.dart b/mobile/lib/db/ml/db.dart
index 0186ead274..a1d2a6ccf1 100644
--- a/mobile/lib/db/ml/db.dart
+++ b/mobile/lib/db/ml/db.dart
@@ -35,6 +35,8 @@ import 'package:sqlite_async/sqlite_async.dart';
///
/// [clipTable] - Stores the embeddings of the CLIP model
/// [fileDataTable] - Stores data about the files that are already processed by the ML models
+///
+/// [faceCacheTable] - Stores a all the mappings from personID or clusterID to the faceID that has been used as cover face.
class MLDataDB with SqlDbBase implements IMLDataDB {
static final Logger _logger = Logger("MLDataDB");
@@ -57,6 +59,7 @@ class MLDataDB with SqlDbBase implements IMLDataDB {
fcClusterIDIndex,
createClipEmbeddingsTable,
createFileDataTable,
+ createFaceCacheTable,
];
// only have a single app-wide reference to the database
@@ -471,6 +474,22 @@ class MLDataDB with SqlDbBase implements IMLDataDB {
return maps.map((e) => e[faceIDColumn] as String).toSet();
}
+ Future> getFaceIDsForClusterOrderedByScore(
+ String clusterID, {
+ int limit = 10,
+ }) async {
+ final db = await instance.asyncDB;
+ final faceIdsResult = await db.getAll(
+ 'SELECT $facesTable.$faceIDColumn FROM $facesTable '
+ 'JOIN $faceClustersTable ON $facesTable.$faceIDColumn = $faceClustersTable.$faceIDColumn '
+ 'WHERE $faceClustersTable.$clusterIDColumn = ? '
+ 'ORDER BY $facesTable.$faceScore DESC '
+ 'LIMIT ?',
+ [clusterID, limit],
+ );
+ return faceIdsResult.map((e) => e[faceIDColumn] as String).toList();
+ }
+
// Get Map of personID to Map of clusterID to faceIDs
@override
Future