Compare commits

...

28 Commits

Author SHA1 Message Date
Jason Rasmussen
328ad7d271 feat: shared link login 2026-01-29 11:13:17 -05:00
Jason Rasmussen
25c573bc7a chore: remove random code snippet (#25677) 2026-01-29 16:11:25 +00:00
renovate[bot]
10bb83cf75 chore(deps): update dependency terragrunt to v0.98.0 (#24328)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-29 08:55:42 -05:00
Jason Rasmussen
10b53b525d refactor: event manager (#25565) 2026-01-29 08:52:18 -05:00
Timon
8db61d341f docs(openapi): add descriptions to OpenAPI specification (#25185)
* faces

* add openapi descriptions

* remove dto descriptions

* gen openapi

* dtos

* fix dtos

* fix more

* fix build

* more

* complete dtos

* descriptions on rebase

* gen rebase

* revert correct integer type conversion

* gen after revert

* revert correct nullables

* regen after revert

* actually incorrect adding default here

* revert correct number type conversion

* regen after revert

* revert nullable usage

* regen fully

* readd some comments

* one more

* one more

* use enum

* add missing

* add missing controllers

* add missing dtos

* complete it

* more

* describe global key and slug

* add remaining body and param descriptions

* lint and format

* cleanup

* response and schema descriptions

* test patch according to suggestion

* revert added api response objects

* revert added api body objects

* revert added api param object

* revert added api query objects

* revert reorganized http code objects

* revert reorganize ApiOkResponse objects

* revert added api response objects (2)

* revert added api tag object

* revert added api schema objects

* migrate missing asset.dto.ts

* regenerate openapi builds

* delete generated mustache files

* remove descriptions from properties that are schemas

* lint

* revert nullable type changes

* revert int/num type changes

* remove explicit default

* readd comment

* lint

* pr fixes

* last bits and pieces

* lint and format

* chore: remove rejected patches

* fix: deleting asset from asset-viewer on search results (#25596)

* fix: escape handling in search asset viewer (#25621)

* fix: correctly show owner in album options modal (#25618)

* fix: validation issues

* fix: validation issues

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
Co-authored-by: Min Idzelis <min123@gmail.com>
Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
Co-authored-by: Paul Makles <me@insrt.uk>
2026-01-29 08:49:15 -05:00
github-actions
eadb2f89af chore: version v2.5.2 2026-01-28 22:05:10 +00:00
Marius
f2f11b1924 fix(mobile): tall image scrolling (#25649)
Add cross-axis gesture detection in PhotoView so vertical scrolling works on tall images that don't fill the screen width (have black bars)
2026-01-28 17:03:11 -05:00
Jason Rasmussen
141be5cbc9 fix: memory generation (#25650) 2026-01-28 15:51:24 -06:00
Jason Rasmussen
e81faa1dbf fix: memory lane (#25652) 2026-01-28 15:51:13 -06:00
Alex
0beb1f9e7a fix: width and height migration issue (#25643)
* fix: width and height migration issue

* chore: sync stream migration tests

* lint and test

---------

Co-authored-by: bwees <brandonwees@gmail.com>
2026-01-28 15:14:50 -06:00
Mert
e07a91f9c2 fix(mobile): actually load original image (#25646)
fix decoding
2026-01-28 15:14:37 -06:00
Noel S
c6defd453b fix(mobile): set correct system-ui mode on asset viewer init (#25610)
fix: set correct systemui mode on asset viewer init
2026-01-28 15:14:23 -06:00
Daniel Dietzler
4e0e1b2c5c fix: escape handling (#25627) 2026-01-28 15:05:21 -05:00
Noel S
84c3980844 fix(mobile): show controls by default on motion photos (#25638)
fix: show controls by default on motion photos
2026-01-28 13:46:29 -06:00
Daniel Dietzler
e50579eefc fix: album card ranges (#25639) 2026-01-28 14:38:09 -05:00
Timon
0cb153a971 chore: update uv version setting command in release script (#25583) 2026-01-28 13:56:25 +00:00
Alex
12d23e987b chore: post release tasks (#25582) 2026-01-28 08:55:58 -05:00
Timon
9486eed97e chore(mise): use explicit monorepo config (#25575)
chore(mise): add monorepo configuration with multiple config roots
2026-01-28 08:55:11 -05:00
Paul Makles
913e939606 fix(server): don't assume maintenance action is set (#25622) 2026-01-28 13:55:18 +01:00
Daniel Dietzler
9be01e79f7 fix: correctly show owner in album options modal (#25618) 2026-01-28 06:24:02 -06:00
Daniel Dietzler
2d09853c3d fix: escape handling in search asset viewer (#25621) 2026-01-28 06:23:15 -06:00
Min Idzelis
91831f68e2 fix: deleting asset from asset-viewer on search results (#25596) 2026-01-28 12:31:23 +01:00
github-actions
41e2ed3754 chore: version v2.5.1 2026-01-27 23:10:13 +00:00
Alex
1319ad373f chore: increase build iOS timeout (#25593) 2026-01-27 23:04:00 +00:00
Alex
97df9fd53f chore: prevent going into sleep mode for large deletion (#25592) 2026-01-27 22:50:28 +00:00
Jason Rasmussen
4707821451 chore: replace patch doc links (#25591)
chore: automatically use the latest patch release
2026-01-27 17:36:38 -05:00
Jason Rasmussen
20c4d375b1 chore: update pump script (#25586) 2026-01-27 17:33:12 -05:00
shenlong
46d2238431 fix: migration on trash source column (#25590)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2026-01-27 16:25:35 -06:00
462 changed files with 6698 additions and 1090 deletions

View File

@@ -269,6 +269,8 @@ jobs:
ENVIRONMENT: ${{ inputs.environment || 'development' }}
BUNDLE_ID_SUFFIX: ${{ inputs.environment == 'production' && '' || 'development' }}
GITHUB_REF: ${{ github.ref }}
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
FASTLANE_XCODEBUILD_SETTINGS_RETRIES: 6
working-directory: ./mobile/ios
run: |
# Only upload to TestFlight on main branch

View File

@@ -36,7 +36,7 @@ jobs:
github-token: ${{ steps.token.outputs.token }}
filters: |
i18n:
- modified: 'i18n/!(en)**\.json'
- modified: 'i18n/!(en|package)**\.json'
skip-force-logic: 'true'
enforce-lock:

View File

@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "2.2.106",
"version": "2.5.2",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",

View File

@@ -1,5 +1,5 @@
[tools]
terragrunt = "0.93.10"
terragrunt = "0.98.0"
opentofu = "1.10.7"
[tasks."tg:fmt"]

View File

@@ -1,40 +1,20 @@
[
{
"label": "v2.5.0",
"url": "https://docs.v2.5.0.archive.immich.app"
"label": "v2.5.2",
"url": "https://docs.v2.5.2.archive.immich.app"
},
{
"label": "v2.4.1",
"url": "https://docs.v2.4.1.archive.immich.app"
},
{
"label": "v2.4.0",
"url": "https://docs.v2.4.0.archive.immich.app"
},
{
"label": "v2.3.1",
"url": "https://docs.v2.3.1.archive.immich.app"
},
{
"label": "v2.3.0",
"url": "https://docs.v2.3.0.archive.immich.app"
},
{
"label": "v2.2.3",
"url": "https://docs.v2.2.3.archive.immich.app"
},
{
"label": "v2.2.2",
"url": "https://docs.v2.2.2.archive.immich.app"
},
{
"label": "v2.2.1",
"url": "https://docs.v2.2.1.archive.immich.app"
},
{
"label": "v2.2.0",
"url": "https://docs.v2.2.0.archive.immich.app"
},
{
"label": "v2.1.0",
"url": "https://docs.v2.1.0.archive.immich.app"
@@ -43,18 +23,10 @@
"label": "v2.0.1",
"url": "https://docs.v2.0.1.archive.immich.app"
},
{
"label": "v2.0.0",
"url": "https://docs.v2.0.0.archive.immich.app"
},
{
"label": "v1.144.1",
"url": "https://docs.v1.144.1.archive.immich.app"
},
{
"label": "v1.144.0",
"url": "https://docs.v1.144.0.archive.immich.app"
},
{
"label": "v1.143.1",
"url": "https://docs.v1.143.1.archive.immich.app"

View File

@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "2.5.0",
"version": "2.5.2",
"description": "",
"main": "index.js",
"type": "module",

View File

@@ -0,0 +1,116 @@
import { faker } from '@faker-js/faker';
import { expect, test } from '@playwright/test';
import {
Changes,
createDefaultTimelineConfig,
generateTimelineData,
TimelineAssetConfig,
TimelineData,
} from 'src/generators/timeline';
import { setupBaseMockApiRoutes } from 'src/mock-network/base-network';
import { setupTimelineMockApiRoutes, TimelineTestContext } from 'src/mock-network/timeline-network';
import { assetViewerUtils } from 'src/web/specs/timeline/utils';
const buildSearchUrl = (assetId: string) => {
const searchQuery = encodeURIComponent(JSON.stringify({ originalFileName: 'test' }));
return `/search/photos/${assetId}?query=${searchQuery}`;
};
test.describe.configure({ mode: 'parallel' });
test.describe('search gallery-viewer', () => {
let adminUserId: string;
let timelineRestData: TimelineData;
const assets: TimelineAssetConfig[] = [];
const testContext = new TimelineTestContext();
const changes: Changes = {
albumAdditions: [],
assetDeletions: [],
assetArchivals: [],
assetFavorites: [],
};
test.beforeAll(async () => {
adminUserId = faker.string.uuid();
testContext.adminId = adminUserId;
timelineRestData = generateTimelineData({ ...createDefaultTimelineConfig(), ownerId: adminUserId });
for (const timeBucket of timelineRestData.buckets.values()) {
assets.push(...timeBucket);
}
});
test.beforeEach(async ({ context }) => {
await setupBaseMockApiRoutes(context, adminUserId);
await setupTimelineMockApiRoutes(context, timelineRestData, changes, testContext);
await context.route('**/api/search/metadata', async (route, request) => {
if (request.method() === 'POST') {
const searchAssets = assets.slice(0, 5).filter((asset) => !changes.assetDeletions.includes(asset.id));
return route.fulfill({
status: 200,
contentType: 'application/json',
json: {
albums: { total: 0, count: 0, items: [], facets: [] },
assets: {
total: searchAssets.length,
count: searchAssets.length,
items: searchAssets,
facets: [],
nextPage: null,
},
},
});
}
await route.fallback();
});
});
test.afterEach(() => {
testContext.slowBucket = false;
changes.albumAdditions = [];
changes.assetDeletions = [];
changes.assetArchivals = [];
changes.assetFavorites = [];
});
test.describe('/search/photos/:id', () => {
test('Deleting a photo advances to the next photo', async ({ page }) => {
const asset = assets[0];
await page.goto(buildSearchUrl(asset.id));
await assetViewerUtils.waitForViewerLoad(page, asset);
await page.getByLabel('Delete').click();
await assetViewerUtils.waitForViewerLoad(page, assets[1]);
});
test('Deleting two photos in a row advances to the next photo each time', async ({ page }) => {
const asset = assets[0];
await page.goto(buildSearchUrl(asset.id));
await assetViewerUtils.waitForViewerLoad(page, asset);
await page.getByLabel('Delete').click();
await assetViewerUtils.waitForViewerLoad(page, assets[1]);
await page.getByLabel('Delete').click();
await assetViewerUtils.waitForViewerLoad(page, assets[2]);
});
test('Navigating backward then deleting advances to the next photo', async ({ page }) => {
const asset = assets[1];
await page.goto(buildSearchUrl(asset.id));
await assetViewerUtils.waitForViewerLoad(page, asset);
await page.getByLabel('View previous asset').click();
await assetViewerUtils.waitForViewerLoad(page, assets[0]);
await page.getByLabel('View next asset').click();
await assetViewerUtils.waitForViewerLoad(page, asset);
await page.getByLabel('Delete').click();
await assetViewerUtils.waitForViewerLoad(page, assets[2]);
});
test('Deleting the last photo advances to the previous photo', async ({ page }) => {
const lastAsset = assets[4];
await page.goto(buildSearchUrl(lastAsset.id));
await assetViewerUtils.waitForViewerLoad(page, lastAsset);
await expect(page.getByLabel('View next asset')).toHaveCount(0);
await page.getByLabel('Delete').click();
await assetViewerUtils.waitForViewerLoad(page, assets[3]);
await expect(page.getByLabel('View previous asset')).toBeVisible();
});
});
});

View File

@@ -1,6 +1,6 @@
{
"name": "immich-i18n",
"version": "1.0.0",
"version": "2.5.2",
"private": true,
"scripts": {
"format": "prettier --check .",

View File

@@ -1,6 +1,6 @@
[project]
name = "immich-ml"
version = "2.5.0"
version = "2.5.2"
description = ""
authors = [{ name = "Hau Tran", email = "alex.tran1502@gmail.com" }]
requires-python = ">=3.11,<4.0"

View File

@@ -919,7 +919,7 @@ wheels = [
[[package]]
name = "immich-ml"
version = "2.4.1"
version = "2.5.2"
source = { editable = "." }
dependencies = [
{ name = "aiocache" },

View File

@@ -1,6 +1,12 @@
#! /usr/bin/env node
const { readFileSync, writeFileSync } = require('node:fs');
const asVersion = (item) => {
const { label, url } = item;
const [major, minor, patch] = label.substring(1).split('.').map(Number);
return { major, minor, patch, label, url };
};
const nextVersion = process.argv[2];
if (!nextVersion) {
console.log('Usage: archive-version.js <version>');
@@ -8,10 +14,32 @@ if (!nextVersion) {
}
const filename = './docs/static/archived-versions.json';
const oldVersions = JSON.parse(readFileSync(filename));
const newVersions = [
{ label: `v${nextVersion}`, url: `https://docs.v${nextVersion}.archive.immich.app` },
...oldVersions,
];
let versions = JSON.parse(readFileSync(filename));
const newVersion = {
label: `v${nextVersion}`,
url: `https://docs.v${nextVersion}.archive.immich.app`,
};
writeFileSync(filename, JSON.stringify(newVersions, null, 2) + '\n');
let lastVersion = asVersion(newVersion);
for (const item of versions) {
const version = asVersion(item);
// only keep the latest patch version for each minor release
if (
lastVersion.major === version.major &&
lastVersion.minor === version.minor &&
lastVersion.patch >= version.patch
) {
versions = versions.filter((item) => item.label !== version.label);
console.log(
`Removed ${version.label} (replaced with ${lastVersion.label})`
);
continue;
}
lastVersion = version;
}
writeFileSync(
filename,
JSON.stringify([newVersion, ...versions], null, 2) + '\n'
);

View File

@@ -61,26 +61,23 @@ fi
if [ "$CURRENT_SERVER" != "$NEXT_SERVER" ]; then
echo "Pumping Server: $CURRENT_SERVER => $NEXT_SERVER"
jq --arg version "$NEXT_SERVER" '.version = $version' server/package.json > server/package.json.tmp && mv server/package.json.tmp server/package.json
pnpm version "$NEXT_SERVER" --no-git-tag-version
pnpm version "$NEXT_SERVER" --no-git-tag-version --prefix server
pnpm version "$NEXT_SERVER" --no-git-tag-version --prefix i18n
pnpm version "$NEXT_SERVER" --no-git-tag-version --prefix cli
pnpm version "$NEXT_SERVER" --no-git-tag-version --prefix web
pnpm version "$NEXT_SERVER" --no-git-tag-version --prefix e2e
pnpm version "$NEXT_SERVER" --no-git-tag-version --prefix open-api/typescript-sdk
# copy version to open-api spec
pnpm install --frozen-lockfile --prefix server
pnpm --prefix server run build
( cd ./open-api && bash ./bin/generate-open-api.sh )
jq --arg version "$NEXT_SERVER" '.version = $version' open-api/typescript-sdk/package.json > open-api/typescript-sdk/package.json.tmp && mv open-api/typescript-sdk/package.json.tmp open-api/typescript-sdk/package.json
uv version --directory machine-learning "$NEXT_SERVER"
# TODO use $SERVER_PUMP once we pass 2.2.x
CURRENT_CLI_VERSION=$(jq -r '.version' cli/package.json)
CLI_PATCH_VERSION=$(echo "$CURRENT_CLI_VERSION" | awk -F. '{print $1"."$2"."($3+1)}')
jq --arg version "$CLI_PATCH_VERSION" '.version = $version' cli/package.json > cli/package.json.tmp && mv cli/package.json.tmp cli/package.json
pnpm install --frozen-lockfile --prefix cli
jq --arg version "$NEXT_SERVER" '.version = $version' web/package.json > web/package.json.tmp && mv web/package.json.tmp web/package.json
pnpm install --frozen-lockfile --prefix web
jq --arg version "$NEXT_SERVER" '.version = $version' e2e/package.json > e2e/package.json.tmp && mv e2e/package.json.tmp e2e/package.json
pnpm install --frozen-lockfile --prefix e2e
uvx --from=toml-cli toml set --toml-path=machine-learning/pyproject.toml project.version "$NEXT_SERVER"
./misc/release/archive-version.js "$NEXT_SERVER"
fi
if [ "$CURRENT_MOBILE" != "$NEXT_MOBILE" ]; then
@@ -92,6 +89,5 @@ sed -i "s/\"android\.injected\.version\.code\" => $CURRENT_MOBILE,/\"android\.in
sed -i "s/^version: $CURRENT_SERVER+$CURRENT_MOBILE$/version: $NEXT_SERVER+$NEXT_MOBILE/" mobile/pubspec.yaml
perl -i -p0e "s/(<key>CFBundleShortVersionString<\/key>\s*<string>)$CURRENT_SERVER(<\/string>)/\${1}$NEXT_SERVER\${2}/s" mobile/ios/Runner/Info.plist
./misc/release/archive-version.js "$NEXT_SERVER"
echo "IMMICH_VERSION=v$NEXT_SERVER" >>"$GITHUB_ENV"

View File

@@ -1,10 +1,23 @@
experimental_monorepo_root = true
[monorepo]
config_roots = [
"plugins",
"server",
"cli",
"deployment",
"mobile",
"e2e",
"web",
"docs",
".github",
]
[tools]
node = "24.13.0"
flutter = "3.35.7"
pnpm = "10.28.0"
terragrunt = "0.93.10"
terragrunt = "0.98.0"
opentofu = "1.10.7"
java = "25.0.1"

View File

@@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 3031,
"android.injected.version.name" => "2.5.0",
"android.injected.version.code" => 3033,
"android.injected.version.name" => "2.5.2",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')

View File

@@ -741,7 +741,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
@@ -885,7 +885,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
@@ -915,7 +915,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
@@ -949,7 +949,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -992,7 +992,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -1032,7 +1032,7 @@
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -1071,7 +1071,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1115,7 +1115,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1156,7 +1156,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 233;
CURRENT_PROJECT_VERSION = 240;
CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES;

View File

@@ -79,6 +79,7 @@ class RemoteImageApiDelegate: NSObject, URLSessionDataDelegate {
kCGImageSourceShouldCache: false,
kCGImageSourceShouldCacheImmediately: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceCreateThumbnailFromImageAlways: true
] as CFDictionary
func urlSession(

View File

@@ -80,7 +80,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.5.0</string>
<string>2.5.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
@@ -107,7 +107,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>233</string>
<string>240</string>
<key>FLTEnableImpeller</key>
<true/>
<key>ITSAppUsesNonExemptEncryption</key>

View File

@@ -39,6 +39,14 @@ iOS Release to TestFlight
iOS Manual Release
### ios gha_build_only
```sh
[bundle exec] fastlane ios gha_build_only
```
iOS Build Only (no TestFlight upload)
----
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.

View File

@@ -89,7 +89,9 @@ enum StoreKey<T> {
cleanupKeepMediaType<int>._(1009),
cleanupKeepAlbumIds<String>._(1010),
cleanupCutoffDaysAgo<int>._(1011),
cleanupDefaultsInitialized<bool>._(1012);
cleanupDefaultsInitialized<bool>._(1012),
syncMigrationStatus<String>._(1013);
const StoreKey._(this.id);
final int id;

View File

@@ -1,4 +1,7 @@
// ignore_for_file: constant_identifier_names
import 'dart:async';
import 'dart:convert';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/sync_event.model.dart';
@@ -7,12 +10,21 @@ import 'package:immich_mobile/extensions/platform_extensions.dart';
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_api.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_migration.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/trashed_local_asset.repository.dart';
import 'package:immich_mobile/repositories/local_files_manager.repository.dart';
import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/utils/semver.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
enum SyncMigrationTask {
v20260128_ResetExifV1, // EXIF table has incorrect width and height information.
v20260128_CopyExifWidthHeightToAsset, // Asset table has incorrect width and height for video ratio calculations.
v20260128_ResetAssetV1, // Asset v2.5.0 has width and height information that were edited assets.
}
class SyncStreamService {
final Logger _logger = Logger('SyncStreamService');
@@ -22,6 +34,8 @@ class SyncStreamService {
final DriftTrashedLocalAssetRepository _trashedLocalAssetRepository;
final LocalFilesManagerRepository _localFilesManager;
final StorageRepository _storageRepository;
final SyncMigrationRepository _syncMigrationRepository;
final ApiService _api;
final bool Function()? _cancelChecker;
SyncStreamService({
@@ -31,6 +45,8 @@ class SyncStreamService {
required DriftTrashedLocalAssetRepository trashedLocalAssetRepository,
required LocalFilesManagerRepository localFilesManager,
required StorageRepository storageRepository,
required SyncMigrationRepository syncMigrationRepository,
required ApiService api,
bool Function()? cancelChecker,
}) : _syncApiRepository = syncApiRepository,
_syncStreamRepository = syncStreamRepository,
@@ -38,12 +54,32 @@ class SyncStreamService {
_trashedLocalAssetRepository = trashedLocalAssetRepository,
_localFilesManager = localFilesManager,
_storageRepository = storageRepository,
_syncMigrationRepository = syncMigrationRepository,
_api = api,
_cancelChecker = cancelChecker;
bool get isCancelled => _cancelChecker?.call() ?? false;
Future<bool> sync() async {
_logger.info("Remote sync request for user");
final serverVersion = await _api.serverInfoApi.getServerVersion();
if (serverVersion == null) {
_logger.severe("Cannot perform sync: unable to determine server version");
return false;
}
final semVer = SemVer(major: serverVersion.major, minor: serverVersion.minor, patch: serverVersion.patch_);
final value = Store.get(StoreKey.syncMigrationStatus, "[]");
final migrations = (jsonDecode(value) as List).cast<String>();
int previousLength = migrations.length;
await _runPreSyncTasks(migrations, semVer);
if (migrations.length != previousLength) {
_logger.info("Updated pre-sync migration status: $migrations");
await Store.put(StoreKey.syncMigrationStatus, jsonEncode(migrations));
}
// Start the sync stream and handle events
bool shouldReset = false;
await _syncApiRepository.streamChanges(_handleEvents, onReset: () => shouldReset = true);
@@ -51,9 +87,56 @@ class SyncStreamService {
_logger.info("Resetting sync state as requested by server");
await _syncApiRepository.streamChanges(_handleEvents);
}
previousLength = migrations.length;
await _runPostSyncTasks(migrations);
if (migrations.length != previousLength) {
_logger.info("Updated pre-sync migration status: $migrations");
await Store.put(StoreKey.syncMigrationStatus, jsonEncode(migrations));
}
return true;
}
Future<void> _runPreSyncTasks(List<String> migrations, SemVer semVer) async {
if (!migrations.contains(SyncMigrationTask.v20260128_ResetExifV1.name)) {
_logger.info("Running pre-sync task: v20260128_ResetExifV1");
await _syncApiRepository.deleteSyncAck([
SyncEntityType.assetExifV1,
SyncEntityType.partnerAssetExifV1,
SyncEntityType.albumAssetExifCreateV1,
SyncEntityType.albumAssetExifUpdateV1,
]);
migrations.add(SyncMigrationTask.v20260128_ResetExifV1.name);
}
if (!migrations.contains(SyncMigrationTask.v20260128_ResetAssetV1.name) &&
semVer >= const SemVer(major: 2, minor: 5, patch: 0)) {
_logger.info("Running pre-sync task: v20260128_ResetAssetV1");
await _syncApiRepository.deleteSyncAck([
SyncEntityType.assetV1,
SyncEntityType.partnerAssetV1,
SyncEntityType.albumAssetCreateV1,
SyncEntityType.albumAssetUpdateV1,
]);
migrations.add(SyncMigrationTask.v20260128_ResetAssetV1.name);
if (!migrations.contains(SyncMigrationTask.v20260128_CopyExifWidthHeightToAsset.name)) {
migrations.add(SyncMigrationTask.v20260128_CopyExifWidthHeightToAsset.name);
}
}
}
Future<void> _runPostSyncTasks(List<String> migrations) async {
if (!migrations.contains(SyncMigrationTask.v20260128_CopyExifWidthHeightToAsset.name)) {
_logger.info("Running post-sync task: v20260128_CopyExifWidthHeightToAsset");
await _syncMigrationRepository.v20260128CopyExifWidthHeightToAsset();
migrations.add(SyncMigrationTask.v20260128_CopyExifWidthHeightToAsset.name);
}
}
Future<void> _handleEvents(List<SyncEvent> events, Function() abort, Function() reset) async {
List<SyncEvent> items = [];
for (final event in events) {

View File

@@ -193,7 +193,13 @@ class Drift extends $Drift implements IDatabaseRepository {
await m.addColumn(v14.localAssetEntity, v14.localAssetEntity.longitude);
},
from14To15: (m, v15) async {
await m.addColumn(v15.trashedLocalAssetEntity, v15.trashedLocalAssetEntity.source);
await m.alterTable(
TableMigration(
v15.trashedLocalAssetEntity,
columnTransformer: {v15.trashedLocalAssetEntity.source: Constant(TrashOrigin.localSync.index)},
newColumns: [v15.trashedLocalAssetEntity.source],
),
);
},
from15To16: (m, v16) async {
// Add i_cloud_id to local and remote asset tables

View File

@@ -19,6 +19,10 @@ class SyncApiRepository {
return _api.syncApi.sendSyncAck(SyncAckSetDto(acks: data));
}
Future<void> deleteSyncAck(List<SyncEntityType> types) {
return _api.syncApi.deleteSyncAck(SyncAckDeleteDto(types: types));
}
Future<void> streamChanges(
Future<void> Function(List<SyncEvent>, Function() abort, Function() reset) onData, {
Function()? onReset,

View File

@@ -0,0 +1,24 @@
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
class SyncMigrationRepository extends DriftDatabaseRepository {
final Drift _db;
const SyncMigrationRepository(super.db) : _db = db;
Future<void> v20260128CopyExifWidthHeightToAsset() async {
await _db.customStatement('''
UPDATE remote_asset_entity
SET width = CASE
WHEN exif.orientation IN ('5', '6', '7', '8', '-90', '90') THEN exif.height
ELSE exif.width
END,
height = CASE
WHEN exif.orientation IN ('5', '6', '7', '8', '-90', '90') THEN exif.width
ELSE exif.height
END
FROM remote_exif_entity exif
WHERE exif.asset_id = remote_asset_entity.id
AND (exif.width IS NOT NULL OR exif.height IS NOT NULL);
''');
}
}

View File

@@ -92,7 +92,9 @@ class AssetViewer extends ConsumerStatefulWidget {
if (asset.isVideo || asset.isMotionPhoto) {
ref.read(videoPlaybackValueProvider.notifier).reset();
ref.read(videoPlayerControlsProvider.notifier).pause();
// Hide controls by default for videos and motion photos
}
// Hide controls by default for videos
if (asset.isVideo) {
ref.read(assetViewerProvider.notifier).setControls(false);
}
}
@@ -147,6 +149,11 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
if (asset != null) {
_stackChildrenKeepAlive = ref.read(stackChildrenNotifier(asset).notifier).ref.keepAlive();
}
if (ref.read(assetViewerProvider).showingControls) {
unawaited(SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge));
} else {
unawaited(SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky));
}
}
@override

View File

@@ -3,6 +3,7 @@ import 'package:immich_mobile/domain/services/hash.service.dart';
import 'package:immich_mobile/domain/services/local_sync.service.dart';
import 'package:immich_mobile/domain/services/sync_stream.service.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_api.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_migration.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
@@ -13,6 +14,8 @@ import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
import 'package:immich_mobile/providers/infrastructure/storage.provider.dart';
import 'package:immich_mobile/repositories/local_files_manager.repository.dart';
final syncMigrationRepositoryProvider = Provider((ref) => SyncMigrationRepository(ref.watch(driftProvider)));
final syncStreamServiceProvider = Provider(
(ref) => SyncStreamService(
syncApiRepository: ref.watch(syncApiRepositoryProvider),
@@ -21,6 +24,8 @@ final syncStreamServiceProvider = Provider(
trashedLocalAssetRepository: ref.watch(trashedLocalAssetRepository),
localFilesManager: ref.watch(localFilesManagerRepositoryProvider),
storageRepository: ref.watch(storageRepositoryProvider),
syncMigrationRepository: ref.watch(syncMigrationRepositoryProvider),
api: ref.watch(apiServiceProvider),
cancelChecker: ref.watch(cancellationProvider),
),
);

View File

@@ -28,6 +28,7 @@ import 'package:immich_mobile/utils/datetime_helpers.dart';
import 'package:immich_mobile/utils/debug_print.dart';
import 'package:immich_mobile/utils/diff.dart';
import 'package:isar/isar.dart';
// ignore: import_rule_photo_manager
import 'package:photo_manager/photo_manager.dart';
@@ -88,7 +89,6 @@ Future<void> migrateDatabaseIfNeeded(Isar db, Drift drift) async {
if (version < 20 && Store.isBetaTimelineEnabled) {
await _syncLocalAlbumIsIosSharedAlbum(drift);
await _backfillAssetExifWidthHeight(drift);
}
if (targetVersion >= 12) {
@@ -282,22 +282,6 @@ Future<void> _syncLocalAlbumIsIosSharedAlbum(Drift db) async {
}
}
Future<void> _backfillAssetExifWidthHeight(Drift db) async {
try {
await db.customStatement('''
UPDATE remote_exif_entity AS remote_exif
SET width = asset.width,
height = asset.height
FROM remote_asset_entity AS asset
WHERE remote_exif.asset_id = asset.id;
''');
dPrint(() => "[MIGRATION] Successfully backfilled asset exif width and height");
} catch (error) {
dPrint(() => "[MIGRATION] Error while backfilling asset exif width and height: $error");
}
}
Future<void> migrateDeviceAssetToSqlite(Isar db, Drift drift) async {
try {
final isarDeviceAssets = await db.deviceAssetEntitys.where().findAll();

View File

@@ -203,9 +203,13 @@ class PhotoViewGestureRecognizer extends ScaleGestureRecognizer {
void _decideIfWeAcceptEvent(PointerEvent event) {
final move = _initialFocalPoint! - _currentFocalPoint!;
final bool shouldMove = validateAxis == Axis.vertical
? hitDetector!.shouldMove(move, Axis.vertical)
: hitDetector!.shouldMove(move, Axis.horizontal);
// Accept gesture if movement is possible in the direction the user is swiping
final bool isHorizontalGesture = move.dx.abs() > move.dy.abs();
final bool shouldMove = isHorizontalGesture
? hitDetector!.shouldMove(move, Axis.horizontal)
: hitDetector!.shouldMove(move, Axis.vertical);
if (shouldMove || _pointerLocations.keys.length > 1) {
final double spanDelta = (_currentSpan! - _initialSpan!).abs();
final double focalPointDelta = (_currentFocalPoint! - _initialFocalPoint!).distance;

View File

@@ -13,6 +13,7 @@ import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/utils/bytes_units.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
class FreeUpSpaceSettings extends ConsumerStatefulWidget {
const FreeUpSpaceSettings({super.key});
@@ -29,6 +30,7 @@ class _FreeUpSpaceSettingsState extends ConsumerState<FreeUpSpaceSettings> {
@override
void initState() {
super.initState();
WakelockPlus.enable();
WidgetsBinding.instance.addPostFrameCallback((_) {
_initializeAlbumDefaults();
});
@@ -168,6 +170,12 @@ class _FreeUpSpaceSettingsState extends ConsumerState<FreeUpSpaceSettings> {
context.pushRoute(CleanupPreviewRoute(assets: assets));
}
@override
dispose() {
super.dispose();
WakelockPlus.disable();
}
@override
Widget build(BuildContext context) {
final state = ref.watch(cleanupProvider);

View File

@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 2.5.0
- API version: 2.5.2
- Generator version: 7.8.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
@@ -256,6 +256,7 @@ Class | Method | HTTP request | Description
*SharedLinksApi* | [**getSharedLinkById**](doc//SharedLinksApi.md#getsharedlinkbyid) | **GET** /shared-links/{id} | Retrieve a shared link
*SharedLinksApi* | [**removeSharedLink**](doc//SharedLinksApi.md#removesharedlink) | **DELETE** /shared-links/{id} | Delete a shared link
*SharedLinksApi* | [**removeSharedLinkAssets**](doc//SharedLinksApi.md#removesharedlinkassets) | **DELETE** /shared-links/{id}/assets | Remove assets from a shared link
*SharedLinksApi* | [**sharedLinkLogin**](doc//SharedLinksApi.md#sharedlinklogin) | **POST** /shared-links/login | Shared link login
*SharedLinksApi* | [**updateSharedLink**](doc//SharedLinksApi.md#updatesharedlink) | **PATCH** /shared-links/{id} | Update a shared link
*StacksApi* | [**createStack**](doc//StacksApi.md#createstack) | **POST** /stacks | Create a stack
*StacksApi* | [**deleteStack**](doc//StacksApi.md#deletestack) | **DELETE** /stacks/{id} | Delete a stack
@@ -552,6 +553,7 @@ Class | Method | HTTP request | Description
- [SetMaintenanceModeDto](doc//SetMaintenanceModeDto.md)
- [SharedLinkCreateDto](doc//SharedLinkCreateDto.md)
- [SharedLinkEditDto](doc//SharedLinkEditDto.md)
- [SharedLinkLoginDto](doc//SharedLinkLoginDto.md)
- [SharedLinkResponseDto](doc//SharedLinkResponseDto.md)
- [SharedLinkType](doc//SharedLinkType.md)
- [SharedLinksResponse](doc//SharedLinksResponse.md)

View File

@@ -292,6 +292,7 @@ part 'model/session_update_dto.dart';
part 'model/set_maintenance_mode_dto.dart';
part 'model/shared_link_create_dto.dart';
part 'model/shared_link_edit_dto.dart';
part 'model/shared_link_login_dto.dart';
part 'model/shared_link_response_dto.dart';
part 'model/shared_link_type.dart';
part 'model/shared_links_response.dart';

View File

@@ -130,14 +130,19 @@ class ActivitiesApi {
/// Parameters:
///
/// * [String] albumId (required):
/// Album ID
///
/// * [String] assetId:
/// Asset ID (if activity is for an asset)
///
/// * [ReactionLevel] level:
/// Filter by activity level
///
/// * [ReactionType] type:
/// Filter by activity type
///
/// * [String] userId:
/// Filter by user ID
Future<Response> getActivitiesWithHttpInfo(String albumId, { String? assetId, ReactionLevel? level, ReactionType? type, String? userId, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/activities';
@@ -184,14 +189,19 @@ class ActivitiesApi {
/// Parameters:
///
/// * [String] albumId (required):
/// Album ID
///
/// * [String] assetId:
/// Asset ID (if activity is for an asset)
///
/// * [ReactionLevel] level:
/// Filter by activity level
///
/// * [ReactionType] type:
/// Filter by activity type
///
/// * [String] userId:
/// Filter by user ID
Future<List<ActivityResponseDto>?> getActivities(String albumId, { String? assetId, ReactionLevel? level, ReactionType? type, String? userId, }) async {
final response = await getActivitiesWithHttpInfo(albumId, assetId: assetId, level: level, type: type, userId: userId, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -219,8 +229,10 @@ class ActivitiesApi {
/// Parameters:
///
/// * [String] albumId (required):
/// Album ID
///
/// * [String] assetId:
/// Asset ID (if activity is for an asset)
Future<Response> getActivityStatisticsWithHttpInfo(String albumId, { String? assetId, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/activities/statistics';
@@ -258,8 +270,10 @@ class ActivitiesApi {
/// Parameters:
///
/// * [String] albumId (required):
/// Album ID
///
/// * [String] assetId:
/// Asset ID (if activity is for an asset)
Future<ActivityStatisticsResponseDto?> getActivityStatistics(String albumId, { String? assetId, }) async {
final response = await getActivityStatisticsWithHttpInfo(albumId, assetId: assetId, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -347,6 +347,7 @@ class AlbumsApi {
/// * [String] slug:
///
/// * [bool] withoutAssets:
/// Exclude assets from response
Future<Response> getAlbumInfoWithHttpInfo(String id, { String? key, String? slug, bool? withoutAssets, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/albums/{id}'
@@ -396,6 +397,7 @@ class AlbumsApi {
/// * [String] slug:
///
/// * [bool] withoutAssets:
/// Exclude assets from response
Future<AlbumResponseDto?> getAlbumInfo(String id, { String? key, String? slug, bool? withoutAssets, }) async {
final response = await getAlbumInfoWithHttpInfo(id, key: key, slug: slug, withoutAssets: withoutAssets, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -468,9 +470,10 @@ class AlbumsApi {
/// Parameters:
///
/// * [String] assetId:
/// Only returns albums that contain the asset Ignores the shared parameter undefined: get all albums
/// Filter albums containing this asset ID (ignores shared parameter)
///
/// * [bool] shared:
/// Filter by shared status: true = only shared, false = only own, undefined = all
Future<Response> getAllAlbumsWithHttpInfo({ String? assetId, bool? shared, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/albums';
@@ -510,9 +513,10 @@ class AlbumsApi {
/// Parameters:
///
/// * [String] assetId:
/// Only returns albums that contain the asset Ignores the shared parameter undefined: get all albums
/// Filter albums containing this asset ID (ignores shared parameter)
///
/// * [bool] shared:
/// Filter by shared status: true = only shared, false = only own, undefined = all
Future<List<AlbumResponseDto>?> getAllAlbums({ String? assetId, bool? shared, }) async {
final response = await getAllAlbumsWithHttpInfo( assetId: assetId, shared: shared, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -185,8 +185,10 @@ class AssetsApi {
/// Parameters:
///
/// * [String] id (required):
/// Asset ID
///
/// * [String] key (required):
/// Metadata key
Future<Response> deleteAssetMetadataWithHttpInfo(String id, String key,) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/{id}/metadata/{key}'
@@ -221,8 +223,10 @@ class AssetsApi {
/// Parameters:
///
/// * [String] id (required):
/// Asset ID
///
/// * [String] key (required):
/// Metadata key
Future<void> deleteAssetMetadata(String id, String key,) async {
final response = await deleteAssetMetadataWithHttpInfo(id, key,);
if (response.statusCode >= HttpStatus.badRequest) {
@@ -337,6 +341,7 @@ class AssetsApi {
/// * [String] id (required):
///
/// * [bool] edited:
/// Return edited asset if available
///
/// * [String] key:
///
@@ -386,6 +391,7 @@ class AssetsApi {
/// * [String] id (required):
///
/// * [bool] edited:
/// Return edited asset if available
///
/// * [String] key:
///
@@ -475,6 +481,7 @@ class AssetsApi {
/// Parameters:
///
/// * [String] deviceId (required):
/// Device ID
Future<Response> getAllUserAssetsByDeviceIdWithHttpInfo(String deviceId,) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/device/{deviceId}'
@@ -508,6 +515,7 @@ class AssetsApi {
/// Parameters:
///
/// * [String] deviceId (required):
/// Device ID
Future<List<String>?> getAllUserAssetsByDeviceId(String deviceId,) async {
final response = await getAllUserAssetsByDeviceIdWithHttpInfo(deviceId,);
if (response.statusCode >= HttpStatus.badRequest) {
@@ -724,8 +732,10 @@ class AssetsApi {
/// Parameters:
///
/// * [String] id (required):
/// Asset ID
///
/// * [String] key (required):
/// Metadata key
Future<Response> getAssetMetadataByKeyWithHttpInfo(String id, String key,) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/{id}/metadata/{key}'
@@ -760,8 +770,10 @@ class AssetsApi {
/// Parameters:
///
/// * [String] id (required):
/// Asset ID
///
/// * [String] key (required):
/// Metadata key
Future<AssetMetadataResponseDto?> getAssetMetadataByKey(String id, String key,) async {
final response = await getAssetMetadataByKeyWithHttpInfo(id, key,);
if (response.statusCode >= HttpStatus.badRequest) {
@@ -846,10 +858,13 @@ class AssetsApi {
/// Parameters:
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] isTrashed:
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<Response> getAssetStatisticsWithHttpInfo({ bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/statistics';
@@ -892,10 +907,13 @@ class AssetsApi {
/// Parameters:
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] isTrashed:
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<AssetStatsResponseDto?> getAssetStatistics({ bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
final response = await getAssetStatisticsWithHttpInfo( isFavorite: isFavorite, isTrashed: isTrashed, visibility: visibility, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -920,6 +938,7 @@ class AssetsApi {
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<Response> getRandomWithHttpInfo({ num? count, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/random';
@@ -956,6 +975,7 @@ class AssetsApi {
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<List<AssetResponseDto>?> getRandom({ num? count, }) async {
final response = await getRandomWithHttpInfo( count: count, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -1106,22 +1126,29 @@ class AssetsApi {
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<Response> replaceAssetWithHttpInfo(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/{id}/original'
@@ -1198,22 +1225,29 @@ class AssetsApi {
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<AssetMediaResponseDto?> replaceAsset(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
final response = await replaceAssetWithHttpInfo(id, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, duration: duration, filename: filename, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -1518,14 +1552,19 @@ class AssetsApi {
/// Parameters:
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
@@ -1535,18 +1574,25 @@ class AssetsApi {
/// sha1 checksum that can be used for duplicate detection before the file is uploaded
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
///
/// * [bool] isFavorite:
/// Mark as favorite
///
/// * [String] livePhotoVideoId:
/// Live photo video ID
///
/// * [List<AssetMetadataUpsertItemDto>] metadata:
/// Asset metadata items
///
/// * [MultipartFile] sidecarData:
/// Sidecar file data
///
/// * [AssetVisibility] visibility:
/// Asset visibility
Future<Response> uploadAssetWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, List<AssetMetadataUpsertItemDto>? metadata, MultipartFile? sidecarData, AssetVisibility? visibility, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets';
@@ -1645,14 +1691,19 @@ class AssetsApi {
/// Parameters:
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
@@ -1662,18 +1713,25 @@ class AssetsApi {
/// sha1 checksum that can be used for duplicate detection before the file is uploaded
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
///
/// * [bool] isFavorite:
/// Mark as favorite
///
/// * [String] livePhotoVideoId:
/// Live photo video ID
///
/// * [List<AssetMetadataUpsertItemDto>] metadata:
/// Asset metadata items
///
/// * [MultipartFile] sidecarData:
/// Sidecar file data
///
/// * [AssetVisibility] visibility:
/// Asset visibility
Future<AssetMediaResponseDto?> uploadAsset(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, List<AssetMetadataUpsertItemDto>? metadata, MultipartFile? sidecarData, AssetVisibility? visibility, }) async {
final response = await uploadAssetWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, xImmichChecksum: xImmichChecksum, duration: duration, filename: filename, isFavorite: isFavorite, livePhotoVideoId: livePhotoVideoId, metadata: metadata, sidecarData: sidecarData, visibility: visibility, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -1700,10 +1758,12 @@ class AssetsApi {
/// * [String] id (required):
///
/// * [bool] edited:
/// Return edited asset if available
///
/// * [String] key:
///
/// * [AssetMediaSize] size:
/// Asset media size
///
/// * [String] slug:
Future<Response> viewAssetWithHttpInfo(String id, { bool? edited, String? key, AssetMediaSize? size, String? slug, }) async {
@@ -1754,10 +1814,12 @@ class AssetsApi {
/// * [String] id (required):
///
/// * [bool] edited:
/// Return edited asset if available
///
/// * [String] key:
///
/// * [AssetMediaSize] size:
/// Asset media size
///
/// * [String] slug:
Future<MultipartFile?> viewAsset(String id, { bool? edited, String? key, AssetMediaSize? size, String? slug, }) async {

View File

@@ -82,6 +82,7 @@ class DeprecatedApi {
/// Parameters:
///
/// * [String] deviceId (required):
/// Device ID
Future<Response> getAllUserAssetsByDeviceIdWithHttpInfo(String deviceId,) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/device/{deviceId}'
@@ -115,6 +116,7 @@ class DeprecatedApi {
/// Parameters:
///
/// * [String] deviceId (required):
/// Device ID
Future<List<String>?> getAllUserAssetsByDeviceId(String deviceId,) async {
final response = await getAllUserAssetsByDeviceIdWithHttpInfo(deviceId,);
if (response.statusCode >= HttpStatus.badRequest) {
@@ -305,6 +307,7 @@ class DeprecatedApi {
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<Response> getRandomWithHttpInfo({ num? count, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/random';
@@ -341,6 +344,7 @@ class DeprecatedApi {
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<List<AssetResponseDto>?> getRandom({ num? count, }) async {
final response = await getRandomWithHttpInfo( count: count, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -370,22 +374,29 @@ class DeprecatedApi {
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<Response> replaceAssetWithHttpInfo(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/{id}/original'
@@ -462,22 +473,29 @@ class DeprecatedApi {
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<AssetMediaResponseDto?> replaceAsset(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
final response = await replaceAssetWithHttpInfo(id, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, duration: duration, filename: filename, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -502,6 +520,7 @@ class DeprecatedApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<Response> runQueueCommandLegacyWithHttpInfo(QueueName name, QueueCommandDto queueCommandDto,) async {
@@ -537,6 +556,7 @@ class DeprecatedApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<QueueResponseLegacyDto?> runQueueCommandLegacy(QueueName name, QueueCommandDto queueCommandDto,) async {

View File

@@ -126,6 +126,7 @@ class FacesApi {
/// Parameters:
///
/// * [String] id (required):
/// Face ID
Future<Response> getFacesWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final apiPath = r'/faces';
@@ -160,6 +161,7 @@ class FacesApi {
/// Parameters:
///
/// * [String] id (required):
/// Face ID
Future<List<AssetFaceResponseDto>?> getFaces(String id,) async {
final response = await getFacesWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -121,6 +121,7 @@ class JobsApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<Response> runQueueCommandLegacyWithHttpInfo(QueueName name, QueueCommandDto queueCommandDto,) async {
@@ -156,6 +157,7 @@ class JobsApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<QueueResponseLegacyDto?> runQueueCommandLegacy(QueueName name, QueueCommandDto queueCommandDto,) async {

View File

@@ -25,16 +25,22 @@ class MapApi {
/// Parameters:
///
/// * [DateTime] fileCreatedAfter:
/// Filter assets created after this date
///
/// * [DateTime] fileCreatedBefore:
/// Filter assets created before this date
///
/// * [bool] isArchived:
/// Filter by archived status
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] withPartners:
/// Include partner assets
///
/// * [bool] withSharedAlbums:
/// Include shared album assets
Future<Response> getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, bool? withSharedAlbums, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/map/markers';
@@ -86,16 +92,22 @@ class MapApi {
/// Parameters:
///
/// * [DateTime] fileCreatedAfter:
/// Filter assets created after this date
///
/// * [DateTime] fileCreatedBefore:
/// Filter assets created before this date
///
/// * [bool] isArchived:
/// Filter by archived status
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] withPartners:
/// Include partner assets
///
/// * [bool] withSharedAlbums:
/// Include shared album assets
Future<List<MapMarkerResponseDto>?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, bool? withSharedAlbums, }) async {
final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, withPartners: withPartners, withSharedAlbums: withSharedAlbums, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -123,8 +135,10 @@ class MapApi {
/// Parameters:
///
/// * [double] lat (required):
/// Latitude (-90 to 90)
///
/// * [double] lon (required):
/// Longitude (-180 to 180)
Future<Response> reverseGeocodeWithHttpInfo(double lat, double lon,) async {
// ignore: prefer_const_declarations
final apiPath = r'/map/reverse-geocode';
@@ -160,8 +174,10 @@ class MapApi {
/// Parameters:
///
/// * [double] lat (required):
/// Latitude (-90 to 90)
///
/// * [double] lon (required):
/// Longitude (-180 to 180)
Future<List<MapReverseGeocodeResponseDto>?> reverseGeocode(double lat, double lon,) async {
final response = await reverseGeocodeWithHttpInfo(lat, lon,);
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -251,17 +251,22 @@ class MemoriesApi {
/// Parameters:
///
/// * [DateTime] for_:
/// Filter by date
///
/// * [bool] isSaved:
/// Filter by saved status
///
/// * [bool] isTrashed:
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<Response> memoriesStatisticsWithHttpInfo({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/memories/statistics';
@@ -313,17 +318,22 @@ class MemoriesApi {
/// Parameters:
///
/// * [DateTime] for_:
/// Filter by date
///
/// * [bool] isSaved:
/// Filter by saved status
///
/// * [bool] isTrashed:
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<MemoryStatisticsResponseDto?> memoriesStatistics({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
final response = await memoriesStatisticsWithHttpInfo( for_: for_, isSaved: isSaved, isTrashed: isTrashed, order: order, size: size, type: type, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -412,17 +422,22 @@ class MemoriesApi {
/// Parameters:
///
/// * [DateTime] for_:
/// Filter by date
///
/// * [bool] isSaved:
/// Filter by saved status
///
/// * [bool] isTrashed:
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<Response> searchMemoriesWithHttpInfo({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/memories';
@@ -474,17 +489,22 @@ class MemoriesApi {
/// Parameters:
///
/// * [DateTime] for_:
/// Filter by date
///
/// * [bool] isSaved:
/// Filter by saved status
///
/// * [bool] isTrashed:
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<List<MemoryResponseDto>?> searchMemories({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
final response = await searchMemoriesWithHttpInfo( for_: for_, isSaved: isSaved, isTrashed: isTrashed, order: order, size: size, type: type, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -179,12 +179,16 @@ class NotificationsApi {
/// Parameters:
///
/// * [String] id:
/// Filter by notification ID
///
/// * [NotificationLevel] level:
/// Filter by notification level
///
/// * [NotificationType] type:
/// Filter by notification type
///
/// * [bool] unread:
/// Filter by unread status
Future<Response> getNotificationsWithHttpInfo({ String? id, NotificationLevel? level, NotificationType? type, bool? unread, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/notifications';
@@ -230,12 +234,16 @@ class NotificationsApi {
/// Parameters:
///
/// * [String] id:
/// Filter by notification ID
///
/// * [NotificationLevel] level:
/// Filter by notification level
///
/// * [NotificationType] type:
/// Filter by notification type
///
/// * [bool] unread:
/// Filter by unread status
Future<List<NotificationDto>?> getNotifications({ String? id, NotificationLevel? level, NotificationType? type, bool? unread, }) async {
final response = await getNotificationsWithHttpInfo( id: id, level: level, type: type, unread: unread, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -138,6 +138,7 @@ class PartnersApi {
/// Parameters:
///
/// * [PartnerDirection] direction (required):
/// Partner direction
Future<Response> getPartnersWithHttpInfo(PartnerDirection direction,) async {
// ignore: prefer_const_declarations
final apiPath = r'/partners';
@@ -172,6 +173,7 @@ class PartnersApi {
/// Parameters:
///
/// * [PartnerDirection] direction (required):
/// Partner direction
Future<List<PartnerResponseDto>?> getPartners(PartnerDirection direction,) async {
final response = await getPartnersWithHttpInfo(direction,);
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -178,8 +178,10 @@ class PeopleApi {
/// Parameters:
///
/// * [String] closestAssetId:
/// Closest asset ID for similarity search
///
/// * [String] closestPersonId:
/// Closest person ID for similarity search
///
/// * [num] page:
/// Page number for pagination
@@ -188,6 +190,7 @@ class PeopleApi {
/// Number of items per page
///
/// * [bool] withHidden:
/// Include hidden people
Future<Response> getAllPeopleWithHttpInfo({ String? closestAssetId, String? closestPersonId, num? page, num? size, bool? withHidden, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/people';
@@ -236,8 +239,10 @@ class PeopleApi {
/// Parameters:
///
/// * [String] closestAssetId:
/// Closest asset ID for similarity search
///
/// * [String] closestPersonId:
/// Closest person ID for similarity search
///
/// * [num] page:
/// Page number for pagination
@@ -246,6 +251,7 @@ class PeopleApi {
/// Number of items per page
///
/// * [bool] withHidden:
/// Include hidden people
Future<PeopleResponseDto?> getAllPeople({ String? closestAssetId, String? closestPersonId, num? page, num? size, bool? withHidden, }) async {
final response = await getAllPeopleWithHttpInfo( closestAssetId: closestAssetId, closestPersonId: closestPersonId, page: page, size: size, withHidden: withHidden, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -25,6 +25,7 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueDeleteDto] queueDeleteDto (required):
Future<Response> emptyQueueWithHttpInfo(QueueName name, QueueDeleteDto queueDeleteDto,) async {
@@ -60,6 +61,7 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueDeleteDto] queueDeleteDto (required):
Future<void> emptyQueue(QueueName name, QueueDeleteDto queueDeleteDto,) async {
@@ -78,6 +80,7 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
Future<Response> getQueueWithHttpInfo(QueueName name,) async {
// ignore: prefer_const_declarations
final apiPath = r'/queues/{name}'
@@ -111,6 +114,7 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
Future<QueueResponseDto?> getQueue(QueueName name,) async {
final response = await getQueueWithHttpInfo(name,);
if (response.statusCode >= HttpStatus.badRequest) {
@@ -135,8 +139,10 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [List<QueueJobStatus>] status:
/// Filter jobs by status
Future<Response> getQueueJobsWithHttpInfo(QueueName name, { List<QueueJobStatus>? status, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/queues/{name}/jobs'
@@ -174,8 +180,10 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [List<QueueJobStatus>] status:
/// Filter jobs by status
Future<List<QueueJobResponseDto>?> getQueueJobs(QueueName name, { List<QueueJobStatus>? status, }) async {
final response = await getQueueJobsWithHttpInfo(name, status: status, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -254,6 +262,7 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueUpdateDto] queueUpdateDto (required):
Future<Response> updateQueueWithHttpInfo(QueueName name, QueueUpdateDto queueUpdateDto,) async {
@@ -289,6 +298,7 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueUpdateDto] queueUpdateDto (required):
Future<QueueResponseDto?> updateQueue(QueueName name, QueueUpdateDto queueUpdateDto,) async {

View File

@@ -127,18 +127,25 @@ class SearchApi {
/// Parameters:
///
/// * [SearchSuggestionType] type (required):
/// Suggestion type
///
/// * [String] country:
/// Filter by country
///
/// * [bool] includeNull:
/// Include null values in suggestions
///
/// * [String] lensModel:
/// Filter by lens model
///
/// * [String] make:
/// Filter by camera make
///
/// * [String] model:
/// Filter by camera model
///
/// * [String] state:
/// Filter by state/province
Future<Response> getSearchSuggestionsWithHttpInfo(SearchSuggestionType type, { String? country, bool? includeNull, String? lensModel, String? make, String? model, String? state, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/search/suggestions';
@@ -191,18 +198,25 @@ class SearchApi {
/// Parameters:
///
/// * [SearchSuggestionType] type (required):
/// Suggestion type
///
/// * [String] country:
/// Filter by country
///
/// * [bool] includeNull:
/// Include null values in suggestions
///
/// * [String] lensModel:
/// Filter by lens model
///
/// * [String] make:
/// Filter by camera make
///
/// * [String] model:
/// Filter by camera model
///
/// * [String] state:
/// Filter by state/province
Future<List<String>?> getSearchSuggestions(SearchSuggestionType type, { String? country, bool? includeNull, String? lensModel, String? make, String? model, String? state, }) async {
final response = await getSearchSuggestionsWithHttpInfo(type, country: country, includeNull: includeNull, lensModel: lensModel, make: make, model: model, state: state, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -342,68 +356,100 @@ class SearchApi {
/// Parameters:
///
/// * [List<String>] albumIds:
/// Filter by album IDs
///
/// * [String] city:
/// Filter by city name
///
/// * [String] country:
/// Filter by country name
///
/// * [DateTime] createdAfter:
/// Filter by creation date (after)
///
/// * [DateTime] createdBefore:
/// Filter by creation date (before)
///
/// * [String] deviceId:
/// Device ID to filter by
///
/// * [bool] isEncoded:
/// Filter by encoded status
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] isMotion:
/// Filter by motion photo status
///
/// * [bool] isNotInAlbum:
/// Filter assets not in any album
///
/// * [bool] isOffline:
/// Filter by offline status
///
/// * [String] lensModel:
/// Filter by lens model
///
/// * [String] libraryId:
/// Library ID to filter by
///
/// * [String] make:
/// Filter by camera make
///
/// * [int] minFileSize:
/// Minimum file size in bytes
///
/// * [String] model:
/// Filter by camera model
///
/// * [String] ocr:
/// Filter by OCR text content
///
/// * [List<String>] personIds:
/// Filter by person IDs
///
/// * [num] rating:
/// Filter by rating
///
/// * [num] size:
/// Number of results to return
///
/// * [String] state:
/// Filter by state/province name
///
/// * [List<String>] tagIds:
/// Filter by tag IDs
///
/// * [DateTime] takenAfter:
/// Filter by taken date (after)
///
/// * [DateTime] takenBefore:
/// Filter by taken date (before)
///
/// * [DateTime] trashedAfter:
/// Filter by trash date (after)
///
/// * [DateTime] trashedBefore:
/// Filter by trash date (before)
///
/// * [AssetTypeEnum] type:
/// Asset type filter
///
/// * [DateTime] updatedAfter:
/// Filter by update date (after)
///
/// * [DateTime] updatedBefore:
/// Filter by update date (before)
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
///
/// * [bool] withDeleted:
/// Include deleted assets
///
/// * [bool] withExif:
/// Include EXIF data in response
Future<Response> searchLargeAssetsWithHttpInfo({ List<String>? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceId, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, int? minFileSize, String? model, String? ocr, List<String>? personIds, num? rating, num? size, String? state, List<String>? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/search/large-assets';
@@ -533,68 +579,100 @@ class SearchApi {
/// Parameters:
///
/// * [List<String>] albumIds:
/// Filter by album IDs
///
/// * [String] city:
/// Filter by city name
///
/// * [String] country:
/// Filter by country name
///
/// * [DateTime] createdAfter:
/// Filter by creation date (after)
///
/// * [DateTime] createdBefore:
/// Filter by creation date (before)
///
/// * [String] deviceId:
/// Device ID to filter by
///
/// * [bool] isEncoded:
/// Filter by encoded status
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] isMotion:
/// Filter by motion photo status
///
/// * [bool] isNotInAlbum:
/// Filter assets not in any album
///
/// * [bool] isOffline:
/// Filter by offline status
///
/// * [String] lensModel:
/// Filter by lens model
///
/// * [String] libraryId:
/// Library ID to filter by
///
/// * [String] make:
/// Filter by camera make
///
/// * [int] minFileSize:
/// Minimum file size in bytes
///
/// * [String] model:
/// Filter by camera model
///
/// * [String] ocr:
/// Filter by OCR text content
///
/// * [List<String>] personIds:
/// Filter by person IDs
///
/// * [num] rating:
/// Filter by rating
///
/// * [num] size:
/// Number of results to return
///
/// * [String] state:
/// Filter by state/province name
///
/// * [List<String>] tagIds:
/// Filter by tag IDs
///
/// * [DateTime] takenAfter:
/// Filter by taken date (after)
///
/// * [DateTime] takenBefore:
/// Filter by taken date (before)
///
/// * [DateTime] trashedAfter:
/// Filter by trash date (after)
///
/// * [DateTime] trashedBefore:
/// Filter by trash date (before)
///
/// * [AssetTypeEnum] type:
/// Asset type filter
///
/// * [DateTime] updatedAfter:
/// Filter by update date (after)
///
/// * [DateTime] updatedBefore:
/// Filter by update date (before)
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
///
/// * [bool] withDeleted:
/// Include deleted assets
///
/// * [bool] withExif:
/// Include EXIF data in response
Future<List<AssetResponseDto>?> searchLargeAssets({ List<String>? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, String? deviceId, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, int? minFileSize, String? model, String? ocr, List<String>? personIds, num? rating, num? size, String? state, List<String>? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, }) async {
final response = await searchLargeAssetsWithHttpInfo( albumIds: albumIds, city: city, country: country, createdAfter: createdAfter, createdBefore: createdBefore, deviceId: deviceId, isEncoded: isEncoded, isFavorite: isFavorite, isMotion: isMotion, isNotInAlbum: isNotInAlbum, isOffline: isOffline, lensModel: lensModel, libraryId: libraryId, make: make, minFileSize: minFileSize, model: model, ocr: ocr, personIds: personIds, rating: rating, size: size, state: state, tagIds: tagIds, takenAfter: takenAfter, takenBefore: takenBefore, trashedAfter: trashedAfter, trashedBefore: trashedBefore, type: type, updatedAfter: updatedAfter, updatedBefore: updatedBefore, visibility: visibility, withDeleted: withDeleted, withExif: withExif, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -622,8 +700,10 @@ class SearchApi {
/// Parameters:
///
/// * [String] name (required):
/// Person name to search for
///
/// * [bool] withHidden:
/// Include hidden people
Future<Response> searchPersonWithHttpInfo(String name, { bool? withHidden, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/search/person';
@@ -661,8 +741,10 @@ class SearchApi {
/// Parameters:
///
/// * [String] name (required):
/// Person name to search for
///
/// * [bool] withHidden:
/// Include hidden people
Future<List<PersonResponseDto>?> searchPerson(String name, { bool? withHidden, }) async {
final response = await searchPersonWithHttpInfo(name, withHidden: withHidden, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -690,6 +772,7 @@ class SearchApi {
/// Parameters:
///
/// * [String] name (required):
/// Place name to search for
Future<Response> searchPlacesWithHttpInfo(String name,) async {
// ignore: prefer_const_declarations
final apiPath = r'/search/places';
@@ -724,6 +807,7 @@ class SearchApi {
/// Parameters:
///
/// * [String] name (required):
/// Place name to search for
Future<List<PlacesResponseDto>?> searchPlaces(String name,) async {
final response = await searchPlacesWithHttpInfo(name,);
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -160,8 +160,10 @@ class SharedLinksApi {
/// Parameters:
///
/// * [String] albumId:
/// Filter by album ID
///
/// * [String] id:
/// Filter by shared link ID
Future<Response> getAllSharedLinksWithHttpInfo({ String? albumId, String? id, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/shared-links';
@@ -201,8 +203,10 @@ class SharedLinksApi {
/// Parameters:
///
/// * [String] albumId:
/// Filter by album ID
///
/// * [String] id:
/// Filter by shared link ID
Future<List<SharedLinkResponseDto>?> getAllSharedLinks({ String? albumId, String? id, }) async {
final response = await getAllSharedLinksWithHttpInfo( albumId: albumId, id: id, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -232,10 +236,12 @@ class SharedLinksApi {
/// * [String] key:
///
/// * [String] password:
/// Link password
///
/// * [String] slug:
///
/// * [String] token:
/// Access token
Future<Response> getMySharedLinkWithHttpInfo({ String? key, String? password, String? slug, String? token, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/shared-links/me';
@@ -283,10 +289,12 @@ class SharedLinksApi {
/// * [String] key:
///
/// * [String] password:
/// Link password
///
/// * [String] slug:
///
/// * [String] token:
/// Access token
Future<SharedLinkResponseDto?> getMySharedLink({ String? key, String? password, String? slug, String? token, }) async {
final response = await getMySharedLinkWithHttpInfo( key: key, password: password, slug: slug, token: token, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -487,6 +495,77 @@ class SharedLinksApi {
return null;
}
/// Shared link login
///
/// Login to a password protected shared link
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [SharedLinkLoginDto] sharedLinkLoginDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> sharedLinkLoginWithHttpInfo(SharedLinkLoginDto sharedLinkLoginDto, { String? key, String? slug, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/shared-links/login';
// ignore: prefer_final_locals
Object? postBody = sharedLinkLoginDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
apiPath,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Shared link login
///
/// Login to a password protected shared link
///
/// Parameters:
///
/// * [SharedLinkLoginDto] sharedLinkLoginDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<SharedLinkResponseDto?> sharedLinkLogin(SharedLinkLoginDto sharedLinkLoginDto, { String? key, String? slug, }) async {
final response = await sharedLinkLoginWithHttpInfo(sharedLinkLoginDto, key: key, slug: slug, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'SharedLinkResponseDto',) as SharedLinkResponseDto;
}
return null;
}
/// Update a shared link
///
/// Update an existing shared link by its ID.

View File

@@ -289,6 +289,7 @@ class StacksApi {
/// Parameters:
///
/// * [String] primaryAssetId:
/// Filter by primary asset ID
Future<Response> searchStacksWithHttpInfo({ String? primaryAssetId, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/stacks';
@@ -325,6 +326,7 @@ class StacksApi {
/// Parameters:
///
/// * [String] primaryAssetId:
/// Filter by primary asset ID
Future<List<StackResponseDto>?> searchStacks({ String? primaryAssetId, }) async {
final response = await searchStacksWithHttpInfo( primaryAssetId: primaryAssetId, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -318,10 +318,13 @@ class UsersAdminApi {
/// * [String] id (required):
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] isTrashed:
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<Response> getUserStatisticsAdminWithHttpInfo(String id, { bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/admin/users/{id}/statistics'
@@ -367,10 +370,13 @@ class UsersAdminApi {
/// * [String] id (required):
///
/// * [bool] isFavorite:
/// Filter by favorite status
///
/// * [bool] isTrashed:
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<AssetStatsResponseDto?> getUserStatisticsAdmin(String id, { bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
final response = await getUserStatisticsAdminWithHttpInfo(id, isFavorite: isFavorite, isTrashed: isTrashed, visibility: visibility, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -452,8 +458,10 @@ class UsersAdminApi {
/// Parameters:
///
/// * [String] id:
/// User ID filter
///
/// * [bool] withDeleted:
/// Include deleted users
Future<Response> searchUsersAdminWithHttpInfo({ String? id, bool? withDeleted, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/admin/users';
@@ -493,8 +501,10 @@ class UsersAdminApi {
/// Parameters:
///
/// * [String] id:
/// User ID filter
///
/// * [bool] withDeleted:
/// Include deleted users
Future<List<UserAdminResponseDto>?> searchUsersAdmin({ String? id, bool? withDeleted, }) async {
final response = await searchUsersAdminWithHttpInfo( id: id, withDeleted: withDeleted, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -25,6 +25,7 @@ class UsersApi {
/// Parameters:
///
/// * [MultipartFile] file (required):
/// Profile image file
Future<Response> createProfileImageWithHttpInfo(MultipartFile file,) async {
// ignore: prefer_const_declarations
final apiPath = r'/users/profile-image';
@@ -67,6 +68,7 @@ class UsersApi {
/// Parameters:
///
/// * [MultipartFile] file (required):
/// Profile image file
Future<CreateProfileImageResponseDto?> createProfileImage(MultipartFile file,) async {
final response = await createProfileImageWithHttpInfo(file,);
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -630,6 +630,8 @@ class ApiClient {
return SharedLinkCreateDto.fromJson(value);
case 'SharedLinkEditDto':
return SharedLinkEditDto.fromJson(value);
case 'SharedLinkLoginDto':
return SharedLinkLoginDto.fromJson(value);
case 'SharedLinkResponseDto':
return SharedLinkResponseDto.fromJson(value);
case 'SharedLinkType':

View File

@@ -19,8 +19,10 @@ class ActivityCreateDto {
required this.type,
});
/// Album ID
String albumId;
/// Asset ID (if activity is for an asset)
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -29,6 +31,7 @@ class ActivityCreateDto {
///
String? assetId;
/// Comment text (required if type is comment)
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -37,6 +40,7 @@ class ActivityCreateDto {
///
String? comment;
/// Activity type (like or comment)
ReactionType type;
@override

View File

@@ -21,14 +21,19 @@ class ActivityResponseDto {
required this.user,
});
/// Asset ID (if activity is for an asset)
String? assetId;
/// Comment text (for comment activities)
String? comment;
/// Creation date
DateTime createdAt;
/// Activity ID
String id;
/// Activity type
ReactionType type;
UserResponseDto user;

View File

@@ -17,8 +17,10 @@ class ActivityStatisticsResponseDto {
required this.likes,
});
/// Number of comments
int comments;
/// Number of likes
int likes;
@override

View File

@@ -16,6 +16,7 @@ class AddUsersDto {
this.albumUsers = const [],
});
/// Album users to add
List<AlbumUserAddDto> albumUsers;
@override

View File

@@ -16,6 +16,7 @@ class AdminOnboardingUpdateDto {
required this.isOnboarded,
});
/// Is admin onboarded
bool isOnboarded;
@override

View File

@@ -34,22 +34,28 @@ class AlbumResponseDto {
required this.updatedAt,
});
/// Album name
String albumName;
/// Thumbnail asset ID
String? albumThumbnailAssetId;
List<AlbumUserResponseDto> albumUsers;
/// Number of assets
int assetCount;
List<AssetResponseDto> assets;
List<ContributorCountResponseDto> contributorCounts;
/// Creation date
DateTime createdAt;
/// Album description
String description;
/// End date (latest asset)
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -58,12 +64,16 @@ class AlbumResponseDto {
///
DateTime? endDate;
/// Has shared link
bool hasSharedLink;
/// Album ID
String id;
/// Activity feed enabled
bool isActivityEnabled;
/// Last modified asset timestamp
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -72,6 +82,7 @@ class AlbumResponseDto {
///
DateTime? lastModifiedAssetTimestamp;
/// Asset sort order
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -82,10 +93,13 @@ class AlbumResponseDto {
UserResponseDto owner;
/// Owner user ID
String ownerId;
/// Is shared album
bool shared;
/// Start date (earliest asset)
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -94,6 +108,7 @@ class AlbumResponseDto {
///
DateTime? startDate;
/// Last update date
DateTime updatedAt;
@override

View File

@@ -18,10 +18,13 @@ class AlbumStatisticsResponseDto {
required this.shared,
});
/// Number of non-shared albums
int notShared;
/// Number of owned albums
int owned;
/// Number of shared albums
int shared;
@override

View File

@@ -17,8 +17,10 @@ class AlbumUserAddDto {
required this.userId,
});
/// Album user role
AlbumUserRole role;
/// User ID
String userId;
@override

View File

@@ -17,8 +17,10 @@ class AlbumUserCreateDto {
required this.userId,
});
/// Album user role
AlbumUserRole role;
/// User ID
String userId;
@override

View File

@@ -17,6 +17,7 @@ class AlbumUserResponseDto {
required this.user,
});
/// Album user role
AlbumUserRole role;
UserResponseDto user;

View File

@@ -10,7 +10,7 @@
part of openapi.api;
/// Album user role
class AlbumUserRole {
/// Instantiate a new enum with the provided [value].
const AlbumUserRole._(this.value);

View File

@@ -17,8 +17,10 @@ class AlbumsAddAssetsDto {
this.assetIds = const [],
});
/// Album IDs
List<String> albumIds;
/// Asset IDs
List<String> assetIds;
@override

View File

@@ -17,6 +17,7 @@ class AlbumsAddAssetsResponseDto {
required this.success,
});
/// Error reason
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -25,6 +26,7 @@ class AlbumsAddAssetsResponseDto {
///
BulkIdErrorReason? error;
/// Operation success
bool success;
@override

View File

@@ -16,6 +16,7 @@ class AlbumsResponse {
this.defaultAssetOrder = AssetOrder.desc,
});
/// Default asset order for albums
AssetOrder defaultAssetOrder;
@override

View File

@@ -16,6 +16,7 @@ class AlbumsUpdate {
this.defaultAssetOrder,
});
/// Default asset order for albums
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated

View File

@@ -17,6 +17,7 @@ class APIKeyCreateDto {
this.permissions = const [],
});
/// API key name
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -25,6 +26,7 @@ class APIKeyCreateDto {
///
String? name;
/// List of permissions
List<Permission> permissions;
@override

View File

@@ -19,6 +19,7 @@ class APIKeyCreateResponseDto {
APIKeyResponseDto apiKey;
/// API key secret (only shown once)
String secret;
@override

View File

@@ -20,14 +20,19 @@ class APIKeyResponseDto {
required this.updatedAt,
});
/// Creation date
DateTime createdAt;
/// API key ID
String id;
/// API key name
String name;
/// List of permissions
List<Permission> permissions;
/// Last update date
DateTime updatedAt;
@override

View File

@@ -17,6 +17,7 @@ class APIKeyUpdateDto {
this.permissions = const [],
});
/// API key name
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -25,6 +26,7 @@ class APIKeyUpdateDto {
///
String? name;
/// List of permissions
List<Permission> permissions;
@override

View File

@@ -17,6 +17,7 @@ class AssetBulkDeleteDto {
this.ids = const [],
});
/// Force delete even if in use
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -25,6 +26,7 @@ class AssetBulkDeleteDto {
///
bool? force;
/// IDs to process
List<String> ids;
@override

View File

@@ -26,6 +26,7 @@ class AssetBulkUpdateDto {
this.visibility,
});
/// Original date and time
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -34,6 +35,7 @@ class AssetBulkUpdateDto {
///
String? dateTimeOriginal;
/// Relative time offset in seconds
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -42,6 +44,7 @@ class AssetBulkUpdateDto {
///
num? dateTimeRelative;
/// Asset description
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -50,10 +53,13 @@ class AssetBulkUpdateDto {
///
String? description;
/// Duplicate asset ID
String? duplicateId;
/// Asset IDs to update
List<String> ids;
/// Mark as favorite
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -62,6 +68,7 @@ class AssetBulkUpdateDto {
///
bool? isFavorite;
/// Latitude coordinate
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -70,6 +77,7 @@ class AssetBulkUpdateDto {
///
num? latitude;
/// Longitude coordinate
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -78,6 +86,8 @@ class AssetBulkUpdateDto {
///
num? longitude;
/// Rating
///
/// Minimum value: -1
/// Maximum value: 5
///
@@ -88,6 +98,7 @@ class AssetBulkUpdateDto {
///
num? rating;
/// Time zone (IANA timezone)
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -96,6 +107,7 @@ class AssetBulkUpdateDto {
///
String? timeZone;
/// Asset visibility
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated

View File

@@ -16,6 +16,7 @@ class AssetBulkUploadCheckDto {
this.assets = const [],
});
/// Assets to check
List<AssetBulkUploadCheckItem> assets;
@override

View File

@@ -17,9 +17,10 @@ class AssetBulkUploadCheckItem {
required this.id,
});
/// base64 or hex encoded sha1 hash
/// Base64 or hex encoded SHA1 hash
String checksum;
/// Asset ID
String id;
@override

View File

@@ -16,6 +16,7 @@ class AssetBulkUploadCheckResponseDto {
this.results = const [],
});
/// Upload check results
List<AssetBulkUploadCheckResult> results;
@override

View File

@@ -20,8 +20,10 @@ class AssetBulkUploadCheckResult {
this.reason,
});
/// Upload action
AssetBulkUploadCheckResultActionEnum action;
/// Existing asset ID if duplicate
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -30,8 +32,10 @@ class AssetBulkUploadCheckResult {
///
String? assetId;
/// Asset ID
String id;
/// Whether existing asset is trashed
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -40,6 +44,7 @@ class AssetBulkUploadCheckResult {
///
bool? isTrashed;
/// Rejection reason if rejected
AssetBulkUploadCheckResultReasonEnum? reason;
@override
@@ -150,7 +155,7 @@ class AssetBulkUploadCheckResult {
};
}
/// Upload action
class AssetBulkUploadCheckResultActionEnum {
/// Instantiate a new enum with the provided [value].
const AssetBulkUploadCheckResultActionEnum._(this.value);
@@ -224,7 +229,7 @@ class AssetBulkUploadCheckResultActionEnumTypeTransformer {
}
/// Rejection reason if rejected
class AssetBulkUploadCheckResultReasonEnum {
/// Instantiate a new enum with the provided [value].
const AssetBulkUploadCheckResultReasonEnum._(this.value);

View File

@@ -22,18 +22,25 @@ class AssetCopyDto {
required this.targetId,
});
/// Copy album associations
bool albums;
/// Copy favorite status
bool favorite;
/// Copy shared links
bool sharedLinks;
/// Copy sidecar file
bool sidecar;
/// Source asset ID
String sourceId;
/// Copy stack association
bool stack;
/// Target asset ID
String targetId;
@override

View File

@@ -17,8 +17,10 @@ class AssetDeltaSyncDto {
this.userIds = const [],
});
/// Sync assets updated after this date
DateTime updatedAfter;
/// User IDs to sync
List<String> userIds;
@override

View File

@@ -18,10 +18,13 @@ class AssetDeltaSyncResponseDto {
this.upserted = const [],
});
/// Deleted asset IDs
List<String> deleted;
/// Whether full sync is needed
bool needsFullSync;
/// Upserted assets
List<AssetResponseDto> upserted;
@override

View File

@@ -10,7 +10,7 @@
part of openapi.api;
/// Type of edit action to perform
class AssetEditAction {
/// Instantiate a new enum with the provided [value].
const AssetEditAction._(this.value);

View File

@@ -17,6 +17,7 @@ class AssetEditActionCrop {
required this.parameters,
});
/// Type of edit action to perform
AssetEditAction action;
CropParameters parameters;

View File

@@ -16,7 +16,7 @@ class AssetEditActionListDto {
this.edits = const [],
});
/// list of edits
/// List of edit actions to apply (crop, rotate, or mirror)
List<AssetEditActionListDtoEditsInner> edits;
@override

View File

@@ -17,6 +17,7 @@ class AssetEditActionListDtoEditsInner {
required this.parameters,
});
/// Type of edit action to perform
AssetEditAction action;
MirrorParameters parameters;

View File

@@ -17,6 +17,7 @@ class AssetEditActionMirror {
required this.parameters,
});
/// Type of edit action to perform
AssetEditAction action;
MirrorParameters parameters;

View File

@@ -17,6 +17,7 @@ class AssetEditActionRotate {
required this.parameters,
});
/// Type of edit action to perform
AssetEditAction action;
RotateParameters parameters;

View File

@@ -17,9 +17,10 @@ class AssetEditsDto {
this.edits = const [],
});
/// Asset ID to apply edits to
String assetId;
/// list of edits
/// List of edit actions to apply (crop, rotate, or mirror)
List<AssetEditActionListDtoEditsInner> edits;
@override

View File

@@ -23,20 +23,28 @@ class AssetFaceCreateDto {
required this.y,
});
/// Asset ID
String assetId;
/// Face bounding box height
int height;
/// Image height in pixels
int imageHeight;
/// Image width in pixels
int imageWidth;
/// Person ID
String personId;
/// Face bounding box width
int width;
/// Face bounding box X coordinate
int x;
/// Face bounding box Y coordinate
int y;
@override

View File

@@ -16,6 +16,7 @@ class AssetFaceDeleteDto {
required this.force,
});
/// Force delete even if person has other faces
bool force;
@override

View File

@@ -24,22 +24,31 @@ class AssetFaceResponseDto {
this.sourceType,
});
/// Bounding box X1 coordinate
int boundingBoxX1;
/// Bounding box X2 coordinate
int boundingBoxX2;
/// Bounding box Y1 coordinate
int boundingBoxY1;
/// Bounding box Y2 coordinate
int boundingBoxY2;
/// Face ID
String id;
/// Image height in pixels
int imageHeight;
/// Image width in pixels
int imageWidth;
/// Person associated with face
PersonResponseDto? person;
/// Face detection source type
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated

View File

@@ -16,6 +16,7 @@ class AssetFaceUpdateDto {
this.data = const [],
});
/// Face update items
List<AssetFaceUpdateItem> data;
@override

View File

@@ -17,8 +17,10 @@ class AssetFaceUpdateItem {
required this.personId,
});
/// Asset ID
String assetId;
/// Person ID
String personId;
@override

View File

@@ -23,20 +23,28 @@ class AssetFaceWithoutPersonResponseDto {
this.sourceType,
});
/// Bounding box X1 coordinate
int boundingBoxX1;
/// Bounding box X2 coordinate
int boundingBoxX2;
/// Bounding box Y1 coordinate
int boundingBoxY1;
/// Bounding box Y2 coordinate
int boundingBoxY2;
/// Face ID
String id;
/// Image height in pixels
int imageHeight;
/// Image width in pixels
int imageWidth;
/// Face detection source type
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated

View File

@@ -19,6 +19,7 @@ class AssetFullSyncDto {
this.userId,
});
/// Last asset ID (pagination)
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -27,11 +28,15 @@ class AssetFullSyncDto {
///
String? lastId;
/// Maximum number of assets to return
///
/// Minimum value: 1
int limit;
/// Sync assets updated until this date
DateTime updatedUntil;
/// Filter by user ID
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated

View File

@@ -16,6 +16,7 @@ class AssetIdsDto {
this.assetIds = const [],
});
/// Asset IDs
List<String> assetIds;
@override

View File

@@ -18,10 +18,13 @@ class AssetIdsResponseDto {
required this.success,
});
/// Asset ID
String assetId;
/// Error reason if failed
AssetIdsResponseDtoErrorEnum? error;
/// Whether operation succeeded
bool success;
@override
@@ -116,7 +119,7 @@ class AssetIdsResponseDto {
};
}
/// Error reason if failed
class AssetIdsResponseDtoErrorEnum {
/// Instantiate a new enum with the provided [value].
const AssetIdsResponseDtoErrorEnum._(this.value);

View File

@@ -10,7 +10,7 @@
part of openapi.api;
/// Job name
class AssetJobName {
/// Instantiate a new enum with the provided [value].
const AssetJobName._(this.value);

View File

@@ -17,8 +17,10 @@ class AssetJobsDto {
required this.name,
});
/// Asset IDs
List<String> assetIds;
/// Job name
AssetJobName name;
@override

View File

@@ -17,8 +17,10 @@ class AssetMediaResponseDto {
required this.status,
});
/// Asset media ID
String id;
/// Upload status
AssetMediaStatus status;
@override

View File

@@ -10,7 +10,7 @@
part of openapi.api;
/// Upload status
class AssetMediaStatus {
/// Instantiate a new enum with the provided [value].
const AssetMediaStatus._(this.value);

View File

@@ -16,6 +16,7 @@ class AssetMetadataBulkDeleteDto {
this.items = const [],
});
/// Metadata items to delete
List<AssetMetadataBulkDeleteItemDto> items;
@override

View File

@@ -17,8 +17,10 @@ class AssetMetadataBulkDeleteItemDto {
required this.key,
});
/// Asset ID
String assetId;
/// Metadata key
String key;
@override

View File

@@ -19,12 +19,16 @@ class AssetMetadataBulkResponseDto {
required this.value,
});
/// Asset ID
String assetId;
/// Metadata key
String key;
/// Last update date
DateTime updatedAt;
/// Metadata value (object)
Object value;
@override

View File

@@ -16,6 +16,7 @@ class AssetMetadataBulkUpsertDto {
this.items = const [],
});
/// Metadata items to upsert
List<AssetMetadataBulkUpsertItemDto> items;
@override

Some files were not shown because too many files have changed in this diff Show More