Compare commits

..

14 Commits

Author SHA1 Message Date
shenlong-tanwen
456ae684e6 fix: run background tasks in root isolate 2026-07-21 16:17:26 +05:30
Nikola Nedevski
2e587fc7e8 feat(docs): add bulgarian readme (#29427)
* Added Bulgarian readme.md

* Updated collaborators link for BG readme collaborators section.
2026-07-21 00:10:08 -04:00
renovate[bot]
df970da59e chore(deps): update dependency eslint-plugin-unicorn to v70 - abandoned (#29684)
* chore(deps): update dependency eslint-plugin-unicorn to v70

* fix: linting

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-07-20 23:47:14 -04:00
Rust
8061a2e5ff fix(web): fix Country/State filters when set to Unknown (#30026)
* fix(web): create emptyStringToNull helper func and apply it to country/state search payload generation

* chore: feedback

* fix: other empty string fields

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2026-07-20 21:15:00 -05:00
Daniel Dietzler
77091b0107 fix: search statistics locked folder permissions (#30063)
fix; search statistics locked folder permissions
2026-07-20 20:08:42 -04:00
Daniel Dietzler
4c754f2999 fix: timebuckets locked permissions (#30066) 2026-07-20 20:07:56 -04:00
Timon
6fa3f2feac chore: bump openapi-generator version to v7.24.0 (#30067)
* remove patch in favor of [OpenAPITools/openapi-generator#23930](https://github.com/OpenAPITools/openapi-generator/issues/23930)

partially revert "chore(mobile): make openapi requests abortable (#28692)"

* gen client

* bump openapi-generator version to v7.24.0

* gen client

* enum migration changes

* drop enum exhaustion switch check
2026-07-20 20:06:23 -04:00
Adam Gastineau
3f6897ef80 chore(mobile): enable Xcode displaying issues from Flutter inline (#30080) 2026-07-20 14:16:12 -05:00
Matthias Keim
89d0a9d59f fix(web): attach file picker input to DOM so iOS Safari fires change … (#29660)
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-07-20 19:03:42 +00:00
Adam Gastineau
45a6ea84af fix(mobile): prevent crash on video widget dispose (#30078) 2026-07-20 19:00:37 +00:00
shenlong
bf64f3867b fix: do not show the whats new page on fresh login (#30072)
* fix: do not show the whats new page on fresh login

* review suggestion

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2026-07-20 12:24:01 -05:00
Priyanshu
4a4d468aa2 fix(web): refresh folder view after asset deletion (#29899) 2026-07-20 18:20:52 +02:00
Priyanshu
522def1ed6 fix(web): align ContextMenu z-index with design-system token (#30015)
Co-authored-by: priyanshuANDcoad <priyanshu23154050@akgec.ac.in>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-07-20 13:54:59 +00:00
Timon
3adc3920fb chore: bump openapi-generator version to v7.23.0 (#28916) 2026-07-20 15:06:51 +02:00
438 changed files with 4006 additions and 7281 deletions

View File

@@ -65,7 +65,6 @@ jobs:
filters: |
mobile:
- 'mobile/**'
- 'native/**'
force-filters: |
- '.github/workflows/build-mobile.yml'
force-events: 'workflow_call,workflow_dispatch'
@@ -155,59 +154,6 @@ jobs:
flutter build apk --release
fi
- name: Verify native Android compatibility
run: |
apk=mobile/build/app/outputs/flutter-apk/app-release.apk
sdk=${ANDROID_SDK_ROOT:-${ANDROID_HOME:?Android SDK path is not set}}
min_sdk=$(sed -nE 's/^[[:space:]]*minSdk[[:space:]]*=[[:space:]]*([0-9]+)[[:space:]]*$/\1/p' mobile/android/app/build.gradle)
[[ $min_sdk =~ ^[0-9]+$ ]] || { printf 'Could not parse minSdk from mobile/android/app/build.gradle\n' >&2; exit 1; }
readelf=$(find "$sdk/ndk" -path '*/toolchains/llvm/prebuilt/*/bin/llvm-readelf' -print | sort -V | tail -n 1)
[[ -n $readelf ]] || { printf 'No llvm-readelf found under %s\n' "$sdk/ndk" >&2; exit 1; }
dir=$(mktemp -d)
trap 'rm -rf "$dir"' EXIT
test -f "$apk"
[[ -x $readelf ]] || { printf 'llvm-readelf is not executable: %s\n' "$readelf" >&2; exit 1; }
for abi in armeabi-v7a arm64-v8a x86_64; do
so="$dir/$abi.so"
unzip -p "$apk" "lib/$abi/libimmich_core_ffi.so" > "$so"
test -s "$so"
notes=$("$readelf" -n "$so")
headers=$("$readelf" -lW "$so")
printf '%s notes:\n%s\n' "$abi" "$notes"
printf '%s LOAD headers:\n%s\n' "$abi" "$(printf '%s\n' "$headers" | awk '/^[[:space:]]*LOAD[[:space:]]/')"
bytes=$(printf '%s\n' "$notes" | awk '
/^[[:space:]]*Android[[:space:]]/ { android = 1; next }
android && /description data:/ {
sub(/^.*description data:[[:space:]]*/, "")
print $1, $2, $3, $4
exit
}
')
read -r b0 b1 b2 b3 <<< "$bytes"
for byte in "$b0" "$b1" "$b2" "$b3"; do
[[ $byte =~ ^[0-9a-fA-F]{2}$ ]]
done
api=$((16#$b0 + (16#$b1 << 8) + (16#$b2 << 16) + (16#$b3 << 24)))
printf '%s Android API: %d\n' "$abi" "$api"
if ((api > min_sdk)); then
printf '%s Android API %d exceeds minSdk %d\n' "$abi" "$api" "$min_sdk" >&2
exit 1
fi
alignments=$(printf '%s\n' "$headers" | awk '/^[[:space:]]*LOAD[[:space:]]/ { print $NF }')
test -n "$alignments"
while read -r alignment; do
if [[ $alignment != 0x4000 ]]; then
printf '%s LOAD alignment %s is not 0x4000\n' "$abi" "$alignment" >&2
exit 1
fi
done <<< "$alignments"
done
- name: Publish Android Artifact
id: upload-apk
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1

View File

@@ -35,7 +35,6 @@ jobs:
mobile:
- 'mobile/**'
- 'i18n/en.json'
- 'native/**'
force-filters: |
- '.github/workflows/static_analysis.yml'
force-events: 'workflow_dispatch,release'

View File

@@ -59,10 +59,6 @@ jobs:
- 'mise.toml'
mobile:
- 'mobile/**'
- 'native/**'
- 'mise.toml'
native:
- 'native/**'
- 'mise.toml'
machine-learning:
- 'machine-learning/**'
@@ -73,45 +69,6 @@ jobs:
- '.github/workflows/test.yml'
force-events: 'workflow_dispatch'
native-tests:
name: Test & Lint Native Core
needs: pre-job
if: ${{ fromJSON(needs.pre-job.outputs.should_run).native == true }}
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: ./native
steps:
- id: token
uses: immich-app/devtools/actions/create-workflow-token@1af396ae134e4bc3b63d947e672bc68bf4ff9dc5 # create-workflow-token-action-v3.0.0
with:
client-id: ${{ secrets.PUSH_O_MATIC_APP_CLIENT_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
permission-contents: read
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
token: ${{ steps.token.outputs.token }}
- name: Setup Mise
uses: immich-app/devtools/actions/use-mise@3bca63ca3c15020293b36b51737a3ee2c773340b # use-mise-action-v3.1.0
with:
github_token: ${{ steps.token.outputs.token }}
working_directory: ./native
- name: Check formatting
run: cargo fmt --all --check
- name: Run Clippy
run: cargo clippy --workspace --all-targets --locked -- -D warnings
- name: Run tests
run: cargo test --workspace --locked
script-unit-tests:
name: Scripts unit tests
needs: pre-job

38
.vscode/settings.json vendored
View File

@@ -29,9 +29,6 @@
"editor.formatOnSave": true,
"tailwindCSS.lint.suggestCanonicalClasses": "ignore"
},
"svelte.plugin.svelte.compilerWarnings": {
"state_referenced_locally": "ignore"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
@@ -43,37 +40,40 @@
"eslint.useFlatConfig": true,
"eslint.validate": ["javascript", "typescript", "svelte"],
"eslint.workingDirectories": [
{ "directory": "cli", "changeProcessCWD": true },
{ "directory": "e2e", "changeProcessCWD": true },
{ "directory": "server", "changeProcessCWD": true },
{ "directory": "web", "changeProcessCWD": true }
{ "changeProcessCWD": true, "directory": "cli" },
{ "changeProcessCWD": true, "directory": "e2e" },
{ "changeProcessCWD": true, "directory": "server" },
{ "changeProcessCWD": true, "directory": "web" }
],
"files.watcherExclude": {
"**/.jj/**": true,
"**/.git/**": true,
"**/node_modules/**": true,
"**/build/**": true,
"**/dist/**": true,
"**/.svelte-kit/**": true
},
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"*.dart": "${capture}.g.dart,${capture}.gr.dart,${capture}.drift.dart",
"*.ts": "${capture}.spec.ts,${capture}.mock.ts",
"*.js": "${capture}.spec.js,${capture}.mock.js",
"*.ts": "${capture}.spec.ts,${capture}.mock.ts",
"package.json": "package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb, bun.lock, pnpm-workspace.yaml, .pnpmfile.cjs"
},
"files.watcherExclude": {
"**/.git/**": true,
"**/.jj/**": true,
"**/.svelte-kit/**": true,
"**/build/**": true,
"**/dist/**": true,
"**/node_modules/**": true
},
"js/ts.preferences.importModuleSpecifier": "non-relative",
"search.exclude": {
"**/node_modules": true,
"**/.svelte-kit": true,
"**/build": true,
"**/dist": true,
"**/.svelte-kit": true,
"**/node_modules": true,
"**/open-api/typescript-sdk/src": true
},
"svelte.enable-ts-plugin": true,
"svelte.plugin.svelte.compilerWarnings": {
"state_referenced_locally": "ignore"
},
"tailwindCSS.experimental.configFile": {
"web/src/app.css": "web/src/**"
},
"js/ts.preferences.importModuleSpecifier": "non-relative",
"vitest.maximumConfigs": 10
}

View File

@@ -5,4 +5,3 @@
/machine-learning/ @mertalev
/e2e/ @danieldietzler
/mobile/ @shenlong-tanwen @santoshakil @agg23
/native/ @santoshakil @mertalev

View File

@@ -32,6 +32,7 @@
<a href="readme_i18n/README_zh_TW.md">正體中文</a>
<a href="readme_i18n/README_uk_UA.md">Українська</a>
<a href="readme_i18n/README_ru_RU.md">Русский</a>
<a href="readme_i18n/README_bg_BG.md">Български</a>
<a href="readme_i18n/README_pt_BR.md">Português Brasileiro</a>
<a href="readme_i18n/README_sv_SE.md">Svenska</a>
<a href="readme_i18n/README_ar_JO.md">العربية</a>

View File

@@ -41,9 +41,17 @@ export default typescriptEslint.config([
'@typescript-eslint/no-floating-promises': 'error',
'unicorn/prefer-module': 'off',
'unicorn/import-style': 'off',
'unicorn/consistent-boolean-name': 'off',
'unicorn/no-non-function-verb-prefix': 'off',
'unicorn/no-unreadable-for-of-expression': 'off',
'unicorn/max-nested-calls': 'off',
'unicorn/prefer-uint8array-base64': 'off',
'unicorn/isolated-functions': 'off',
'unicorn/prefer-promise-with-resolvers': 'off',
'unicorn/no-declarations-before-early-exit': 'off',
curly: 2,
'prettier/prettier': 0,
'unicorn/prevent-abbreviations': 'off',
'unicorn/name-replacements': 'off',
'unicorn/filename-case': 'off',
'unicorn/no-null': 'off',
'unicorn/prefer-top-level-await': 'off',

View File

@@ -40,7 +40,7 @@
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^64.0.0",
"eslint-plugin-unicorn": "^70.0.0",
"exiftool-vendored": "^35.0.0",
"globals": "^17.0.0",
"luxon": "^3.4.4",

View File

@@ -118,7 +118,7 @@ describe('/admin/database-backups', () => {
expect(status).toBe(201);
cookie = headers['set-cookie'][0].split(';')[0];
cookie = headers['set-cookie'][0].split(';', 1)[0];
await expect
.poll(
@@ -224,7 +224,7 @@ describe('/admin/database-backups', () => {
});
expect(status).toBe(201);
cookie = headers['set-cookie'][0].split(';')[0];
cookie = headers['set-cookie'][0].split(';', 1)[0];
await expect
.poll(
@@ -295,7 +295,7 @@ describe('/admin/database-backups', () => {
});
expect(status).toBe(201);
cookie = headers['set-cookie'][0].split(';')[0];
cookie = headers['set-cookie'][0].split(';', 1)[0];
await expect
.poll(

View File

@@ -85,7 +85,7 @@ describe('/admin/maintenance', () => {
expect(status).toBe(201);
cookie = headers['set-cookie'][0].split(';')[0];
cookie = headers['set-cookie'][0].split(';', 1)[0];
expect(cookie).toEqual(
expect.stringMatching(/^immich_maintenance_token=[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*$/),
);
@@ -149,7 +149,7 @@ describe('/admin/maintenance', () => {
const { status, body } = await request(app)
.post('/admin/maintenance/login')
.send({
token: cookie!.split('=')[1].trim(),
token: cookie!.split('=', 2)[1].trim(),
});
expect(status).toBe(201);
expect(body).toEqual(

View File

@@ -27,7 +27,7 @@ test.describe('Maintenance', () => {
test('maintenance shows no options to users until they authenticate', async ({ page }) => {
const setCookie = await utils.enterMaintenance(admin.accessToken);
const cookie = setCookie
?.map((cookie) => cookie.split(';')[0].split('='))
?.map((cookie) => cookie.split(';', 1)[0].split('='))
?.find(([name]) => name === 'immich_maintenance_token');
expect(cookie).toBeTruthy();

View File

@@ -120,6 +120,7 @@ describe('/albums', () => {
}),
]);
// eslint-disable-next-line unicorn/no-unreadable-array-destructuring
[user2Albums[0]] = await Promise.all([
getAlbumInfo({ id: user2Albums[0].id }, { headers: asBearerAuth(user2.accessToken) }),
deleteUserAdmin({ id: user3.userId, userAdminDeleteDto: {} }, { headers: asBearerAuth(admin.accessToken) }),

View File

@@ -781,7 +781,7 @@ describe('/asset', () => {
exifImageWidth: 4032,
exifImageHeight: 3024,
latitude: 41.2203,
longitude: -96.071_625,
longitude: -96.071625,
make: 'Apple',
model: 'iPhone 7',
lensModel: 'iPhone 7 back camera 3.99mm f/1.8',
@@ -973,9 +973,9 @@ describe('/asset', () => {
fileSizeInByte: 31_175_472,
focalLength: 18.3,
iso: 100,
latitude: 36.613_24,
latitude: 36.61324,
lensModel: '18.3mm F2.8',
longitude: -121.897_85,
longitude: -121.89785,
make: 'RICOH IMAGING COMPANY, LTD.',
model: 'RICOH GR III',
orientation: '1',

View File

@@ -75,7 +75,7 @@ describe('/map', () => {
country: 'United States of America',
id: expect.any(String),
lat: expect.closeTo(39.115),
lon: expect.closeTo(-108.400_968),
lon: expect.closeTo(-108.400968),
state: 'Colorado',
},
{
@@ -83,7 +83,7 @@ describe('/map', () => {
country: 'United States of America',
id: expect.any(String),
lat: expect.closeTo(41.2203),
lon: expect.closeTo(-96.071_625),
lon: expect.closeTo(-96.071625),
state: 'Nebraska',
},
]);
@@ -123,7 +123,7 @@ describe('/map', () => {
country: 'United States of America',
id: expect.any(String),
lat: expect.closeTo(39.115),
lon: expect.closeTo(-108.400_968),
lon: expect.closeTo(-108.400968),
state: 'Colorado',
},
{
@@ -131,7 +131,7 @@ describe('/map', () => {
country: 'United States of America',
id: expect.any(String),
lat: expect.closeTo(41.2203),
lon: expect.closeTo(-96.071_625),
lon: expect.closeTo(-96.071625),
state: 'Nebraska',
},
]);
@@ -188,20 +188,20 @@ describe('/map', () => {
const reverseGeocodeTestCases = [
{
name: 'Vaucluse',
lat: -33.858_977_058_663_13,
lon: 151.278_490_730_270_48,
lat: -33.85897705866313,
lon: 151.27849073027048,
results: [{ city: 'Vaucluse', state: 'New South Wales', country: 'Australia' }],
},
{
name: 'Ravenhall',
lat: -37.765_732_399_174_75,
lon: 144.752_453_164_883_3,
lat: -37.76573239917475,
lon: 144.7524531648833,
results: [{ city: 'Ravenhall', state: 'Victoria', country: 'Australia' }],
},
{
name: 'Scarborough',
lat: -31.894_346_156_789_997,
lon: 115.757_617_103_904_64,
lat: -31.894346156789997,
lon: 115.75761710390464,
results: [{ city: 'Scarborough', state: 'Western Australia', country: 'Australia' }],
},
];

View File

@@ -44,7 +44,7 @@ const loginWithOAuth = async (sub: OAuthUser | string, redirectUri?: string) =>
});
// login
const response1 = await redirect(url.replace(authServer.internal, authServer.external));
const response1 = await redirect(url.replace(authServer.internal, () => authServer.external));
const response2 = await request(authServer.external + response1.location)
.post('')
.set('Cookie', response1.cookies)

View File

@@ -87,23 +87,23 @@ describe('/search', () => {
// note: the coordinates here are not the actual coordinates of the images and are random for most of them
const coordinates = [
{ latitude: 48.853_41, longitude: 2.3488 }, // paris
{ latitude: 35.6895, longitude: 139.691_71 }, // tokyo
{ latitude: 52.524_37, longitude: 13.410_53 }, // berlin
{ latitude: 1.314_663_1, longitude: 103.845_409_3 }, // singapore
{ latitude: 41.013_84, longitude: 28.949_66 }, // istanbul
{ latitude: 5.556_02, longitude: -0.1969 }, // accra
{ latitude: 37.544_270_6, longitude: -4.727_752_8 }, // andalusia
{ latitude: 23.133_02, longitude: -82.383_04 }, // havana
{ latitude: 41.694_11, longitude: 44.833_68 }, // tbilisi
{ latitude: 31.222_22, longitude: 121.458_06 }, // shanghai
{ latitude: 48.85341, longitude: 2.3488 }, // paris
{ latitude: 35.6895, longitude: 139.69171 }, // tokyo
{ latitude: 52.52437, longitude: 13.41053 }, // berlin
{ latitude: 1.3146631, longitude: 103.8454093 }, // singapore
{ latitude: 41.01384, longitude: 28.94966 }, // istanbul
{ latitude: 5.55602, longitude: -0.1969 }, // accra
{ latitude: 37.5442706, longitude: -4.7277528 }, // andalusia
{ latitude: 23.13302, longitude: -82.38304 }, // havana
{ latitude: 41.69411, longitude: 44.83368 }, // tbilisi
{ latitude: 31.22222, longitude: 121.45806 }, // shanghai
{ latitude: 38.9711, longitude: -109.7137 }, // thompson springs
{ latitude: 40.714_27, longitude: -74.005_97 }, // new york
{ latitude: 47.040_57, longitude: 9.068_04 }, // glarus
{ latitude: 32.771_52, longitude: -89.116_73 }, // philadelphia
{ latitude: 31.634_16, longitude: -7.999_94 }, // marrakesh
{ latitude: 38.523_735_4, longitude: -78.488_619_4 }, // tanners ridge
{ latitude: 59.938_63, longitude: 30.314_13 }, // st. petersburg
{ latitude: 40.71427, longitude: -74.00597 }, // new york
{ latitude: 47.04057, longitude: 9.06804 }, // glarus
{ latitude: 32.77152, longitude: -89.11673 }, // philadelphia
{ latitude: 31.63416, longitude: -7.99994 }, // marrakesh
{ latitude: 38.5237354, longitude: -78.4886194 }, // tanners ridge
{ latitude: 59.93863, longitude: 30.31413 }, // st. petersburg
{ latitude: 0, longitude: 0 }, // null island
];
@@ -112,7 +112,7 @@ describe('/search', () => {
);
await Promise.all(updates);
for (const [i] of coordinates.entries()) {
for (const i of coordinates.keys()) {
await utils.waitForWebsocketEvent({ event: 'assetUpdate', id: assets[i].id });
}

View File

@@ -31,7 +31,7 @@ describe(`immich login`, () => {
it('should login and save auth.yml with 600', async () => {
const admin = await utils.adminSetup();
const key = await utils.createApiKey(admin.accessToken, [Permission.All]);
const { stdout, stderr, exitCode } = await immichCli(['login', app, `${key.secret}`]);
const { stdout, stderr, exitCode } = await immichCli(['login', app, key.secret]);
expect(stdout.split('\n')).toEqual([
'Logging in to http://127.0.0.1:2285/api',
'Logged in as admin@immich.cloud',
@@ -48,7 +48,7 @@ describe(`immich login`, () => {
it('should login without /api in the url', async () => {
const admin = await utils.adminSetup();
const key = await utils.createApiKey(admin.accessToken, [Permission.All]);
const { stdout, stderr, exitCode } = await immichCli(['login', app.replaceAll('/api', ''), `${key.secret}`]);
const { stdout, stderr, exitCode } = await immichCli(['login', app.replaceAll('/api', ''), key.secret]);
expect(stdout.split('\n')).toEqual([
'Logging in to http://127.0.0.1:2285',
'Discovered API at http://127.0.0.1:2285/api',

View File

@@ -119,7 +119,9 @@ describe(`immich upload`, () => {
const baseDir = `/tmp/upload/`;
const testPaths = Object.keys(files).map((filePath) => `${baseDir}/${filePath}`);
testPaths.map((filePath) => utils.createImageFile(filePath));
for (const filePath of testPaths) {
utils.createImageFile(filePath);
}
const commandLine = paths.map((argument) => `${baseDir}/${argument}`);
@@ -135,7 +137,9 @@ describe(`immich upload`, () => {
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(expectedCount);
testPaths.map((filePath) => utils.removeImageFile(filePath));
for (const filePath of testPaths) {
utils.removeImageFile(filePath);
}
});
}
});

View File

@@ -21,7 +21,7 @@ export const randomImageFromString = async (
let seedNumber = 0;
for (let i = 0; i < seed.length; i++) {
seedNumber = (seedNumber << 5) - seedNumber + (seed.codePointAt(i) ?? 0);
seedNumber = seedNumber & seedNumber; // Convert to 32bit integer
seedNumber &= seedNumber; // Convert to 32bit integer
}
return randomImage(new SeededRandom(Math.abs(seedNumber)), { width, height });
};

View File

@@ -64,7 +64,7 @@ export function generateAsset(
const asset: MockTimelineAsset = {
id: assetId,
ownerId,
ratio: Number.parseFloat(ratio.split(':')[0]) / Number.parseFloat(ratio.split(':')[1]),
ratio: Number(ratio.split(':', 1)[0]) / Number(ratio.split(':', 2)[1]),
thumbhash: generateThumbhash(rng),
localDateTime: date.toISOString(),
fileCreatedAt: date.toISOString(),
@@ -214,7 +214,7 @@ export function generateTimelineData(config: TimelineConfig): MockTimelineData {
}
// Create a mock album from random assets
const allAssets = [...buckets.values()].flat();
const allAssets = buckets.values().toArray().flat();
// Select 10-30 random assets for the album (or all assets if less than 10)
const albumSize = Math.min(allAssets.length, globalRng.nextInt(10, 31));

View File

@@ -172,11 +172,7 @@ function shouldIncludeAsset(
if (isArchived !== undefined && actuallyArchived !== isArchived) {
return false;
}
if (isFavorite !== undefined && actuallyFavorited !== isFavorite) {
return false;
}
return true;
return isFavorite === undefined || actuallyFavorited === isFavorite;
}
/**
* Get summary for all buckets (mimics getTimeBuckets API)
@@ -361,7 +357,7 @@ export function getAsset(
owner?: UserResponseDto,
): AssetResponseDto | undefined {
// Search through all buckets for the asset
const buckets = [...timelineData.buckets.values()];
const buckets = timelineData.buckets.values().toArray();
for (const assets of buckets) {
const asset = assets.find((a) => a.id === assetId);
if (asset) {
@@ -395,7 +391,7 @@ export function getAlbum(
// Get the actual asset objects from the timeline data
const albumAssets: AssetResponseDto[] = [];
const allAssets = [...timelineData.buckets.values()].flat();
const allAssets = timelineData.buckets.values().toArray().flat();
for (const assetId of album.assetIds) {
const assetConfig = allAssets.find((a) => a.id === assetId);

View File

@@ -143,7 +143,7 @@ export function validateTimelineConfig(config: TimelineConfig): void {
}
// Validate seed if provided
if (config.seed !== undefined && (config.seed < 0 || !Number.isInteger(config.seed))) {
if (config.seed !== undefined && (config.seed < 0 || !Number.isSafeInteger(config.seed))) {
throw new Error('Seed must be a non-negative integer');
}

View File

@@ -153,11 +153,8 @@ export function getMockAsset(
const isInDifferentPeriod = (date1: DateTime, date2: DateTime): boolean => {
if (unit === 'day') {
return !date1.startOf('day').equals(date2.startOf('day'));
} else if (unit === 'month') {
return date1.year !== date2.year || date1.month !== date2.month;
} else {
return date1.year !== date2.year;
}
return unit === 'month' ? date1.year !== date2.year || date1.month !== date2.month : date1.year !== date2.year;
};
if (direction === 'next') {

View File

@@ -40,7 +40,8 @@ export const setupTimelineMockApiRoutes = async (
contentType: 'application/json',
json: getTimeBuckets(timelineRestData, isTrashed, isArchived, isFavorite, albumId, changes),
});
} else if (pathname === '/api/timeline/bucket') {
}
if (pathname === '/api/timeline/bucket') {
const timeBucket = url.searchParams.get('timeBucket');
if (!timeBucket) {
return route.continue();

View File

@@ -1,3 +1,4 @@
/* eslint-disable unicorn/no-this-outside-of-class */
import type { AssetResponseDto } from '@immich/sdk';
import { expect, Page } from '@playwright/test';

View File

@@ -72,6 +72,7 @@ export const thumbnailUtils = {
},
async queryThumbnailInViewport(page: Page, collector: (assetId: string) => boolean) {
const assetIds: string[] = [];
// eslint-disable-next-line unicorn/no-this-outside-of-class
for (const thumb of await this.locator(page).all()) {
const box = await thumb.boundingBox();
if (box) {
@@ -151,6 +152,7 @@ export const timelineUtils = {
page.evaluate(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return document.querySelector('#asset-grid').scrollTop;
});
await expect.poll(queryTop).toBeGreaterThan(0);
@@ -177,6 +179,7 @@ export const assetViewerUtils = {
page.evaluate(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line unicorn/no-optional-chaining-on-undeclared-variable
return document.activeElement?.dataset?.asset;
});
await expect(poll(page, activeElement, (result) => result === assetId)).resolves.toBe(assetId);

View File

@@ -1,3 +1,4 @@
/* eslint-disable unicorn/no-top-level-assignment-in-function */
import {
AssetMediaCreateDto,
AssetMediaResponseDto,
@@ -177,7 +178,7 @@ export const utils = {
resetDatabase: async (tables?: string[]) => {
client = await utils.connectDatabase();
tables = tables || [
tables ||= [
// TODO e2e test for deleting a stack, since it is quite complex
'stack',
'library',
@@ -304,7 +305,7 @@ export const utils = {
},
adminSetup: async (options?: AdminSetupOptions) => {
options = options || { onboarding: true };
options ||= { onboarding: true };
await signUpAdmin({ signUpDto: signupDto.admin });
const response = await login({ loginCredentialDto: loginDto.admin });
@@ -545,6 +546,7 @@ export const utils = {
{
headers: asBearerAuth(accessToken),
fetch: (...args: Parameters<typeof fetch>) =>
// eslint-disable-next-line unicorn/no-invalid-argument-count, unicorn/prefer-await
fetch(...args).then((response) => {
setCookie = response.headers.getSetCookie();
return response;
@@ -674,7 +676,7 @@ export const utils = {
cliLogin: async (accessToken: string) => {
const key = await utils.createApiKey(accessToken, [Permission.All]);
await immichCli(['login', app, `${key.secret}`]);
await immichCli(['login', app, key.secret]);
return key.secret;
},
@@ -706,6 +708,7 @@ export const utils = {
},
};
// eslint-disable-next-line unicorn/no-top-level-side-effects
utils.initSdk();
if (!existsSync(`${testAssetDir}/albums`)) {

View File

@@ -10,6 +10,7 @@
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"target": "es2023",
"lib": ["dom", "ESNext"],
"sourceMap": true,
"outDir": "./dist",
"incremental": true,

View File

@@ -12,7 +12,6 @@ config_roots = [
"docs",
".github",
"machine-learning",
"native",
]
[tools]

View File

@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.12)
set(CMAKE_C_STANDARD 17)
set(CMAKE_C_STANDARD_REQUIRED ON)
project(native_buffer LANGUAGES C)
add_library(native_buffer SHARED
src/main/cpp/native_buffer.c
src/main/cpp/native_image.c
)
target_link_libraries(native_buffer jnigraphics)

View File

@@ -77,6 +77,11 @@ android {
}
namespace 'app.alextran.immich'
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
flutter {

View File

@@ -0,0 +1,52 @@
#include <jni.h>
#include <stdlib.h>
#include <string.h>
JNIEXPORT jlong JNICALL
Java_app_alextran_immich_NativeBuffer_allocate(
JNIEnv *env, jclass clazz, jint size) {
void *ptr = malloc(size);
return (jlong) ptr;
}
JNIEXPORT void JNICALL
Java_app_alextran_immich_NativeBuffer_free(
JNIEnv *env, jclass clazz, jlong address) {
free((void *) address);
}
JNIEXPORT jlong JNICALL
Java_app_alextran_immich_NativeBuffer_realloc(
JNIEnv *env, jclass clazz, jlong address, jint size) {
void *ptr = realloc((void *) address, size);
return (jlong) ptr;
}
JNIEXPORT jobject JNICALL
Java_app_alextran_immich_NativeBuffer_wrap(
JNIEnv *env, jclass clazz, jlong address, jint capacity) {
return (*env)->NewDirectByteBuffer(env, (void *) address, capacity);
}
JNIEXPORT void JNICALL
Java_app_alextran_immich_NativeBuffer_copy(
JNIEnv *env, jclass clazz, jobject buffer, jlong destAddress, jint offset, jint length) {
void *src = (*env)->GetDirectBufferAddress(env, buffer);
if (src != NULL) {
memcpy((void *) destAddress, (char *) src + offset, length);
}
}
/**
* Creates a JNI global reference to the given object and returns its address.
* The caller is responsible for deleting the global reference when it's no longer needed.
*/
JNIEXPORT jlong JNICALL
Java_app_alextran_immich_NativeBuffer_createGlobalRef(JNIEnv *env, jobject clazz, jobject obj) {
if (obj == NULL) {
return 0;
}
jobject globalRef = (*env)->NewGlobalRef(env, obj);
return (jlong) globalRef;
}

View File

@@ -0,0 +1,173 @@
#include <jni.h>
#include <stdlib.h>
#include <stdint.h>
#include <android/bitmap.h>
// Cache-friendly block size for the tiled rotation (in pixels). 32x32 uint32 = 4KB, fits L1.
#define TILE 32
// EXIF orientation values (androidx.exifinterface.media.ExifInterface.ORIENTATION_*).
enum {
ORIENTATION_FLIP_HORIZONTAL = 2,
ORIENTATION_ROTATE_180 = 3,
ORIENTATION_FLIP_VERTICAL = 4,
ORIENTATION_TRANSPOSE = 5,
ORIENTATION_ROTATE_90 = 6,
ORIENTATION_TRANSVERSE = 7,
ORIENTATION_ROTATE_270 = 8,
};
// The orientations that swap width and height. Must stay in sync with affine_for's dim usage.
static int swaps_dims(int o) {
return o == ORIENTATION_ROTATE_90 || o == ORIENTATION_ROTATE_270 ||
o == ORIENTATION_TRANSPOSE || o == ORIENTATION_TRANSVERSE;
}
// A source pixel (sx, sy) maps to destination index base + sx*stepX + sy*stepY, where dw is the
// destination width. This affine form covers all 8 EXIF orientations and matches the pixel layout
// of Bitmap.createBitmap(src, matrixForExifOrientation(o)). int64_t so it stays correct on
// armeabi-v7a (32-bit long) regardless of how large MAX_RAW_DECODE_PIXELS grows.
static void affine_for(int o, int sw, int sh, int dw, int64_t *base, int64_t *stepX, int64_t *stepY) {
switch (o) {
case ORIENTATION_ROTATE_90: *base = sh - 1; *stepX = dw; *stepY = -1; break;
case ORIENTATION_ROTATE_270: *base = (int64_t) (sw - 1) * dw; *stepX = -dw; *stepY = 1; break;
case ORIENTATION_ROTATE_180: *base = (int64_t) (sh - 1) * dw + (sw - 1); *stepX = -1; *stepY = -dw; break;
case ORIENTATION_FLIP_HORIZONTAL: *base = sw - 1; *stepX = -1; *stepY = dw; break;
case ORIENTATION_FLIP_VERTICAL: *base = (int64_t) (sh - 1) * dw; *stepX = 1; *stepY = -dw; break;
case ORIENTATION_TRANSPOSE: *base = 0; *stepX = dw; *stepY = 1; break;
case ORIENTATION_TRANSVERSE: *base = (int64_t) (sw - 1) * dw + (sh - 1); *stepX = -dw; *stepY = -1; break;
default: *base = 0; *stepX = 1; *stepY = dw; break;
}
}
// Copy each source pixel (whole uint32, so channel order/premult is irrelevant) to its rotated
// destination, walking TILE x TILE blocks so the scattered writes of a 90/270 transpose stay
// cache-resident. dst is densely packed (rowBytes == dw*4, no padding), which the affine math relies on.
static void rotate_tiled(const uint8_t *src, int srcStride, uint32_t *dst,
int sw, int sh, int64_t base, int64_t stepX, int64_t stepY) {
for (int ty = 0; ty < sh; ty += TILE) {
int yEnd = ty + TILE < sh ? ty + TILE : sh;
for (int tx = 0; tx < sw; tx += TILE) {
int xEnd = tx + TILE < sw ? tx + TILE : sw;
for (int sy = ty; sy < yEnd; sy++) {
const uint32_t *srcRow = (const uint32_t *) (src + (size_t) sy * srcStride);
int64_t idx = base + (int64_t) sy * stepY + (int64_t) tx * stepX;
for (int sx = tx; sx < xEnd; sx++) {
dst[idx] = srcRow[sx];
idx += stepX;
}
}
}
}
}
// Rotates an RGBA_8888 bitmap to the given EXIF orientation into a freshly malloc'd buffer (free it
// via NativeBuffer.free). Fills outInfo with {width, height, rowBytes} and returns the buffer
// address, or 0 if the bitmap can't be handled (e.g. a non-8888 format) so the caller can fall back.
JNIEXPORT jlong JNICALL
Java_app_alextran_immich_NativeImage_rotate(
JNIEnv *env, jclass clazz, jobject bitmap, jint orientation, jintArray outInfo) {
AndroidBitmapInfo info;
if (AndroidBitmap_getInfo(env, bitmap, &info) != ANDROID_BITMAP_RESULT_SUCCESS) {
return 0;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
return 0;
}
int sw = (int) info.width;
int sh = (int) info.height;
int dw = swaps_dims(orientation) ? sh : sw;
int dh = swaps_dims(orientation) ? sw : sh;
uint32_t *dst = (uint32_t *) malloc((size_t) dw * dh * 4);
if (dst == NULL) {
return 0;
}
void *srcPixels = NULL;
if (AndroidBitmap_lockPixels(env, bitmap, &srcPixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
free(dst);
return 0;
}
int64_t base, stepX, stepY;
affine_for(orientation, sw, sh, dw, &base, &stepX, &stepY);
rotate_tiled((const uint8_t *) srcPixels, (int) info.stride, dst, sw, sh, base, stepX, stepY);
AndroidBitmap_unlockPixels(env, bitmap);
jint dims[3] = {dw, dh, dw * 4};
(*env)->SetIntArrayRegion(env, outInfo, 0, 3, dims);
// Keep ownership in C until the buffer is safely handed back: if outInfo was somehow too small,
// SetIntArrayRegion left a pending exception and Kotlin will never receive (or free) dst.
if ((*env)->ExceptionCheck(env)) {
free(dst);
return 0;
}
return (jlong) dst;
}
// Convert an RGBA_1010102 buffer to densely-packed RGBA_8888, matching Skia's
// Bitmap.copy(ARGB_8888) byte-for-byte so it's a drop-in for the intermediate 8888 bitmap.
// Each source pixel is a native (little-endian on every Android ABI) u32 with R in bits 0-9,
// G in 10-19, B in 20-29, A in 30-31 (standard RGB10_A2). Each 10-bit channel maps to 8-bit via
// round(v*255/1023). The 2-bit alpha maps to a*85. Both are kept as plain arithmetic as the whole
// loop auto-vectorizes to NEON and measures faster than a LUT on-device. Output is R,G,B,A bytes
// per pixel, i.e. Android ARGB_8888 memory == Dart PixelFormat.rgba8888.
static void convert_1010102(const uint8_t *src, int srcStride, uint32_t *dst, int w, int h) {
for (int y = 0; y < h; y++) {
const uint32_t *srcRow = (const uint32_t *) (src + (size_t) y * srcStride);
uint32_t *dstRow = dst + (size_t) y * w;
for (int x = 0; x < w; x++) {
uint32_t px = srcRow[x];
uint32_t r = ((px & 0x3FF) * 16336u + 32768u) >> 16;
uint32_t g = (((px >> 10) & 0x3FF) * 16336u + 32768u) >> 16;
uint32_t b = (((px >> 20) & 0x3FF) * 16336u + 32768u) >> 16;
uint32_t a = ((px >> 30) & 0x3) * 85u;
dstRow[x] = r | (g << 8) | (b << 16) | (a << 24);
}
}
}
// Converts an RGBA_1010102 bitmap (what a 10-bit HEIC/AVIF decodes to on API 33+) into a freshly
// malloc'd RGBA_8888 buffer. Fills outInfo with {width, height, rowBytes} and returns the buffer
// address, or 0 (so the caller falls back to a Skia copy) if the bitmap isn't 1010102 or can't be
// locked. Same ownership contract as rotate: free the returned buffer via NativeBuffer.free.
JNIEXPORT jlong JNICALL
Java_app_alextran_immich_NativeImage_convert1010102(
JNIEnv *env, jclass clazz, jobject bitmap, jintArray outInfo) {
AndroidBitmapInfo info;
if (AndroidBitmap_getInfo(env, bitmap, &info) != ANDROID_BITMAP_RESULT_SUCCESS) {
return 0;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_1010102) {
return 0;
}
int w = (int) info.width;
int h = (int) info.height;
uint32_t *dst = (uint32_t *) malloc((size_t) w * h * 4);
if (dst == NULL) {
return 0;
}
void *srcPixels = NULL;
if (AndroidBitmap_lockPixels(env, bitmap, &srcPixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
free(dst);
return 0;
}
convert_1010102((const uint8_t *) srcPixels, (int) info.stride, dst, w, h);
AndroidBitmap_unlockPixels(env, bitmap);
jint dims[3] = {w, h, w * 4};
(*env)->SetIntArrayRegion(env, outInfo, 0, 3, dims);
if ((*env)->ExceptionCheck(env)) {
free(dst);
return 0;
}
return (jlong) dst;
}

View File

@@ -6,7 +6,7 @@ const val INITIAL_BUFFER_SIZE = 32 * 1024
object NativeBuffer {
init {
System.loadLibrary("immich_core_ffi")
System.loadLibrary("native_buffer")
}
@JvmStatic
@@ -21,6 +21,9 @@ object NativeBuffer {
@JvmStatic
external fun wrap(address: Long, capacity: Int): ByteBuffer
@JvmStatic
external fun copy(buffer: ByteBuffer, destAddress: Long, offset: Int, length: Int)
@JvmStatic
external fun createGlobalRef(obj: Any): Long
}
@@ -32,12 +35,8 @@ class NativeByteBuffer(initialCapacity: Int) {
inline fun ensureHeadroom() {
if (offset == capacity) {
check(capacity <= Int.MAX_VALUE / 2) { "Native buffer capacity overflow" }
val newCapacity = capacity * 2
val newPointer = NativeBuffer.realloc(pointer, newCapacity)
check(newPointer != 0L) { "Native buffer realloc failed" }
pointer = newPointer
capacity = newCapacity
capacity *= 2
pointer = NativeBuffer.realloc(pointer, capacity)
}
}

View File

@@ -4,27 +4,26 @@ import android.graphics.Bitmap
object NativeImage {
init {
System.loadLibrary("immich_core_ffi")
// rotate() is compiled into the native_buffer shared lib (which already links jnigraphics).
System.loadLibrary("native_buffer")
}
/**
* Rotates an RGBA_8888 [bitmap] and returns a malloc'd buffer, or 0 on failure.
* [outInfo] receives width, height, and row bytes.
* Rotates an RGBA_8888 [bitmap] to the given EXIF [orientation], writing the result into a freshly
* malloc'd native buffer. Returns the buffer address (free it with [NativeBuffer.free]) and fills
* [outInfo] with {width, height, rowBytes}. Returns 0 when the bitmap can't be handled (e.g. a
* non-8888 config) so the caller can fall back.
*/
@JvmStatic
external fun rotate(bitmap: Bitmap, orientation: Int, outInfo: IntArray): Long
/**
* Converts an RGBA_1010102 [bitmap] to RGBA_8888 and returns a malloc'd buffer, or 0 on failure.
* [outInfo] receives width, height, and row bytes.
* Converts an RGBA_1010102 [bitmap] (what a 10-bit HEIC/AVIF decodes to on API 33+) to RGBA_8888,
* writing the result into a freshly malloc'd native buffer in one pass, with no intermediate
* ARGB_8888 bitmap. Returns the buffer address (free it with [NativeBuffer.free]) and fills
* [outInfo] with {width, height, rowBytes}. Returns 0 when the bitmap isn't RGBA_1010102 so the
* caller can fall back to a Skia copy.
*/
@JvmStatic
external fun convert1010102(bitmap: Bitmap, outInfo: IntArray): Long
/**
* Decodes a ThumbHash into a malloc'd RGBA_8888 buffer, or 0 on failure.
* [outInfo] receives width, height, and row bytes.
*/
@JvmStatic
external fun thumbhash(hash: ByteArray, outInfo: IntArray): Long
}

View File

@@ -13,7 +13,6 @@ import android.provider.MediaStore.Video
import android.util.Size
import androidx.annotation.RequiresApi
import androidx.exifinterface.media.ExifInterface
import app.alextran.immich.BuildConfig
import app.alextran.immich.NativeBuffer
import app.alextran.immich.NativeImage
import kotlin.math.*
@@ -50,23 +49,17 @@ fun Bitmap.toNativeBuffer(): Map<String, Long> {
// Dart reads the buffer as rgba8888, but 10-bit sources decode to RGBA_1010102, which garbles
// colors when copied verbatim. Convert those straight into the output buffer in native code -
// one pass, no intermediate ARGB_8888 bitmap.
val source1010102 =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && config == Bitmap.Config.RGBA_1010102
if (source1010102) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && config == Bitmap.Config.RGBA_1010102) {
val info = IntArray(3)
val pointer = NativeImage.convert1010102(this, info)
if (pointer != 0L) {
recycle()
return buildMap {
put("pointer", pointer)
put("width", info[0].toLong())
put("height", info[1].toLong())
put("rowBytes", info[2].toLong())
if (BuildConfig.DEBUG) {
put("source1010102", 1L)
put("converted1010102", 1L)
}
}
return mapOf(
"pointer" to pointer,
"width" to info[0].toLong(),
"height" to info[1].toLong(),
"rowBytes" to info[2].toLong()
)
}
// native convert declined (OOM/lock) -> fall through to the Skia copy path below.
}
@@ -77,16 +70,12 @@ fun Bitmap.toNativeBuffer(): Map<String, Long> {
try {
val buffer = NativeBuffer.wrap(pointer, size)
bitmap.copyPixelsToBuffer(buffer)
return buildMap {
put("pointer", pointer)
put("width", bitmap.width.toLong())
put("height", bitmap.height.toLong())
put("rowBytes", (bitmap.width * 4).toLong())
if (BuildConfig.DEBUG) {
put("source1010102", if (source1010102) 1L else 0L)
put("converted1010102", 0L)
}
}
return mapOf(
"pointer" to pointer,
"width" to bitmap.width.toLong(),
"height" to bitmap.height.toLong(),
"rowBytes" to (bitmap.width * 4).toLong()
)
} catch (e: Throwable) {
NativeBuffer.free(pointer)
throw e
@@ -112,14 +101,12 @@ class LocalImagesImpl(context: Context) : LocalImageApi {
threadPool.execute {
try {
val bytes = Base64.getDecoder().decode(thumbhash)
val info = IntArray(3)
val pointer = NativeImage.thumbhash(bytes, info)
require(pointer != 0L) { "Invalid thumbhash" }
val image = ThumbHash.thumbHashToRGBA(bytes)
val res = mapOf(
"pointer" to pointer,
"width" to info[0].toLong(),
"height" to info[1].toLong(),
"rowBytes" to info[2].toLong()
"pointer" to image.pointer,
"width" to image.width.toLong(),
"height" to image.height.toLong(),
"rowBytes" to (image.width * 4).toLong()
)
callback(Result.success(res))
} catch (e: Exception) {

View File

@@ -0,0 +1,166 @@
package app.alextran.immich.images;
// Copyright (c) 2023 Evan Wallace
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import java.nio.ByteBuffer;
import app.alextran.immich.NativeBuffer;
// modified to use native allocations
public final class ThumbHash {
/**
* Decodes a ThumbHash to an RGBA image. RGB is not be premultiplied by A.
*
* @param hash The bytes of the ThumbHash.
* @return The width, height, and pixels of the rendered placeholder image.
*/
public static Image thumbHashToRGBA(byte[] hash) {
// Read the constants
int header24 = (hash[0] & 255) | ((hash[1] & 255) << 8) | ((hash[2] & 255) << 16);
int header16 = (hash[3] & 255) | ((hash[4] & 255) << 8);
float l_dc = (float) (header24 & 63) / 63.0f;
float p_dc = (float) ((header24 >> 6) & 63) / 31.5f - 1.0f;
float q_dc = (float) ((header24 >> 12) & 63) / 31.5f - 1.0f;
float l_scale = (float) ((header24 >> 18) & 31) / 31.0f;
boolean hasAlpha = (header24 >> 23) != 0;
float p_scale = (float) ((header16 >> 3) & 63) / 63.0f;
float q_scale = (float) ((header16 >> 9) & 63) / 63.0f;
boolean isLandscape = (header16 >> 15) != 0;
int lx = Math.max(3, isLandscape ? hasAlpha ? 5 : 7 : header16 & 7);
int ly = Math.max(3, isLandscape ? header16 & 7 : hasAlpha ? 5 : 7);
float a_dc = hasAlpha ? (float) (hash[5] & 15) / 15.0f : 1.0f;
float a_scale = (float) ((hash[5] >> 4) & 15) / 15.0f;
// Read the varying factors (boost saturation by 1.25x to compensate for quantization)
int ac_start = hasAlpha ? 6 : 5;
int ac_index = 0;
Channel l_channel = new Channel(lx, ly);
Channel p_channel = new Channel(3, 3);
Channel q_channel = new Channel(3, 3);
Channel a_channel = null;
ac_index = l_channel.decode(hash, ac_start, ac_index, l_scale);
ac_index = p_channel.decode(hash, ac_start, ac_index, p_scale * 1.25f);
ac_index = q_channel.decode(hash, ac_start, ac_index, q_scale * 1.25f);
if (hasAlpha) {
a_channel = new Channel(5, 5);
a_channel.decode(hash, ac_start, ac_index, a_scale);
}
float[] l_ac = l_channel.ac;
float[] p_ac = p_channel.ac;
float[] q_ac = q_channel.ac;
float[] a_ac = hasAlpha ? a_channel.ac : null;
// Decode using the DCT into RGB
float ratio = thumbHashToApproximateAspectRatio(hash);
int w = Math.round(ratio > 1.0f ? 32.0f : 32.0f * ratio);
int h = Math.round(ratio > 1.0f ? 32.0f / ratio : 32.0f);
int size = w * h * 4;
long pointer = NativeBuffer.allocate(size);
ByteBuffer rgba = NativeBuffer.wrap(pointer, size);
int cx_stop = Math.max(lx, hasAlpha ? 5 : 3);
int cy_stop = Math.max(ly, hasAlpha ? 5 : 3);
float[] fx = new float[cx_stop];
float[] fy = new float[cy_stop];
for (int y = 0, i = 0; y < h; y++) {
for (int x = 0; x < w; x++, i += 4) {
float l = l_dc, p = p_dc, q = q_dc, a = a_dc;
// Precompute the coefficients
for (int cx = 0; cx < cx_stop; cx++)
fx[cx] = (float) Math.cos(Math.PI / w * (x + 0.5f) * cx);
for (int cy = 0; cy < cy_stop; cy++)
fy[cy] = (float) Math.cos(Math.PI / h * (y + 0.5f) * cy);
// Decode L
for (int cy = 0, j = 0; cy < ly; cy++) {
float fy2 = fy[cy] * 2.0f;
for (int cx = cy > 0 ? 0 : 1; cx * ly < lx * (ly - cy); cx++, j++)
l += l_ac[j] * fx[cx] * fy2;
}
// Decode P and Q
for (int cy = 0, j = 0; cy < 3; cy++) {
float fy2 = fy[cy] * 2.0f;
for (int cx = cy > 0 ? 0 : 1; cx < 3 - cy; cx++, j++) {
float f = fx[cx] * fy2;
p += p_ac[j] * f;
q += q_ac[j] * f;
}
}
// Decode A
if (hasAlpha)
for (int cy = 0, j = 0; cy < 5; cy++) {
float fy2 = fy[cy] * 2.0f;
for (int cx = cy > 0 ? 0 : 1; cx < 5 - cy; cx++, j++)
a += a_ac[j] * fx[cx] * fy2;
}
// Convert to RGB
float b = l - 2.0f / 3.0f * p;
float r = (3.0f * l - b + q) / 2.0f;
float g = r - q;
rgba.put(i, (byte) Math.max(0, Math.round(255.0f * Math.min(1, r))));
rgba.put(i + 1, (byte) Math.max(0, Math.round(255.0f * Math.min(1, g))));
rgba.put(i + 2, (byte) Math.max(0, Math.round(255.0f * Math.min(1, b))));
rgba.put(i + 3, (byte) Math.max(0, Math.round(255.0f * Math.min(1, a))));
}
}
return new Image(w, h, pointer);
}
/**
* Extracts the approximate aspect ratio of the original image.
*
* @param hash The bytes of the ThumbHash.
* @return The approximate aspect ratio (i.e. width / height).
*/
public static float thumbHashToApproximateAspectRatio(byte[] hash) {
byte header = hash[3];
boolean hasAlpha = (hash[2] & 0x80) != 0;
boolean isLandscape = (hash[4] & 0x80) != 0;
int lx = isLandscape ? hasAlpha ? 5 : 7 : header & 7;
int ly = isLandscape ? header & 7 : hasAlpha ? 5 : 7;
return (float) lx / (float) ly;
}
public static final class Image {
public int width;
public int height;
public long pointer;
public Image(int width, int height, long pointer) {
this.width = width;
this.height = height;
this.pointer = pointer;
}
}
private static final class Channel {
int nx;
int ny;
float[] ac;
Channel(int nx, int ny) {
this.nx = nx;
this.ny = ny;
int n = 0;
for (int cy = 0; cy < ny; cy++)
for (int cx = cy > 0 ? 0 : 1; cx * ny < nx * (ny - cy); cx++)
n++;
ac = new float[n];
}
int decode(byte[] hash, int start, int index, float scale) {
for (int i = 0; i < ac.length; i++) {
int data = hash[start + (index >> 1)] >> ((index & 1) << 2);
ac[i] = ((float) (data & 15) / 7.5f - 1.0f) * scale;
index++;
}
return index;
}
}
}

View File

@@ -46,7 +46,7 @@ void main() {
void sendUser(SyncStream stream, String id, String name) {
stream.send(
type: SyncEntityType.userV1.value,
type: SyncEntityType.userV1.toString(),
data: SyncUserV1(
id: id,
name: name,

View File

@@ -1,97 +0,0 @@
import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_native_core/immich_native_core.dart';
import 'package:integration_test/integration_test.dart';
Uint8List _px1010102(int r, int g, int b, int a) {
final px = (r & 0x3FF) | ((g & 0x3FF) << 10) | ((b & 0x3FF) << 20) | ((a & 0x3) << 30);
return Uint8List(4)..buffer.asByteData().setUint32(0, px, Endian.little);
}
Uint8List? _withBuffers(
Uint8List src,
int dstLen,
bool Function(Pointer<Uint8> src, int dstLen, Pointer<Uint8> dst) call,
) {
final srcPtr = calloc<Uint8>(src.length);
final dstPtr = calloc<Uint8>(dstLen);
try {
srcPtr.asTypedList(src.length).setAll(0, src);
if (!call(srcPtr, dstLen, dstPtr)) {
return null;
}
return Uint8List.fromList(dstPtr.asTypedList(dstLen));
} finally {
calloc.free(srcPtr);
calloc.free(dstPtr);
}
}
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
test('loads the native core', () {
final ptr = immich_core_version();
expect(ptr, isNot(equals(nullptr)));
final version = ptr.cast<Utf8>().toDartString();
immich_core_free_string(ptr);
expect(version, isNotEmpty);
});
test('reports swapped orientations', () {
for (final o in [5, 6, 7, 8]) {
expect(immich_core_orientation_swaps_dims(o), isTrue, reason: 'o=$o');
}
for (final o in [0, 1, 2, 3, 4, 9]) {
expect(immich_core_orientation_swaps_dims(o), isFalse, reason: 'o=$o');
}
});
test('rotates RGBA pixels', () {
final src = Uint8List.fromList([255, 0, 0, 255, 0, 255, 0, 255]);
final out = _withBuffers(src, 8, (s, len, d) => immich_core_rotate_rgba8888(s, src.length, 8, 2, 1, 3, d, len));
expect(out, [0, 255, 0, 255, 255, 0, 0, 255]);
});
test('converts RGBA_1010102 pixels', () {
// 179 and 111 distinguish rounded scaling from `>> 2`.
final src = Uint8List.fromList([..._px1010102(1023, 0, 0, 3), ..._px1010102(179, 111, 0, 3)]);
final out = _withBuffers(
src,
8,
(s, len, d) => immich_core_rgba1010102_to_rgba8888(s, src.length, 8, 2, 1, d, len),
);
expect(out, isNotNull);
expect(out!.sublist(0, 4), [255, 0, 0, 255]);
expect(out.sublist(4, 8), [45, 28, 0, 255]);
});
test('decodes a thumbhash', () {
final hash = base64Decode('1QcSHQRnh493V4dIh4eXh1h4kJUI');
final hashPtr = malloc<Uint8>(hash.length);
final info = malloc<Uint32>(3);
try {
hashPtr.asTypedList(hash.length).setAll(0, hash);
final ptr = immich_core_thumbhash_decode(hashPtr, hash.length, info);
expect(ptr, isNot(equals(nullptr)));
expect((info[0], info[1], info[2]), (23, 32, 23 * 4));
final len = info[0] * info[1] * 4;
final pixels = ptr.asTypedList(len);
for (var i = 3; i < len; i += 4) {
expect(pixels[i], 255, reason: 'alpha at $i');
}
expect(pixels.toSet().length, greaterThan(2));
malloc.free(ptr);
expect(immich_core_thumbhash_decode(hashPtr, 4, info), equals(nullptr));
} finally {
malloc.free(hashPtr);
malloc.free(info);
}
});
}

View File

@@ -1,194 +0,0 @@
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/platform/local_image_api.g.dart';
import 'package:integration_test/integration_test.dart';
import 'package:photo_manager/photo_manager.dart';
const _fixture10BitAvifB64 =
'AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAAD5bWV0YQAAAAAAAAAvaGRscgAAAAAA'
'AAAAcGljdAAAAAAAAAAAAAAAAFBpY3R1cmVIYW5kbGVyAAAAAA5waXRtAAAAAAABAAAAHmlsb2MA'
'AAAARAAAAQABAAAAAQAAASEAAAAmAAAAKGlpbmYAAAAAAAEAAAAaaW5mZQIAAAAAAQAAYXYwMUNv'
'bG9yAAAAAGppcHJwAAAAS2lwY28AAAAUaXNwZQAAAAAAAABAAAAAQAAAABBwaXhpAAAAAAMKCgoA'
'AAAMYXYxQ4EATAAAAAATY29scm5jbHgAAQACAAEAAAAAF2lwbWEAAAAAAAAAAQABBAECgwQAAAAu'
'bWRhdAoNAAAAAq//jV86AgQCCDIVEACLggAAAAAAgAAifC/LKY1kV6Bd';
// 16x12 linear DNG with EXIF orientation 6; the pixel strip is appended below.
const _fixtureOrientedDngHeaderB64 =
'SUkqAAgAAAAVAAABAwABAAAAEAAAAAEBAwABAAAADAAAAAIBAwADAAAACgEAAAMBAwABAAAAAQAAAAYBAwABAAAATIgAAAoB'
'AwABAAAAAQAAABEBBAABAAAAvAEAABIBAwABAAAABgAAABUBAwABAAAAAwAAABYBAwABAAAADAAAABcBBAABAAAAgAQAABwB'
'AwABAAAAAQAAACkBAwACAAAAAAABAD4BBQACAAAAEAEAAD8BBQAGAAAAIAEAABLGAQAEAAAAAQQAABPGAQAEAAAAAQEAABTG'
'AgAMAAAAUAEAACHGCgAJAAAAXAEAACjGBQADAAAApAEAAFrGAwABAAAAFQAAAAAAAAAQABAAEAA3GqAAAAAAAiuHCgAAACAA'
'hetRAAAAgADD9agAAAAAAs3MTAAAAAABzcxMAAAAgADNzEwAAAAAAo/C9QAAAAAQSW1taWNoIFRlc3QAAQAAAAEAAAAAAAAA'
'AQAAAAAAAAABAAAAAAAAAAEAAAABAAAAAQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAA'
'AQAAAAEAAAABAAAA';
Uint8List _orientedDng() {
final header = base64Decode(_fixtureOrientedDngHeaderB64);
final pixels = ByteData(16 * 12 * 6);
for (var y = 0; y < 12; y++) {
final r = (11 - y) * 65535 ~/ 11;
final b = y * 65535 ~/ 11;
for (var x = 0; x < 16; x++) {
final offset = (y * 16 + x) * 6;
pixels.setUint16(offset, r, Endian.little);
pixels.setUint16(offset + 2, 0, Endian.little);
pixels.setUint16(offset + 4, b, Endian.little);
}
}
return Uint8List(header.length + pixels.lengthInBytes)
..setAll(0, header)
..setAll(header.length, pixels.buffer.asUint8List());
}
Uint8List _read(int address, int length) => Uint8List.fromList(Pointer<Uint8>.fromAddress(address).asTypedList(length));
void _free(int address) => malloc.free(Pointer<Uint8>.fromAddress(address));
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
if (!Platform.isAndroid) {
return;
}
final api = LocalImageApi();
final fixture = base64Decode(_fixture10BitAvifB64);
String? assetId;
String? orientedAssetId;
setUpAll(() async {
await PhotoManager.setIgnorePermissionCheck(true);
final entity = await PhotoManager.editor.saveImage(fixture, filename: 'immich_jni_fixture.avif');
assetId = entity.id;
});
tearDownAll(() async {
final ids = [assetId, orientedAssetId].whereType<String>().toList();
if (ids.isNotEmpty) {
try {
await PhotoManager.editor.deleteWithIds(ids);
} catch (_) {}
}
});
test('thumbhash JNI roundtrip', () async {
final a = await api.getThumbhash('1QcSHQRnh493V4dIh4eXh1h4kJUI');
final b = await api.getThumbhash('1QcSHQRnh493V4dIh4eXh1h4kJUI');
final (w, h, rowBytes) = (a['width']!, a['height']!, a['rowBytes']!);
expect(a['pointer'], isNot(0));
expect(w, inInclusiveRange(1, 128));
expect(h, inInclusiveRange(1, 128));
expect(rowBytes, w * 4);
final pixelsA = _read(a['pointer']!, rowBytes * h);
final pixelsB = _read(b['pointer']!, rowBytes * h);
_free(a['pointer']!);
_free(b['pointer']!);
expect(pixelsA, pixelsB);
expect(pixelsA.toSet().length, greaterThan(1));
});
test('encoded image buffer roundtrip', () async {
final res = await api.requestImage(
assetId!,
requestId: 900001,
width: 0,
height: 0,
isVideo: false,
preferEncoded: true,
);
expect(res, isNotNull);
expect(res!['length'], fixture.length);
final bytes = _read(res['pointer']!, res['length']!);
_free(res['pointer']!);
expect(bytes, fixture);
});
test('10-bit decode runs NativeImage.convert1010102', () async {
final Map<String, int>? res;
try {
res = await api.requestImage(
assetId!,
requestId: 900002,
width: 0,
height: 0,
isVideo: false,
preferEncoded: false,
);
} on PlatformException catch (e) {
markTestSkipped('device cannot decode the 10-bit AVIF fixture: ${e.message}');
return;
}
expect(res, isNotNull);
final (w, h, rowBytes) = (res!['width']!, res['height']!, res['rowBytes']!);
expect(w, 64);
expect(h, 64);
expect(rowBytes, w * 4);
final pixels = _read(res['pointer']!, rowBytes * h);
_free(res['pointer']!);
final source1010102 = res['source1010102'];
expect(source1010102, isNotNull, reason: 'decode result did not report its source format');
if (source1010102 == 0) {
markTestSkipped('device decoded the 10-bit AVIF fixture without RGBA_1010102');
return;
}
expect(source1010102, 1);
expect(
res['converted1010102'],
1,
reason: 'RGBA_1010102 source fell back instead of running the native conversion',
);
for (final (x, y) in [(2, 2), (32, 32), (61, 61)]) {
final o = (y * w + x) * 4;
expect(pixels[o], closeTo(45, 12), reason: 'R at ($x,$y)');
expect(pixels[o + 1], closeTo(139, 12), reason: 'G at ($x,$y)');
expect(pixels[o + 2], closeTo(107, 12), reason: 'B at ($x,$y)');
expect(pixels[o + 3], 255, reason: 'A at ($x,$y)');
}
});
test('raw EXIF orientation rotates through NativeImage.rotate', () async {
final sdkInt = (await DeviceInfoPlugin().androidInfo).version.sdkInt;
if (sdkInt < 29) {
markTestSkipped('raw image rotation needs Android 10 or newer');
return;
}
final entity = await PhotoManager.editor.saveImage(_orientedDng(), filename: 'immich_jni_orientation.dng');
orientedAssetId = entity.id;
expect(await entity.mimeTypeAsync, anyOf('image/dng', 'image/x-adobe-dng'));
expect(entity.orientation, 90);
expect((entity.width, entity.height), (16, 12));
final Map<String, int>? res;
try {
res = await api.requestImage(
entity.id,
requestId: 900003,
width: 0,
height: 0,
isVideo: false,
preferEncoded: false,
);
} on PlatformException catch (e) {
markTestSkipped('device cannot decode the DNG fixture: ${e.message}');
return;
}
expect(res, isNotNull);
final (w, h, rowBytes) = (res!['width']!, res['height']!, res['rowBytes']!);
expect((w, h, rowBytes), (12, 16, 48));
final pixels = _read(res['pointer']!, rowBytes * h);
_free(res['pointer']!);
for (final (x, r, b) in [(0, 0, 255), (11, 255, 0)]) {
final o = 8 * rowBytes + x * 4;
expect(pixels[o], closeTo(r, 12), reason: 'R at ($x,8)');
expect(pixels[o + 2], closeTo(b, 12), reason: 'B at ($x,8)');
}
});
}

View File

@@ -36,6 +36,7 @@
FE5499F62F11980E006016CB /* LocalImagesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE5499F52F11980E006016CB /* LocalImagesImpl.swift */; };
FE5499F82F1198E2006016CB /* RemoteImagesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE5499F72F1198DE006016CB /* RemoteImagesImpl.swift */; };
FE5FE4AE2F30FBC000A71243 /* ImageProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE5FE4AD2F30FBC000A71243 /* ImageProcessing.swift */; };
FEAFA8732E4D42F4001E47FE /* Thumbhash.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEAFA8722E4D42F4001E47FE /* Thumbhash.swift */; };
FEE084F82EC172460045228E /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = FEE084F72EC172460045228E /* SQLiteData */; };
FEE084FB2EC1725A0045228E /* RawStructuredFieldValues in Frameworks */ = {isa = PBXBuildFile; productRef = FEE084FA2EC1725A0045228E /* RawStructuredFieldValues */; };
FEE084FD2EC1725A0045228E /* StructuredFieldValues in Frameworks */ = {isa = PBXBuildFile; productRef = FEE084FC2EC1725A0045228E /* StructuredFieldValues */; };
@@ -130,6 +131,7 @@
FE5499F52F11980E006016CB /* LocalImagesImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalImagesImpl.swift; sourceTree = "<group>"; };
FE5499F72F1198DE006016CB /* RemoteImagesImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteImagesImpl.swift; sourceTree = "<group>"; };
FE5FE4AD2F30FBC000A71243 /* ImageProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProcessing.swift; sourceTree = "<group>"; };
FEAFA8722E4D42F4001E47FE /* Thumbhash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Thumbhash.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
@@ -355,6 +357,7 @@
FE5499F52F11980E006016CB /* LocalImagesImpl.swift */,
FE5499F12F1197D8006016CB /* LocalImages.g.swift */,
FE5499F22F1197D8006016CB /* RemoteImages.g.swift */,
FEAFA8722E4D42F4001E47FE /* Thumbhash.swift */,
);
path = Images;
sourceTree = "<group>";
@@ -583,7 +586,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
shellScript = "/bin/bash \"$SRCROOT/scripts/xcode_flutter_build.sh\"\n";
};
BAEA01ACA3F5C9CD3D732370 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
@@ -625,6 +628,7 @@
B2EE00022E72CA15008B6CA7 /* PermissionApi.g.swift in Sources */,
B2EE00042E72CA15008B6CA7 /* PermissionApiImpl.swift in Sources */,
FE5499F82F1198E2006016CB /* RemoteImagesImpl.swift in Sources */,
FEAFA8732E4D42F4001E47FE /* Thumbhash.swift in Sources */,
B25D377C2E72CA26008B6CA7 /* ConnectivityApiImpl.swift in Sources */,
B21E34AA2E5AFD2B0031FDB9 /* BackgroundWorkerApiImpl.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,

View File

@@ -1,57 +0,0 @@
import Foundation
import OSLog
// Native assets embed the framework without linking Runner, so resolve its symbol at runtime.
enum NativeCore {
typealias ThumbhashDecode = @convention(c) (
UnsafePointer<UInt8>?, UInt, UnsafeMutablePointer<UInt32>?
) -> UnsafeMutablePointer<UInt8>?
static let thumbhashDecode: ThumbhashDecode? = symbol("immich_core_thumbhash_decode")
private static let logger = Logger(
subsystem: Bundle.main.bundleIdentifier ?? "app.alextran.immich",
category: "NativeCore"
)
private static let handle: UnsafeMutableRawPointer? = load()
private static func load() -> UnsafeMutableRawPointer? {
if let frameworks = Bundle.main.privateFrameworksPath {
let path = "\(frameworks)/immich_core_ffi.framework/immich_core_ffi"
dlerror()
if let handle = dlopen(path, RTLD_NOW) {
return handle
}
let error = lastError()
logger.warning("dlopen failed for \(path, privacy: .public): \(error, privacy: .public)")
}
dlerror()
guard let handle = dlopen(nil, RTLD_NOW) else {
let error = lastError()
logger.error("dlopen failed for process scope: \(error, privacy: .public)")
return nil
}
return handle
}
private static func symbol<T>(_ name: String) -> T? {
guard let handle else {
logger.error("native core is unavailable while loading \(name, privacy: .public)")
return nil
}
dlerror()
guard let sym = dlsym(handle, name) else {
let error = lastError()
logger.error("dlsym failed for \(name, privacy: .public): \(error, privacy: .public)")
return nil
}
return unsafeBitCast(sym, to: T.self)
}
private static func lastError() -> String {
guard let error = dlerror() else { return "unknown error" }
return String(cString: error)
}
}

View File

@@ -38,26 +38,15 @@ class LocalImageApiImpl: LocalImageApi {
func getThumbhash(thumbhash: String, completion: @escaping (Result<[String : Int64], any Error>) -> Void) {
ImageProcessing.queue.addOperation {
guard let data = Data(base64Encoded: thumbhash) else {
return completion(.failure(PigeonError(code: "invalid-base64", message: "Invalid base64 thumbhash", details: nil)))
}
guard let decode = NativeCore.thumbhashDecode else {
return completion(.failure(PigeonError(code: "native-core-unavailable", message: "Native thumbhash decoder is unavailable", details: nil)))
}
var info = [UInt32](repeating: 0, count: 3)
let pointer = data.withUnsafeBytes { bytes in
decode(bytes.bindMemory(to: UInt8.self).baseAddress, UInt(bytes.count), &info)
}
guard let pointer else {
return completion(.failure(PigeonError(code: "invalid-thumbhash", message: "Invalid thumbhash", details: nil)))
}
guard let data = Data(base64Encoded: thumbhash)
else { return completion(.failure(PigeonError(code: "", message: "Invalid base64 string: \(thumbhash)", details: nil)))}
let (width, height, pointer) = thumbHashToRGBA(hash: data)
completion(.success([
"pointer": Int64(Int(bitPattern: pointer)),
"width": Int64(info[0]),
"height": Int64(info[1]),
"rowBytes": Int64(info[2])
"pointer": Int64(Int(bitPattern: pointer.baseAddress)),
"width": Int64(width),
"height": Int64(height),
"rowBytes": Int64(width * 4)
]))
}
}

View File

@@ -0,0 +1,225 @@
// Copyright (c) 2023 Evan Wallace
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import Foundation
// NOTE: Swift has an exponential-time type checker and compiling very simple
// expressions can easily take many seconds, especially when expressions involve
// numeric type constructors.
//
// This file deliberately breaks compound expressions up into separate variables
// to improve compile time even though this comes at the expense of readability.
// This is a known workaround for this deficiency in the Swift compiler.
//
// The following command is helpful when debugging Swift compile time issues:
//
// swiftc ThumbHash.swift -Xfrontend -debug-time-function-bodies
//
// These optimizations brought the compile time for this file from around 2.5
// seconds to around 250ms (10x faster).
// NOTE: Swift's debug-build performance of for-in loops over numeric ranges is
// really awful. Debug builds compile a very generic indexing iterator thing
// that makes many nested calls for every iteration, which makes debug-build
// performance crawl.
//
// This file deliberately avoids for-in loops that loop for more than a few
// times to improve debug-build run time even though this comes at the expense
// of readability. Similarly unsafe pointers are used instead of array getters
// to avoid unnecessary bounds checks, which have extra overhead in debug builds.
//
// These optimizations brought the run time to encode and decode 10 ThumbHashes
// in debug mode from 700ms to 70ms (10x faster).
// changed signature and allocation method to avoid automatic GC
func thumbHashToRGBA(hash: Data) -> (Int, Int, UnsafeMutableRawBufferPointer) {
// Read the constants
let h0 = UInt32(hash[0])
let h1 = UInt32(hash[1])
let h2 = UInt32(hash[2])
let h3 = UInt16(hash[3])
let h4 = UInt16(hash[4])
let header24 = h0 | (h1 << 8) | (h2 << 16)
let header16 = h3 | (h4 << 8)
let il_dc = header24 & 63
let ip_dc = (header24 >> 6) & 63
let iq_dc = (header24 >> 12) & 63
var l_dc = Float32(il_dc)
var p_dc = Float32(ip_dc)
var q_dc = Float32(iq_dc)
l_dc = l_dc / 63
p_dc = p_dc / 31.5 - 1
q_dc = q_dc / 31.5 - 1
let il_scale = (header24 >> 18) & 31
var l_scale = Float32(il_scale)
l_scale = l_scale / 31
let hasAlpha = (header24 >> 23) != 0
let ip_scale = (header16 >> 3) & 63
let iq_scale = (header16 >> 9) & 63
var p_scale = Float32(ip_scale)
var q_scale = Float32(iq_scale)
p_scale = p_scale / 63
q_scale = q_scale / 63
let isLandscape = (header16 >> 15) != 0
let lx16 = max(3, isLandscape ? hasAlpha ? 5 : 7 : header16 & 7)
let ly16 = max(3, isLandscape ? header16 & 7 : hasAlpha ? 5 : 7)
let lx = Int(lx16)
let ly = Int(ly16)
var a_dc = Float32(1)
var a_scale = Float32(1)
if hasAlpha {
let ia_dc = hash[5] & 15
let ia_scale = hash[5] >> 4
a_dc = Float32(ia_dc)
a_scale = Float32(ia_scale)
a_dc /= 15
a_scale /= 15
}
// Read the varying factors (boost saturation by 1.25x to compensate for quantization)
let ac_start = hasAlpha ? 6 : 5
var ac_index = 0
let decodeChannel = { (nx: Int, ny: Int, scale: Float32) -> [Float32] in
var ac: [Float32] = []
for cy in 0 ..< ny {
var cx = cy > 0 ? 0 : 1
while cx * ny < nx * (ny - cy) {
let iac = (hash[ac_start + (ac_index >> 1)] >> ((ac_index & 1) << 2)) & 15;
var fac = Float32(iac)
fac = (fac / 7.5 - 1) * scale
ac.append(fac)
ac_index += 1
cx += 1
}
}
return ac
}
let l_ac = decodeChannel(lx, ly, l_scale)
let p_ac = decodeChannel(3, 3, p_scale * 1.25)
let q_ac = decodeChannel(3, 3, q_scale * 1.25)
let a_ac = hasAlpha ? decodeChannel(5, 5, a_scale) : []
// Decode using the DCT into RGB
let ratio = thumbHashToApproximateAspectRatio(hash: hash)
let fw = round(ratio > 1 ? 32 : 32 * ratio)
let fh = round(ratio > 1 ? 32 / ratio : 32)
let w = Int(fw)
let h = Int(fh)
let pointer = UnsafeMutableRawBufferPointer.allocate(
byteCount: w * h * 4,
alignment: MemoryLayout<UInt8>.alignment
)
var rgba = pointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
let cx_stop = max(lx, hasAlpha ? 5 : 3)
let cy_stop = max(ly, hasAlpha ? 5 : 3)
var fx = [Float32](repeating: 0, count: cx_stop)
var fy = [Float32](repeating: 0, count: cy_stop)
fx.withUnsafeMutableBytes { fx in
let fx = fx.baseAddress!.bindMemory(to: Float32.self, capacity: fx.count)
fy.withUnsafeMutableBytes { fy in
let fy = fy.baseAddress!.bindMemory(to: Float32.self, capacity: fy.count)
var y = 0
while y < h {
var x = 0
while x < w {
var l = l_dc
var p = p_dc
var q = q_dc
var a = a_dc
// Precompute the coefficients
var cx = 0
while cx < cx_stop {
let fw = Float32(w)
let fxx = Float32(x)
let fcx = Float32(cx)
fx[cx] = cos(Float32.pi / fw * (fxx + 0.5) * fcx)
cx += 1
}
var cy = 0
while cy < cy_stop {
let fh = Float32(h)
let fyy = Float32(y)
let fcy = Float32(cy)
fy[cy] = cos(Float32.pi / fh * (fyy + 0.5) * fcy)
cy += 1
}
// Decode L
var j = 0
cy = 0
while cy < ly {
var cx = cy > 0 ? 0 : 1
let fy2 = fy[cy] * 2
while cx * ly < lx * (ly - cy) {
l += l_ac[j] * fx[cx] * fy2
j += 1
cx += 1
}
cy += 1
}
// Decode P and Q
j = 0
cy = 0
while cy < 3 {
var cx = cy > 0 ? 0 : 1
let fy2 = fy[cy] * 2
while cx < 3 - cy {
let f = fx[cx] * fy2
p += p_ac[j] * f
q += q_ac[j] * f
j += 1
cx += 1
}
cy += 1
}
// Decode A
if hasAlpha {
j = 0
cy = 0
while cy < 5 {
var cx = cy > 0 ? 0 : 1
let fy2 = fy[cy] * 2
while cx < 5 - cy {
a += a_ac[j] * fx[cx] * fy2
j += 1
cx += 1
}
cy += 1
}
}
// Convert to RGB
var b = l - 2 / 3 * p
var r = (3 * l - b + q) / 2
var g = r - q
r = max(0, 255 * min(1, r))
g = max(0, 255 * min(1, g))
b = max(0, 255 * min(1, b))
a = max(0, 255 * min(1, a))
rgba[0] = UInt8(r)
rgba[1] = UInt8(g)
rgba[2] = UInt8(b)
rgba[3] = UInt8(a)
rgba = rgba.advanced(by: 4)
x += 1
}
y += 1
}
}
}
return (w, h, pointer)
}
func thumbHashToApproximateAspectRatio(hash: Data) -> Float32 {
let header = hash[3]
let hasAlpha = (hash[2] & 0x80) != 0
let isLandscape = (hash[4] & 0x80) != 0
let lx = isLandscape ? hasAlpha ? 5 : 7 : header & 7
let ly = isLandscape ? header & 7 : hasAlpha ? 5 : 7
return Float32(lx) / Float32(ly)
}

View File

@@ -34,13 +34,6 @@ platform :ios do
)
end
# Xcode build phases need mise trust saved to disk.
def trust_mise_configs
return unless system("command -v mise > /dev/null 2>&1")
sh("mise trust ../../../mise.toml")
sh("mise trust ../../mise.toml")
end
# Helper method to assemble xcargs with optional CUSTOM_GROUP_ID override
def build_xcargs(group_id: nil)
args = "-skipMacroValidation CODE_SIGN_IDENTITY='#{CODE_SIGN_IDENTITY}' CODE_SIGN_STYLE=Manual"
@@ -109,8 +102,6 @@ end
)
app_identifier = base_bundle_id
trust_mise_configs
# Set version number if provided
if version_number
increment_version_number(version_number: version_number)
@@ -267,8 +258,6 @@ end
api_key = get_api_key
trust_mise_configs
# Download and install provisioning profiles from App Store Connect
# Certificate is imported by GHA workflow into build.keychain
sigh(api_key: api_key, app_identifier: DEV_BUNDLE_ID, force: true)
@@ -295,7 +284,6 @@ end
configuration: "Release",
export_method: "app-store",
skip_package_ipa: true,
xcodebuild_formatter: "", # raw xcodebuild output so script-phase errors show in CI logs
xcargs: build_xcargs(group_id: DEV_GROUP_ID),
export_options: {
provisioningProfiles: {

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
# Makes Flutter's builds through the Xcode GUI properly display errors and warnings
# in the Issue navigator
#
# Flutter's `xcode_backend.dart` runs `flutter assemble` with `allowFail: true`,
# which intentionally does not prefix output with `error:`. Unsure why they do this,
# but this script rebuilds the expected output so Xcode can parse and display the errors
set -o pipefail
# The Immich mobile root (containing the Dart `lib` directory). This is used to make
# absolute paths for Xcode linking
app_root="${FLUTTER_APPLICATION_PATH:-$SRCROOT/..}"
/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build 2>&1 \
| awk -v app_root="$app_root" '
# Match Dart CFE diagnostics: <path>.dart:<line>:<col>: <Kind>: <message>
# Written for macOS/POSIX/BSD awk
{
# Always pass the original line through to preserve the original build log
print
if ($0 ~ /^.*\.dart:[0-9]+:[0-9]+: (Error|Warning|Context|Info):/) {
# Locate the ": Kind:" separator to split location from message.
rest = $0
if (match(rest, /: Error:/)) { kind = "Error"; keyword = "error" }
else if (match(rest, /: Warning:/)) { kind = "Warning"; keyword = "warning" }
else if (match(rest, /: Context:/)) { kind = "Context"; keyword = "note" }
else if (match(rest, /: Info:/)) { kind = "Info"; keyword = "note" }
# location = everything before ": Kind:" (e.g. "lib/foo.dart:12:5")
location = substr(rest, 1, RSTART - 1)
# message = everything after ": Kind:" (leading space preserved)
message = substr(rest, RSTART + length(": " kind ":"))
# Make the path absolute so Xcode links to it
if (location !~ /^\//)
location = app_root "/" location
printf "%s: %s:%s\n", location, keyword, message
}
}
'
exit "${PIPESTATUS[0]}"

View File

@@ -6,7 +6,10 @@ import 'package:background_downloader/background_downloader.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/constants.dart';
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/log.service.dart';
import 'package:immich_mobile/domain/services/sync_stream.service.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/extensions/platform_extensions.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
@@ -14,11 +17,16 @@ import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.d
import 'package:immich_mobile/infrastructure/repositories/settings.repository.dart';
import 'package:immich_mobile/platform/background_worker_api.g.dart';
import 'package:immich_mobile/platform/background_worker_lock_api.g.dart';
import 'package:immich_mobile/providers/background_sync.provider.dart';
import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart' show nativeSyncApiProvider;
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
import 'package:immich_mobile/providers/infrastructure/sync.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/repositories/asset_media.repository.dart';
import 'package:immich_mobile/repositories/permission.repository.dart';
import 'package:immich_mobile/services/auth.service.dart';
import 'package:immich_mobile/services/foreground_upload.service.dart';
import 'package:immich_mobile/services/localization.service.dart';
@@ -58,12 +66,43 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
final BackgroundWorkerBgHostApi _backgroundHostApi;
final _cancellationToken = Completer<void>();
final Logger _logger = Logger('BackgroundWorkerBgService');
late LocalSyncService _localSyncService;
late SyncStreamService _remoteSyncService;
late HashService _hashService;
bool _isCleanedUp = false;
BackgroundWorkerBgService({required this._drift, required this._driftLogger})
: _backgroundHostApi = BackgroundWorkerBgHostApi() {
_ref = ProviderContainer(overrides: [driftProvider.overrideWith(driftOverride(_drift))]);
final ref = ProviderContainer(overrides: [driftProvider.overrideWith(driftOverride(_drift))]);
_ref = ref;
_localSyncService = LocalSyncService(
localAlbumRepository: ref.read(localAlbumRepository),
localAssetRepository: ref.read(localAssetRepository),
nativeSyncApi: ref.read(nativeSyncApiProvider),
trashedLocalAssetRepository: ref.read(trashedLocalAssetRepository),
assetMediaRepository: ref.read(assetMediaRepositoryProvider),
permissionRepository: ref.read(permissionRepositoryProvider),
cancellation: _cancellationToken,
);
_remoteSyncService = SyncStreamService(
syncApiRepository: ref.read(syncApiRepositoryProvider),
syncStreamRepository: ref.read(syncStreamRepositoryProvider),
localAssetRepository: ref.read(localAssetRepository),
trashedLocalAssetRepository: ref.read(trashedLocalAssetRepository),
assetMediaRepository: ref.read(assetMediaRepositoryProvider),
permissionRepository: ref.read(permissionRepositoryProvider),
syncMigrationRepository: ref.read(syncMigrationRepositoryProvider),
api: ref.read(apiServiceProvider),
cancellation: _cancellationToken,
);
_hashService = HashService(
localAlbumRepository: ref.read(localAlbumRepository),
localAssetRepository: ref.read(localAssetRepository),
nativeSyncApi: ref.read(nativeSyncApiProvider),
trashedLocalAssetRepository: ref.read(trashedLocalAssetRepository),
cancellation: _cancellationToken,
);
BackgroundWorkerFlutterApi.setUp(this);
}
@@ -119,11 +158,6 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
try {
final budget = maxSeconds != null ? Duration(seconds: maxSeconds - 1) : null;
final sync = _ref?.read(backgroundSyncProvider);
if (sync == null) {
return;
}
// Only for Background Processing tasks
if (maxSeconds == null) {
await _optimizeDB();
@@ -135,9 +169,23 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
// hash and handle_backup read drift state and tolerate stale reads
// (server-side dedup catches the rare race). The single budget caps the
// whole batch; no phase needs its own timeout.
final all = Future.wait<dynamic>([sync.syncLocal(), sync.syncRemote(), sync.hashAssets(), _handleBackup()]);
final all = Future.wait<dynamic>([
_localSyncService.sync(),
_remoteSyncService.sync(),
_hashService.hashAssets(),
_handleBackup(),
]);
if (budget != null) {
await all.timeout(budget, onTimeout: () => <dynamic>[]);
await all.timeout(
budget,
onTimeout: () {
if (!_cancellationToken.isCompleted) {
_logger.warning("iOS background upload timed out after ${budget.inSeconds}s, cancelling tasks");
_cancellationToken.complete();
}
return <dynamic>[];
},
);
} else {
await all;
}
@@ -221,7 +269,6 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
try {
_isCleanedUp = true;
final backgroundSyncManager = _ref?.read(backgroundSyncProvider);
final nativeSyncApi = _ref?.read(nativeSyncApiProvider);
_logger.info("Cleaning up background worker");
@@ -230,10 +277,7 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
}
// Workers share one sqlite connection, so DB teardown must wait until every worker has stopped using it.
await Future.wait([
if (backgroundSyncManager != null) backgroundSyncManager.cancel(),
if (nativeSyncApi != null) nativeSyncApi.cancelHashing(),
]);
await Future.wait([if (nativeSyncApi != null) nativeSyncApi.cancelHashing()]);
await workerManagerPatch.dispose().catchError((_) async {});
await Future.wait([LogService.I.dispose(), Store.dispose()]);
await _drift.close();
@@ -279,18 +323,18 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
}
Future<bool> _syncAssets({Duration? hashTimeout}) async {
await _ref?.read(backgroundSyncProvider).syncLocal();
await _localSyncService.sync();
if (_isCleanedUp) {
return false;
}
final isSuccess = await _ref?.read(backgroundSyncProvider).syncRemote() ?? false;
final isSuccess = await _remoteSyncService.sync();
if (_isCleanedUp) {
return isSuccess;
}
var hashFuture = _ref?.read(backgroundSyncProvider).hashAssets();
if (hashTimeout != null && hashFuture != null) {
var hashFuture = _hashService.hashAssets();
if (hashTimeout != null) {
hashFuture = hashFuture.timeout(
hashTimeout,
onTimeout: () {

View File

@@ -328,8 +328,6 @@ class SyncStreamService {
return _syncStreamRepository.updateAssetOcrV1(data.cast());
case SyncEntityType.assetOcrDeleteV1:
return _syncStreamRepository.deleteAssetOcrV1(data.cast());
default:
_logger.warning("Unknown sync data type: $type");
}
}

View File

@@ -58,7 +58,6 @@ extension on api.AssetVisibility {
api.AssetVisibility.hidden => AssetVisibility.hidden,
api.AssetVisibility.archive => AssetVisibility.archive,
api.AssetVisibility.locked => AssetVisibility.locked,
_ => AssetVisibility.timeline,
};
}
@@ -68,6 +67,5 @@ extension on api.AssetTypeEnum {
api.AssetTypeEnum.VIDEO => AssetType.video,
api.AssetTypeEnum.AUDIO => AssetType.audio,
api.AssetTypeEnum.OTHER => AssetType.other,
_ => throw Exception('Unknown AssetType value: $this'),
};
}

View File

@@ -937,7 +937,6 @@ extension on AssetTypeEnum {
AssetTypeEnum.VIDEO => AssetType.video,
AssetTypeEnum.AUDIO => AssetType.audio,
AssetTypeEnum.OTHER => AssetType.other,
_ => throw Exception('Unknown AssetType value: $this'),
};
}
@@ -945,14 +944,12 @@ extension on AssetOrder {
AlbumAssetOrder toAlbumAssetOrder() => switch (this) {
AssetOrder.asc => AlbumAssetOrder.asc,
AssetOrder.desc => AlbumAssetOrder.desc,
_ => throw Exception('Unknown AssetOrder value: $this'),
};
}
extension on MemoryType {
MemoryTypeEnum toMemoryType() => switch (this) {
MemoryType.onThisDay => MemoryTypeEnum.onThisDay,
_ => throw Exception('Unknown MemoryType value: $this'),
};
}
@@ -961,7 +958,6 @@ extension on api.AlbumUserRole {
api.AlbumUserRole.editor => AlbumUserRole.editor,
api.AlbumUserRole.viewer => AlbumUserRole.viewer,
api.AlbumUserRole.owner => AlbumUserRole.owner,
_ => throw Exception('Unknown AlbumUserRole value: $this'),
};
}
@@ -971,7 +967,6 @@ extension on api.AssetVisibility {
api.AssetVisibility.hidden => AssetVisibility.hidden,
api.AssetVisibility.archive => AssetVisibility.archive,
api.AssetVisibility.locked => AssetVisibility.locked,
_ => throw Exception('Unknown AssetVisibility value: $this'),
};
}
@@ -980,12 +975,11 @@ extension on api.UserMetadataKey {
api.UserMetadataKey.onboarding => UserMetadataKey.onboarding,
api.UserMetadataKey.preferences => UserMetadataKey.preferences,
api.UserMetadataKey.license => UserMetadataKey.license,
_ => throw Exception('Unknown UserMetadataKey value: $this'),
};
}
extension on UserAvatarColor {
AvatarColor? toAvatarColor() => AvatarColor.values.firstWhereOrNull((c) => c.name == value);
AvatarColor? toAvatarColor() => AvatarColor.values.firstWhereOrNull((c) => c.name == toString());
}
extension on api.AssetEditAction {
@@ -993,6 +987,5 @@ extension on api.AssetEditAction {
api.AssetEditAction.crop => AssetEditAction.crop,
api.AssetEditAction.rotate => AssetEditAction.rotate,
api.AssetEditAction.mirror => AssetEditAction.mirror,
_ => AssetEditAction.other,
};
}

View File

@@ -91,7 +91,7 @@ class _NativeVideoViewerState extends ConsumerState<NativeVideoViewer> with Widg
}
case AppLifecycleState.paused:
_shouldPlayOnForeground = await _controller?.isPlaying() ?? true;
if (_shouldPlayOnForeground) {
if (_shouldPlayOnForeground && mounted) {
await _notifier.pause();
}
default:
@@ -268,10 +268,13 @@ class _NativeVideoViewerState extends ConsumerState<NativeVideoViewer> with Widg
return;
}
await _notifier.load(source);
// Grab refs to prevent reading after dispose
final loopVideo = ref.read(appConfigProvider).viewer.loopVideo;
await _notifier.setLoop(!widget.asset.isMotionPhoto && loopVideo);
await _notifier.setVolume(1);
final localNotifier = _notifier;
await localNotifier.load(source);
await localNotifier.setLoop(!widget.asset.isMotionPhoto && loopVideo);
await localNotifier.setVolume(1);
}
void _initController(NativeVideoPlayerController nc) {

View File

@@ -318,7 +318,7 @@ class BackgroundUploadService {
isFavorite: asset.isFavorite,
requiresWiFi: requiresWiFi,
// Visibility hidden on upload to prevent the server from running regular jobs on the live photo asset
fields: entity.isLivePhoto ? {'visibility': api.AssetVisibility.hidden.value} : null,
fields: entity.isLivePhoto ? {'visibility': api.AssetVisibility.hidden.toString()} : null,
cloudId: entity.isLivePhoto ? null : asset.cloudId,
adjustmentTime: entity.isLivePhoto ? null : asset.adjustmentTime?.toIso8601String(),
latitude: entity.isLivePhoto ? null : asset.latitude?.toString(),

View File

@@ -342,7 +342,7 @@ class ForegroundUploadService {
file: livePhotoFile,
originalFileName: livePhotoTitle,
// Visibility hidden on upload to prevent the server from running regular jobs on the live photo asset
fields: {...fields, 'visibility': AssetVisibility.hidden.value},
fields: {...fields, 'visibility': AssetVisibility.hidden.toString()},
cancelToken: cancelToken,
onProgress: onProgress != null
? (bytes, totalBytes) => onProgress(asset.localId!, livePhotoTitle, bytes, totalBytes)

View File

@@ -1,76 +1,16 @@
import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_native_core/immich_native_core.dart';
import 'package:thumbhash/thumbhash.dart' as thumbhash;
ObjectRef<Uint8List?> useDriftBlurHashRef(RemoteAsset? asset) {
return useRef(decodeDriftThumbHash(asset?.thumbHash));
}
Uint8List? decodeDriftThumbHash(String? thumbHash) {
if (thumbHash == null || thumbHash.isEmpty) {
return null;
}
final Uint8List hash;
try {
hash = base64Decode(thumbHash);
} on FormatException {
return null;
}
final hashPtr = malloc<Uint8>(hash.length);
final info = malloc<Uint32>(3);
try {
hashPtr.asTypedList(hash.length).setAll(0, hash);
final rgba = immich_core_thumbhash_decode(hashPtr, hash.length, info);
if (rgba == nullptr) {
return null;
}
try {
return _rgbaToBmp(rgba, info[0], info[1], info[2]);
} finally {
malloc.free(rgba);
}
} finally {
malloc.free(hashPtr);
malloc.free(info);
}
}
Uint8List? _rgbaToBmp(Pointer<Uint8> rgba, int width, int height, int stride) {
if (width <= 0 || width > 32 || height <= 0 || height > 32 || stride != width * 4) {
return null;
}
const headerSize = 54;
final imageSize = stride * height;
final data = ByteData(headerSize + imageSize);
data
..setUint16(0, 0x4d42, Endian.little)
..setUint32(2, data.lengthInBytes, Endian.little)
..setUint32(10, headerSize, Endian.little)
..setUint32(14, 40, Endian.little)
..setInt32(18, width, Endian.little)
..setInt32(22, -height, Endian.little)
..setUint16(26, 1, Endian.little)
..setUint16(28, 32, Endian.little)
..setUint32(34, imageSize, Endian.little);
final pixels = rgba.asTypedList(imageSize);
for (var src = 0, dst = headerSize; src < imageSize; src += 4, dst += 4) {
data
..setUint8(dst, pixels[src + 2])
..setUint8(dst + 1, pixels[src + 1])
..setUint8(dst + 2, pixels[src])
..setUint8(dst + 3, pixels[src + 3]);
}
return data.buffer.asUint8List();
if (asset?.thumbHash == null) {
return useRef(null);
}
final rbga = thumbhash.thumbHashToRGBA(base64Decode(asset!.thumbHash!));
return useRef(thumbhash.rgbaToBmp(rbga));
}

View File

@@ -12,7 +12,7 @@ String getThumbnailUrlForRemoteId(
bool edited = true,
String? thumbhash,
}) {
final url = '${Store.get(StoreKey.serverEndpoint)}/assets/$id/thumbnail?size=${type.value}&edited=$edited';
final url = '${Store.get(StoreKey.serverEndpoint)}/assets/$id/thumbnail?size=${type.toString()}&edited=$edited';
return thumbhash != null ? '$url&c=${Uri.encodeComponent(thumbhash)}' : url;
}

View File

@@ -11,17 +11,20 @@ import 'package:immich_mobile/domain/models/log.model.dart';
import 'package:immich_mobile/domain/models/settings_key.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/domain/models/timeline.model.dart';
import 'package:immich_mobile/domain/services/feature_message.service.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/infrastructure/entities/settings.entity.drift.dart';
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
import 'package:immich_mobile/infrastructure/repositories/settings.repository.dart';
import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart';
import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart';
const int targetVersion = 26;
Future<void> migrateDatabaseIfNeeded(Drift drift) async {
final int version = Store.get(StoreKey.version, targetVersion);
final int? storedVersion = Store.tryGet(StoreKey.version);
final version = storedVersion ?? targetVersion;
if (version < 25) {
await _migrateTo25();
@@ -31,6 +34,10 @@ Future<void> migrateDatabaseIfNeeded(Drift drift) async {
await _migrateTo26(drift);
}
if (storedVersion == null) {
await FeatureMessageService(SettingsRepository.instance).markSeen();
}
await Store.put(StoreKey.version, targetVersion);
return;
}

View File

@@ -184,10 +184,3 @@ url = "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c55847602
[tools.java."platforms.windows-x64"]
checksum = "sha256:b6c17e747ae78cdd6de4d7532b3164b277daee97c007d3eaa2b39cca99882664"
url = "https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_windows-x64_bin.zip"
[[tools.rust]]
version = "1.92.0"
backend = "core:rust"
[tools.rust.options]
targets = "aarch64-apple-ios,aarch64-apple-ios-sim,aarch64-linux-android,armv7-linux-androideabi,x86_64-apple-ios,x86_64-linux-android"

View File

@@ -1,8 +1,6 @@
[tools]
"aqua:flutter/flutter" = "3.44.6"
java = "21.0.2"
# RUSTUP_TOOLCHAIN makes build hooks ignore rust-toolchain.toml targets.
rust = { version = "1.92.0", targets = "armv7-linux-androideabi,aarch64-linux-android,x86_64-linux-android,aarch64-apple-ios,aarch64-apple-ios-sim,x86_64-apple-ios" }
[tools."github:CQLabs/homebrew-dcm"]
version = "1.37.0"

View File

@@ -1 +1 @@
7.22.0
7.24.0

View File

@@ -4,12 +4,12 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 3.0.3
- Generator version: 7.22.0
- Generator version: 7.24.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements
Dart 2.12 or later
Dart 2.17 or later
## Installation & Usage

View File

@@ -97,9 +97,9 @@ class ApiClient {
if (nullableHeaderParams != null) {
request.headers.addAll(nullableHeaderParams);
}
if (msgBody is String) {
if (msgBody is String && msgBody.isNotEmpty) {
request.body = msgBody;
} else if (msgBody is List<int>) {
} else if (msgBody is List<int> && msgBody.isNotEmpty) {
request.bodyBytes = msgBody;
} else if (msgBody is Map<String, String>) {
request.bodyFields = msgBody;

View File

@@ -11,31 +11,30 @@
part of openapi.api;
/// Album user role
class AlbumUserRole {
/// Instantiate a new enum with the provided [value].
const AlbumUserRole._(this.value);
enum AlbumUserRole {
editor._(r'editor'),
owner._(r'owner'),
viewer._(r'viewer'),
;
/// Instantiate a new enum with the provided value.
const AlbumUserRole._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const editor = AlbumUserRole._(r'editor');
static const owner = AlbumUserRole._(r'owner');
static const viewer = AlbumUserRole._(r'viewer');
/// List of all possible values in this [enum][AlbumUserRole].
static const values = <AlbumUserRole>[
editor,
owner,
viewer,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AlbumUserRole] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AlbumUserRole? fromJson(dynamic value) => AlbumUserRoleTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AlbumUserRole]
/// that were successfully decoded from the passed [JSON][json].
static List<AlbumUserRole> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AlbumUserRole>[];
if (json is List && json.isNotEmpty) {
@@ -57,9 +56,11 @@ class AlbumUserRoleTypeTransformer {
const AlbumUserRoleTypeTransformer._();
String encode(AlbumUserRole data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AlbumUserRole data) => data._value;
/// Decodes a [dynamic value][data] to a AlbumUserRole.
/// Returns the instance of [AlbumUserRole] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -68,6 +69,9 @@ class AlbumUserRoleTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AlbumUserRole? decode(dynamic data, {bool allowNull = true}) {
if (data is AlbumUserRole) {
return data;
}
if (data != null) {
switch (data) {
case r'editor': return AlbumUserRole.editor;
@@ -82,7 +86,7 @@ class AlbumUserRoleTypeTransformer {
return null;
}
/// Singleton [AlbumUserRoleTypeTransformer] instance.
/// The singleton instance of this transformer.
static AlbumUserRoleTypeTransformer? _instance;
}

View File

@@ -11,31 +11,30 @@
part of openapi.api;
/// Type of edit action to perform
class AssetEditAction {
/// Instantiate a new enum with the provided [value].
const AssetEditAction._(this.value);
enum AssetEditAction {
crop._(r'crop'),
rotate._(r'rotate'),
mirror._(r'mirror'),
;
/// Instantiate a new enum with the provided value.
const AssetEditAction._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const crop = AssetEditAction._(r'crop');
static const rotate = AssetEditAction._(r'rotate');
static const mirror = AssetEditAction._(r'mirror');
/// List of all possible values in this [enum][AssetEditAction].
static const values = <AssetEditAction>[
crop,
rotate,
mirror,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetEditAction] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetEditAction? fromJson(dynamic value) => AssetEditActionTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetEditAction]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetEditAction> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetEditAction>[];
if (json is List && json.isNotEmpty) {
@@ -57,9 +56,11 @@ class AssetEditActionTypeTransformer {
const AssetEditActionTypeTransformer._();
String encode(AssetEditAction data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetEditAction data) => data._value;
/// Decodes a [dynamic value][data] to a AssetEditAction.
/// Returns the instance of [AssetEditAction] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -68,6 +69,9 @@ class AssetEditActionTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetEditAction? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetEditAction) {
return data;
}
if (data != null) {
switch (data) {
case r'crop': return AssetEditAction.crop;
@@ -82,7 +86,7 @@ class AssetEditActionTypeTransformer {
return null;
}
/// Singleton [AssetEditActionTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetEditActionTypeTransformer? _instance;
}

View File

@@ -11,31 +11,30 @@
part of openapi.api;
/// Error reason if failed
class AssetIdErrorReason {
/// Instantiate a new enum with the provided [value].
const AssetIdErrorReason._(this.value);
enum AssetIdErrorReason {
duplicate._(r'duplicate'),
noPermission._(r'no_permission'),
notFound._(r'not_found'),
;
/// Instantiate a new enum with the provided value.
const AssetIdErrorReason._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const duplicate = AssetIdErrorReason._(r'duplicate');
static const noPermission = AssetIdErrorReason._(r'no_permission');
static const notFound = AssetIdErrorReason._(r'not_found');
/// List of all possible values in this [enum][AssetIdErrorReason].
static const values = <AssetIdErrorReason>[
duplicate,
noPermission,
notFound,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetIdErrorReason] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetIdErrorReason? fromJson(dynamic value) => AssetIdErrorReasonTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetIdErrorReason]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetIdErrorReason> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetIdErrorReason>[];
if (json is List && json.isNotEmpty) {
@@ -57,9 +56,11 @@ class AssetIdErrorReasonTypeTransformer {
const AssetIdErrorReasonTypeTransformer._();
String encode(AssetIdErrorReason data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetIdErrorReason data) => data._value;
/// Decodes a [dynamic value][data] to a AssetIdErrorReason.
/// Returns the instance of [AssetIdErrorReason] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -68,6 +69,9 @@ class AssetIdErrorReasonTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetIdErrorReason? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetIdErrorReason) {
return data;
}
if (data != null) {
switch (data) {
case r'duplicate': return AssetIdErrorReason.duplicate;
@@ -82,7 +86,7 @@ class AssetIdErrorReasonTypeTransformer {
return null;
}
/// Singleton [AssetIdErrorReasonTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetIdErrorReasonTypeTransformer? _instance;
}

View File

@@ -11,33 +11,31 @@
part of openapi.api;
/// Job name
class AssetJobName {
/// Instantiate a new enum with the provided [value].
const AssetJobName._(this.value);
enum AssetJobName {
refreshFaces._(r'refresh-faces'),
refreshMetadata._(r'refresh-metadata'),
regenerateThumbnail._(r'regenerate-thumbnail'),
transcodeVideo._(r'transcode-video'),
;
/// Instantiate a new enum with the provided value.
const AssetJobName._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const refreshFaces = AssetJobName._(r'refresh-faces');
static const refreshMetadata = AssetJobName._(r'refresh-metadata');
static const regenerateThumbnail = AssetJobName._(r'regenerate-thumbnail');
static const transcodeVideo = AssetJobName._(r'transcode-video');
/// List of all possible values in this [enum][AssetJobName].
static const values = <AssetJobName>[
refreshFaces,
refreshMetadata,
regenerateThumbnail,
transcodeVideo,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetJobName] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetJobName? fromJson(dynamic value) => AssetJobNameTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetJobName]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetJobName> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetJobName>[];
if (json is List && json.isNotEmpty) {
@@ -59,9 +57,11 @@ class AssetJobNameTypeTransformer {
const AssetJobNameTypeTransformer._();
String encode(AssetJobName data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetJobName data) => data._value;
/// Decodes a [dynamic value][data] to a AssetJobName.
/// Returns the instance of [AssetJobName] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -70,6 +70,9 @@ class AssetJobNameTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetJobName? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetJobName) {
return data;
}
if (data != null) {
switch (data) {
case r'refresh-faces': return AssetJobName.refreshFaces;
@@ -85,7 +88,7 @@ class AssetJobNameTypeTransformer {
return null;
}
/// Singleton [AssetJobNameTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetJobNameTypeTransformer? _instance;
}

View File

@@ -11,33 +11,31 @@
part of openapi.api;
/// Asset media size
class AssetMediaSize {
/// Instantiate a new enum with the provided [value].
const AssetMediaSize._(this.value);
enum AssetMediaSize {
original._(r'original'),
fullsize._(r'fullsize'),
preview._(r'preview'),
thumbnail._(r'thumbnail'),
;
/// Instantiate a new enum with the provided value.
const AssetMediaSize._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const original = AssetMediaSize._(r'original');
static const fullsize = AssetMediaSize._(r'fullsize');
static const preview = AssetMediaSize._(r'preview');
static const thumbnail = AssetMediaSize._(r'thumbnail');
/// List of all possible values in this [enum][AssetMediaSize].
static const values = <AssetMediaSize>[
original,
fullsize,
preview,
thumbnail,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetMediaSize] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetMediaSize? fromJson(dynamic value) => AssetMediaSizeTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetMediaSize]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetMediaSize> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetMediaSize>[];
if (json is List && json.isNotEmpty) {
@@ -59,9 +57,11 @@ class AssetMediaSizeTypeTransformer {
const AssetMediaSizeTypeTransformer._();
String encode(AssetMediaSize data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetMediaSize data) => data._value;
/// Decodes a [dynamic value][data] to a AssetMediaSize.
/// Returns the instance of [AssetMediaSize] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -70,6 +70,9 @@ class AssetMediaSizeTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetMediaSize? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetMediaSize) {
return data;
}
if (data != null) {
switch (data) {
case r'original': return AssetMediaSize.original;
@@ -85,7 +88,7 @@ class AssetMediaSizeTypeTransformer {
return null;
}
/// Singleton [AssetMediaSizeTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetMediaSizeTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Upload status
class AssetMediaStatus {
/// Instantiate a new enum with the provided [value].
const AssetMediaStatus._(this.value);
enum AssetMediaStatus {
created._(r'created'),
duplicate._(r'duplicate'),
;
/// Instantiate a new enum with the provided value.
const AssetMediaStatus._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const created = AssetMediaStatus._(r'created');
static const duplicate = AssetMediaStatus._(r'duplicate');
/// List of all possible values in this [enum][AssetMediaStatus].
static const values = <AssetMediaStatus>[
created,
duplicate,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetMediaStatus] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetMediaStatus? fromJson(dynamic value) => AssetMediaStatusTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetMediaStatus]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetMediaStatus> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetMediaStatus>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class AssetMediaStatusTypeTransformer {
const AssetMediaStatusTypeTransformer._();
String encode(AssetMediaStatus data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetMediaStatus data) => data._value;
/// Decodes a [dynamic value][data] to a AssetMediaStatus.
/// Returns the instance of [AssetMediaStatus] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class AssetMediaStatusTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetMediaStatus? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetMediaStatus) {
return data;
}
if (data != null) {
switch (data) {
case r'created': return AssetMediaStatus.created;
@@ -79,7 +84,7 @@ class AssetMediaStatusTypeTransformer {
return null;
}
/// Singleton [AssetMediaStatusTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetMediaStatusTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Asset sort order
class AssetOrder {
/// Instantiate a new enum with the provided [value].
const AssetOrder._(this.value);
enum AssetOrder {
asc._(r'asc'),
desc._(r'desc'),
;
/// Instantiate a new enum with the provided value.
const AssetOrder._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const asc = AssetOrder._(r'asc');
static const desc = AssetOrder._(r'desc');
/// List of all possible values in this [enum][AssetOrder].
static const values = <AssetOrder>[
asc,
desc,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetOrder] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetOrder? fromJson(dynamic value) => AssetOrderTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetOrder]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetOrder> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetOrder>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class AssetOrderTypeTransformer {
const AssetOrderTypeTransformer._();
String encode(AssetOrder data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetOrder data) => data._value;
/// Decodes a [dynamic value][data] to a AssetOrder.
/// Returns the instance of [AssetOrder] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class AssetOrderTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetOrder? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetOrder) {
return data;
}
if (data != null) {
switch (data) {
case r'asc': return AssetOrder.asc;
@@ -79,7 +84,7 @@ class AssetOrderTypeTransformer {
return null;
}
/// Singleton [AssetOrderTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetOrderTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Asset sorting property
class AssetOrderBy {
/// Instantiate a new enum with the provided [value].
const AssetOrderBy._(this.value);
enum AssetOrderBy {
takenAt._(r'takenAt'),
createdAt._(r'createdAt'),
;
/// Instantiate a new enum with the provided value.
const AssetOrderBy._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const takenAt = AssetOrderBy._(r'takenAt');
static const createdAt = AssetOrderBy._(r'createdAt');
/// List of all possible values in this [enum][AssetOrderBy].
static const values = <AssetOrderBy>[
takenAt,
createdAt,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetOrderBy] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetOrderBy? fromJson(dynamic value) => AssetOrderByTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetOrderBy]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetOrderBy> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetOrderBy>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class AssetOrderByTypeTransformer {
const AssetOrderByTypeTransformer._();
String encode(AssetOrderBy data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetOrderBy data) => data._value;
/// Decodes a [dynamic value][data] to a AssetOrderBy.
/// Returns the instance of [AssetOrderBy] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class AssetOrderByTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetOrderBy? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetOrderBy) {
return data;
}
if (data != null) {
switch (data) {
case r'takenAt': return AssetOrderBy.takenAt;
@@ -79,7 +84,7 @@ class AssetOrderByTypeTransformer {
return null;
}
/// Singleton [AssetOrderByTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetOrderByTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Rejection reason if rejected
class AssetRejectReason {
/// Instantiate a new enum with the provided [value].
const AssetRejectReason._(this.value);
enum AssetRejectReason {
duplicate._(r'duplicate'),
unsupportedFormat._(r'unsupported-format'),
;
/// Instantiate a new enum with the provided value.
const AssetRejectReason._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const duplicate = AssetRejectReason._(r'duplicate');
static const unsupportedFormat = AssetRejectReason._(r'unsupported-format');
/// List of all possible values in this [enum][AssetRejectReason].
static const values = <AssetRejectReason>[
duplicate,
unsupportedFormat,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetRejectReason] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetRejectReason? fromJson(dynamic value) => AssetRejectReasonTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetRejectReason]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetRejectReason> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetRejectReason>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class AssetRejectReasonTypeTransformer {
const AssetRejectReasonTypeTransformer._();
String encode(AssetRejectReason data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetRejectReason data) => data._value;
/// Decodes a [dynamic value][data] to a AssetRejectReason.
/// Returns the instance of [AssetRejectReason] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class AssetRejectReasonTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetRejectReason? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetRejectReason) {
return data;
}
if (data != null) {
switch (data) {
case r'duplicate': return AssetRejectReason.duplicate;
@@ -79,7 +84,7 @@ class AssetRejectReasonTypeTransformer {
return null;
}
/// Singleton [AssetRejectReasonTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetRejectReasonTypeTransformer? _instance;
}

View File

@@ -11,33 +11,31 @@
part of openapi.api;
/// Asset type
class AssetTypeEnum {
/// Instantiate a new enum with the provided [value].
const AssetTypeEnum._(this.value);
enum AssetTypeEnum {
IMAGE._(r'IMAGE'),
VIDEO._(r'VIDEO'),
AUDIO._(r'AUDIO'),
OTHER._(r'OTHER'),
;
/// Instantiate a new enum with the provided value.
const AssetTypeEnum._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const IMAGE = AssetTypeEnum._(r'IMAGE');
static const VIDEO = AssetTypeEnum._(r'VIDEO');
static const AUDIO = AssetTypeEnum._(r'AUDIO');
static const OTHER = AssetTypeEnum._(r'OTHER');
/// List of all possible values in this [enum][AssetTypeEnum].
static const values = <AssetTypeEnum>[
IMAGE,
VIDEO,
AUDIO,
OTHER,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetTypeEnum] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetTypeEnum? fromJson(dynamic value) => AssetTypeEnumTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetTypeEnum]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetTypeEnum> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetTypeEnum>[];
if (json is List && json.isNotEmpty) {
@@ -59,9 +57,11 @@ class AssetTypeEnumTypeTransformer {
const AssetTypeEnumTypeTransformer._();
String encode(AssetTypeEnum data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetTypeEnum data) => data._value;
/// Decodes a [dynamic value][data] to a AssetTypeEnum.
/// Returns the instance of [AssetTypeEnum] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -70,6 +70,9 @@ class AssetTypeEnumTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetTypeEnum? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetTypeEnum) {
return data;
}
if (data != null) {
switch (data) {
case r'IMAGE': return AssetTypeEnum.IMAGE;
@@ -85,7 +88,7 @@ class AssetTypeEnumTypeTransformer {
return null;
}
/// Singleton [AssetTypeEnumTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetTypeEnumTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Upload action
class AssetUploadAction {
/// Instantiate a new enum with the provided [value].
const AssetUploadAction._(this.value);
enum AssetUploadAction {
accept._(r'accept'),
reject._(r'reject'),
;
/// Instantiate a new enum with the provided value.
const AssetUploadAction._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const accept = AssetUploadAction._(r'accept');
static const reject = AssetUploadAction._(r'reject');
/// List of all possible values in this [enum][AssetUploadAction].
static const values = <AssetUploadAction>[
accept,
reject,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetUploadAction] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetUploadAction? fromJson(dynamic value) => AssetUploadActionTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetUploadAction]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetUploadAction> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetUploadAction>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class AssetUploadActionTypeTransformer {
const AssetUploadActionTypeTransformer._();
String encode(AssetUploadAction data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetUploadAction data) => data._value;
/// Decodes a [dynamic value][data] to a AssetUploadAction.
/// Returns the instance of [AssetUploadAction] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class AssetUploadActionTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetUploadAction? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetUploadAction) {
return data;
}
if (data != null) {
switch (data) {
case r'accept': return AssetUploadAction.accept;
@@ -79,7 +84,7 @@ class AssetUploadActionTypeTransformer {
return null;
}
/// Singleton [AssetUploadActionTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetUploadActionTypeTransformer? _instance;
}

View File

@@ -11,33 +11,31 @@
part of openapi.api;
/// Asset visibility
class AssetVisibility {
/// Instantiate a new enum with the provided [value].
const AssetVisibility._(this.value);
enum AssetVisibility {
archive._(r'archive'),
timeline._(r'timeline'),
hidden._(r'hidden'),
locked._(r'locked'),
;
/// Instantiate a new enum with the provided value.
const AssetVisibility._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const archive = AssetVisibility._(r'archive');
static const timeline = AssetVisibility._(r'timeline');
static const hidden = AssetVisibility._(r'hidden');
static const locked = AssetVisibility._(r'locked');
/// List of all possible values in this [enum][AssetVisibility].
static const values = <AssetVisibility>[
archive,
timeline,
hidden,
locked,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AssetVisibility] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AssetVisibility? fromJson(dynamic value) => AssetVisibilityTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AssetVisibility]
/// that were successfully decoded from the passed [JSON][json].
static List<AssetVisibility> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetVisibility>[];
if (json is List && json.isNotEmpty) {
@@ -59,9 +57,11 @@ class AssetVisibilityTypeTransformer {
const AssetVisibilityTypeTransformer._();
String encode(AssetVisibility data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AssetVisibility data) => data._value;
/// Decodes a [dynamic value][data] to a AssetVisibility.
/// Returns the instance of [AssetVisibility] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -70,6 +70,9 @@ class AssetVisibilityTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetVisibility? decode(dynamic data, {bool allowNull = true}) {
if (data is AssetVisibility) {
return data;
}
if (data != null) {
switch (data) {
case r'archive': return AssetVisibility.archive;
@@ -85,7 +88,7 @@ class AssetVisibilityTypeTransformer {
return null;
}
/// Singleton [AssetVisibilityTypeTransformer] instance.
/// The singleton instance of this transformer.
static AssetVisibilityTypeTransformer? _instance;
}

View File

@@ -11,33 +11,31 @@
part of openapi.api;
/// Target audio codec
class AudioCodec {
/// Instantiate a new enum with the provided [value].
const AudioCodec._(this.value);
enum AudioCodec {
mp3._(r'mp3'),
aac._(r'aac'),
opus._(r'opus'),
pcmS16le._(r'pcm_s16le'),
;
/// Instantiate a new enum with the provided value.
const AudioCodec._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const mp3 = AudioCodec._(r'mp3');
static const aac = AudioCodec._(r'aac');
static const opus = AudioCodec._(r'opus');
static const pcmS16le = AudioCodec._(r'pcm_s16le');
/// List of all possible values in this [enum][AudioCodec].
static const values = <AudioCodec>[
mp3,
aac,
opus,
pcmS16le,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [AudioCodec] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static AudioCodec? fromJson(dynamic value) => AudioCodecTypeTransformer().decode(value);
/// Returns a [List] containing instances of [AudioCodec]
/// that were successfully decoded from the passed [JSON][json].
static List<AudioCodec> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AudioCodec>[];
if (json is List && json.isNotEmpty) {
@@ -59,9 +57,11 @@ class AudioCodecTypeTransformer {
const AudioCodecTypeTransformer._();
String encode(AudioCodec data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(AudioCodec data) => data._value;
/// Decodes a [dynamic value][data] to a AudioCodec.
/// Returns the instance of [AudioCodec] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -70,6 +70,9 @@ class AudioCodecTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AudioCodec? decode(dynamic data, {bool allowNull = true}) {
if (data is AudioCodec) {
return data;
}
if (data != null) {
switch (data) {
case r'mp3': return AudioCodec.mp3;
@@ -85,7 +88,7 @@ class AudioCodecTypeTransformer {
return null;
}
/// Singleton [AudioCodecTypeTransformer] instance.
/// The singleton instance of this transformer.
static AudioCodecTypeTransformer? _instance;
}

View File

@@ -11,35 +11,32 @@
part of openapi.api;
/// Error reason
class BulkIdErrorReason {
/// Instantiate a new enum with the provided [value].
const BulkIdErrorReason._(this.value);
enum BulkIdErrorReason {
duplicate._(r'duplicate'),
noPermission._(r'no_permission'),
notFound._(r'not_found'),
unknown._(r'unknown'),
validation._(r'validation'),
;
/// Instantiate a new enum with the provided value.
const BulkIdErrorReason._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const duplicate = BulkIdErrorReason._(r'duplicate');
static const noPermission = BulkIdErrorReason._(r'no_permission');
static const notFound = BulkIdErrorReason._(r'not_found');
static const unknown = BulkIdErrorReason._(r'unknown');
static const validation = BulkIdErrorReason._(r'validation');
/// List of all possible values in this [enum][BulkIdErrorReason].
static const values = <BulkIdErrorReason>[
duplicate,
noPermission,
notFound,
unknown,
validation,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [BulkIdErrorReason] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static BulkIdErrorReason? fromJson(dynamic value) => BulkIdErrorReasonTypeTransformer().decode(value);
/// Returns a [List] containing instances of [BulkIdErrorReason]
/// that were successfully decoded from the passed [JSON][json].
static List<BulkIdErrorReason> listFromJson(dynamic json, {bool growable = false,}) {
final result = <BulkIdErrorReason>[];
if (json is List && json.isNotEmpty) {
@@ -61,9 +58,11 @@ class BulkIdErrorReasonTypeTransformer {
const BulkIdErrorReasonTypeTransformer._();
String encode(BulkIdErrorReason data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(BulkIdErrorReason data) => data._value;
/// Decodes a [dynamic value][data] to a BulkIdErrorReason.
/// Returns the instance of [BulkIdErrorReason] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -72,6 +71,9 @@ class BulkIdErrorReasonTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
BulkIdErrorReason? decode(dynamic data, {bool allowNull = true}) {
if (data is BulkIdErrorReason) {
return data;
}
if (data != null) {
switch (data) {
case r'duplicate': return BulkIdErrorReason.duplicate;
@@ -88,7 +90,7 @@ class BulkIdErrorReasonTypeTransformer {
return null;
}
/// Singleton [BulkIdErrorReasonTypeTransformer] instance.
/// The singleton instance of this transformer.
static BulkIdErrorReasonTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Type of calendar heatmap
class CalendarHeatmapType {
/// Instantiate a new enum with the provided [value].
const CalendarHeatmapType._(this.value);
enum CalendarHeatmapType {
upload._(r'Upload'),
taken._(r'Taken'),
;
/// Instantiate a new enum with the provided value.
const CalendarHeatmapType._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const upload = CalendarHeatmapType._(r'Upload');
static const taken = CalendarHeatmapType._(r'Taken');
/// List of all possible values in this [enum][CalendarHeatmapType].
static const values = <CalendarHeatmapType>[
upload,
taken,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [CalendarHeatmapType] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static CalendarHeatmapType? fromJson(dynamic value) => CalendarHeatmapTypeTypeTransformer().decode(value);
/// Returns a [List] containing instances of [CalendarHeatmapType]
/// that were successfully decoded from the passed [JSON][json].
static List<CalendarHeatmapType> listFromJson(dynamic json, {bool growable = false,}) {
final result = <CalendarHeatmapType>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class CalendarHeatmapTypeTypeTransformer {
const CalendarHeatmapTypeTypeTransformer._();
String encode(CalendarHeatmapType data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(CalendarHeatmapType data) => data._value;
/// Decodes a [dynamic value][data] to a CalendarHeatmapType.
/// Returns the instance of [CalendarHeatmapType] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class CalendarHeatmapTypeTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
CalendarHeatmapType? decode(dynamic data, {bool allowNull = true}) {
if (data is CalendarHeatmapType) {
return data;
}
if (data != null) {
switch (data) {
case r'Upload': return CalendarHeatmapType.upload;
@@ -79,7 +84,7 @@ class CalendarHeatmapTypeTypeTransformer {
return null;
}
/// Singleton [CalendarHeatmapTypeTypeTransformer] instance.
/// The singleton instance of this transformer.
static CalendarHeatmapTypeTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Colorspace
class Colorspace {
/// Instantiate a new enum with the provided [value].
const Colorspace._(this.value);
enum Colorspace {
srgb._(r'srgb'),
p3._(r'p3'),
;
/// Instantiate a new enum with the provided value.
const Colorspace._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const srgb = Colorspace._(r'srgb');
static const p3 = Colorspace._(r'p3');
/// List of all possible values in this [enum][Colorspace].
static const values = <Colorspace>[
srgb,
p3,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [Colorspace] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static Colorspace? fromJson(dynamic value) => ColorspaceTypeTransformer().decode(value);
/// Returns a [List] containing instances of [Colorspace]
/// that were successfully decoded from the passed [JSON][json].
static List<Colorspace> listFromJson(dynamic json, {bool growable = false,}) {
final result = <Colorspace>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class ColorspaceTypeTransformer {
const ColorspaceTypeTransformer._();
String encode(Colorspace data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(Colorspace data) => data._value;
/// Decodes a [dynamic value][data] to a Colorspace.
/// Returns the instance of [Colorspace] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class ColorspaceTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
Colorspace? decode(dynamic data, {bool allowNull = true}) {
if (data is Colorspace) {
return data;
}
if (data != null) {
switch (data) {
case r'srgb': return Colorspace.srgb;
@@ -79,7 +84,7 @@ class ColorspaceTypeTransformer {
return null;
}
/// Singleton [ColorspaceTypeTransformer] instance.
/// The singleton instance of this transformer.
static ColorspaceTypeTransformer? _instance;
}

View File

@@ -11,31 +11,30 @@
part of openapi.api;
/// CQ mode
class CQMode {
/// Instantiate a new enum with the provided [value].
const CQMode._(this.value);
enum CQMode {
auto._(r'auto'),
cqp._(r'cqp'),
icq._(r'icq'),
;
/// Instantiate a new enum with the provided value.
const CQMode._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const auto = CQMode._(r'auto');
static const cqp = CQMode._(r'cqp');
static const icq = CQMode._(r'icq');
/// List of all possible values in this [enum][CQMode].
static const values = <CQMode>[
auto,
cqp,
icq,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [CQMode] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static CQMode? fromJson(dynamic value) => CQModeTypeTransformer().decode(value);
/// Returns a [List] containing instances of [CQMode]
/// that were successfully decoded from the passed [JSON][json].
static List<CQMode> listFromJson(dynamic json, {bool growable = false,}) {
final result = <CQMode>[];
if (json is List && json.isNotEmpty) {
@@ -57,9 +56,11 @@ class CQModeTypeTransformer {
const CQModeTypeTransformer._();
String encode(CQMode data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(CQMode data) => data._value;
/// Decodes a [dynamic value][data] to a CQMode.
/// Returns the instance of [CQMode] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -68,6 +69,9 @@ class CQModeTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
CQMode? decode(dynamic data, {bool allowNull = true}) {
if (data is CQMode) {
return data;
}
if (data != null) {
switch (data) {
case r'auto': return CQMode.auto;
@@ -82,7 +86,7 @@ class CQModeTypeTransformer {
return null;
}
/// Singleton [CQModeTypeTransformer] instance.
/// The singleton instance of this transformer.
static CQModeTypeTransformer? _instance;
}

View File

@@ -11,35 +11,32 @@
part of openapi.api;
/// HLS video resolution
class HlsVideoResolution {
/// Instantiate a new enum with the provided [value].
const HlsVideoResolution._(this.value);
enum HlsVideoResolution {
number480._(480),
number720._(720),
number1080._(1080),
number1440._(1440),
number2160._(2160),
;
/// Instantiate a new enum with the provided value.
const HlsVideoResolution._(this._value);
/// The underlying value of this enum member.
final int value;
final int _value;
@override
String toString() => value.toString();
String toString() => _value.toString();
int toJson() => value;
static const number480 = HlsVideoResolution._(480);
static const number720 = HlsVideoResolution._(720);
static const number1080 = HlsVideoResolution._(1080);
static const number1440 = HlsVideoResolution._(1440);
static const number2160 = HlsVideoResolution._(2160);
/// List of all possible values in this [enum][HlsVideoResolution].
static const values = <HlsVideoResolution>[
number480,
number720,
number1080,
number1440,
number2160,
];
/// Encodes this enum as a value suitable for JSON.
int toJson() => _value;
/// Returns the instance of [HlsVideoResolution] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static HlsVideoResolution? fromJson(dynamic value) => HlsVideoResolutionTypeTransformer().decode(value);
/// Returns a [List] containing instances of [HlsVideoResolution]
/// that were successfully decoded from the passed [JSON][json].
static List<HlsVideoResolution> listFromJson(dynamic json, {bool growable = false,}) {
final result = <HlsVideoResolution>[];
if (json is List && json.isNotEmpty) {
@@ -61,9 +58,11 @@ class HlsVideoResolutionTypeTransformer {
const HlsVideoResolutionTypeTransformer._();
int encode(HlsVideoResolution data) => data.value;
/// Encodes this enum as a value suitable for JSON.
int encode(HlsVideoResolution data) => data._value;
/// Decodes a [dynamic value][data] to a HlsVideoResolution.
/// Returns the instance of [HlsVideoResolution] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -72,6 +71,9 @@ class HlsVideoResolutionTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
HlsVideoResolution? decode(dynamic data, {bool allowNull = true}) {
if (data is HlsVideoResolution) {
return data;
}
if (data != null) {
switch (data) {
case 480: return HlsVideoResolution.number480;
@@ -88,7 +90,7 @@ class HlsVideoResolutionTypeTransformer {
return null;
}
/// Singleton [HlsVideoResolutionTypeTransformer] instance.
/// The singleton instance of this transformer.
static HlsVideoResolutionTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Image format
class ImageFormat {
/// Instantiate a new enum with the provided [value].
const ImageFormat._(this.value);
enum ImageFormat {
jpeg._(r'jpeg'),
webp._(r'webp'),
;
/// Instantiate a new enum with the provided value.
const ImageFormat._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const jpeg = ImageFormat._(r'jpeg');
static const webp = ImageFormat._(r'webp');
/// List of all possible values in this [enum][ImageFormat].
static const values = <ImageFormat>[
jpeg,
webp,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [ImageFormat] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static ImageFormat? fromJson(dynamic value) => ImageFormatTypeTransformer().decode(value);
/// Returns a [List] containing instances of [ImageFormat]
/// that were successfully decoded from the passed [JSON][json].
static List<ImageFormat> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ImageFormat>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class ImageFormatTypeTransformer {
const ImageFormatTypeTransformer._();
String encode(ImageFormat data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(ImageFormat data) => data._value;
/// Decodes a [dynamic value][data] to a ImageFormat.
/// Returns the instance of [ImageFormat] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class ImageFormatTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
ImageFormat? decode(dynamic data, {bool allowNull = true}) {
if (data is ImageFormat) {
return data;
}
if (data != null) {
switch (data) {
case r'jpeg': return ImageFormat.jpeg;
@@ -79,7 +84,7 @@ class ImageFormatTypeTransformer {
return null;
}
/// Singleton [ImageFormatTypeTransformer] instance.
/// The singleton instance of this transformer.
static ImageFormatTypeTransformer? _instance;
}

View File

@@ -11,31 +11,30 @@
part of openapi.api;
/// Integrity report type
class IntegrityReport {
/// Instantiate a new enum with the provided [value].
const IntegrityReport._(this.value);
enum IntegrityReport {
untrackedFile._(r'untracked_file'),
missingFile._(r'missing_file'),
checksumMismatch._(r'checksum_mismatch'),
;
/// Instantiate a new enum with the provided value.
const IntegrityReport._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const untrackedFile = IntegrityReport._(r'untracked_file');
static const missingFile = IntegrityReport._(r'missing_file');
static const checksumMismatch = IntegrityReport._(r'checksum_mismatch');
/// List of all possible values in this [enum][IntegrityReport].
static const values = <IntegrityReport>[
untrackedFile,
missingFile,
checksumMismatch,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [IntegrityReport] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static IntegrityReport? fromJson(dynamic value) => IntegrityReportTypeTransformer().decode(value);
/// Returns a [List] containing instances of [IntegrityReport]
/// that were successfully decoded from the passed [JSON][json].
static List<IntegrityReport> listFromJson(dynamic json, {bool growable = false,}) {
final result = <IntegrityReport>[];
if (json is List && json.isNotEmpty) {
@@ -57,9 +56,11 @@ class IntegrityReportTypeTransformer {
const IntegrityReportTypeTransformer._();
String encode(IntegrityReport data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(IntegrityReport data) => data._value;
/// Decodes a [dynamic value][data] to a IntegrityReport.
/// Returns the instance of [IntegrityReport] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -68,6 +69,9 @@ class IntegrityReportTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
IntegrityReport? decode(dynamic data, {bool allowNull = true}) {
if (data is IntegrityReport) {
return data;
}
if (data != null) {
switch (data) {
case r'untracked_file': return IntegrityReport.untrackedFile;
@@ -82,7 +86,7 @@ class IntegrityReportTypeTransformer {
return null;
}
/// Singleton [IntegrityReportTypeTransformer] instance.
/// The singleton instance of this transformer.
static IntegrityReportTypeTransformer? _instance;
}

View File

@@ -11,157 +11,93 @@
part of openapi.api;
/// Job name
class JobName {
/// Instantiate a new enum with the provided [value].
const JobName._(this.value);
enum JobName {
assetDelete._(r'AssetDelete'),
assetDeleteCheck._(r'AssetDeleteCheck'),
assetDetectFacesQueueAll._(r'AssetDetectFacesQueueAll'),
assetDetectFaces._(r'AssetDetectFaces'),
assetDetectDuplicatesQueueAll._(r'AssetDetectDuplicatesQueueAll'),
assetDetectDuplicates._(r'AssetDetectDuplicates'),
assetEditThumbnailGeneration._(r'AssetEditThumbnailGeneration'),
assetEncodeVideoQueueAll._(r'AssetEncodeVideoQueueAll'),
assetEncodeVideo._(r'AssetEncodeVideo'),
assetEmptyTrash._(r'AssetEmptyTrash'),
assetExtractMetadataQueueAll._(r'AssetExtractMetadataQueueAll'),
assetExtractMetadata._(r'AssetExtractMetadata'),
assetFileMigration._(r'AssetFileMigration'),
assetGenerateThumbnailsQueueAll._(r'AssetGenerateThumbnailsQueueAll'),
assetGenerateThumbnails._(r'AssetGenerateThumbnails'),
auditTableCleanup._(r'AuditTableCleanup'),
databaseBackup._(r'DatabaseBackup'),
facialRecognitionQueueAll._(r'FacialRecognitionQueueAll'),
facialRecognition._(r'FacialRecognition'),
fileDelete._(r'FileDelete'),
fileMigrationQueueAll._(r'FileMigrationQueueAll'),
libraryDeleteCheck._(r'LibraryDeleteCheck'),
libraryDelete._(r'LibraryDelete'),
libraryRemoveAsset._(r'LibraryRemoveAsset'),
libraryScanAssetsQueueAll._(r'LibraryScanAssetsQueueAll'),
librarySyncAssets._(r'LibrarySyncAssets'),
librarySyncFilesQueueAll._(r'LibrarySyncFilesQueueAll'),
librarySyncFiles._(r'LibrarySyncFiles'),
libraryScanQueueAll._(r'LibraryScanQueueAll'),
hlsSessionCleanup._(r'HlsSessionCleanup'),
memoryCleanup._(r'MemoryCleanup'),
memoryGenerate._(r'MemoryGenerate'),
notificationsCleanup._(r'NotificationsCleanup'),
notifyUserSignup._(r'NotifyUserSignup'),
notifyAlbumInvite._(r'NotifyAlbumInvite'),
notifyAlbumUpdate._(r'NotifyAlbumUpdate'),
userDelete._(r'UserDelete'),
userDeleteCheck._(r'UserDeleteCheck'),
userSyncUsage._(r'UserSyncUsage'),
personCleanup._(r'PersonCleanup'),
personFileMigration._(r'PersonFileMigration'),
personGenerateThumbnail._(r'PersonGenerateThumbnail'),
sessionCleanup._(r'SessionCleanup'),
sendMail._(r'SendMail'),
sidecarQueueAll._(r'SidecarQueueAll'),
sidecarCheck._(r'SidecarCheck'),
sidecarWrite._(r'SidecarWrite'),
smartSearchQueueAll._(r'SmartSearchQueueAll'),
smartSearch._(r'SmartSearch'),
storageTemplateMigration._(r'StorageTemplateMigration'),
storageTemplateMigrationSingle._(r'StorageTemplateMigrationSingle'),
tagCleanup._(r'TagCleanup'),
versionCheck._(r'VersionCheck'),
ocrQueueAll._(r'OcrQueueAll'),
ocr._(r'Ocr'),
workflowAssetTrigger._(r'WorkflowAssetTrigger'),
integrityUntrackedFilesQueueAll._(r'IntegrityUntrackedFilesQueueAll'),
integrityUntrackedFiles._(r'IntegrityUntrackedFiles'),
integrityUntrackedRefresh._(r'IntegrityUntrackedRefresh'),
integrityMissingFilesQueueAll._(r'IntegrityMissingFilesQueueAll'),
integrityMissingFiles._(r'IntegrityMissingFiles'),
integrityMissingFilesRefresh._(r'IntegrityMissingFilesRefresh'),
integrityChecksumFiles._(r'IntegrityChecksumFiles'),
integrityChecksumFilesRefresh._(r'IntegrityChecksumFilesRefresh'),
integrityDeleteReportType._(r'IntegrityDeleteReportType'),
integrityDeleteReports._(r'IntegrityDeleteReports'),
;
/// Instantiate a new enum with the provided value.
const JobName._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const assetDelete = JobName._(r'AssetDelete');
static const assetDeleteCheck = JobName._(r'AssetDeleteCheck');
static const assetDetectFacesQueueAll = JobName._(r'AssetDetectFacesQueueAll');
static const assetDetectFaces = JobName._(r'AssetDetectFaces');
static const assetDetectDuplicatesQueueAll = JobName._(r'AssetDetectDuplicatesQueueAll');
static const assetDetectDuplicates = JobName._(r'AssetDetectDuplicates');
static const assetEditThumbnailGeneration = JobName._(r'AssetEditThumbnailGeneration');
static const assetEncodeVideoQueueAll = JobName._(r'AssetEncodeVideoQueueAll');
static const assetEncodeVideo = JobName._(r'AssetEncodeVideo');
static const assetEmptyTrash = JobName._(r'AssetEmptyTrash');
static const assetExtractMetadataQueueAll = JobName._(r'AssetExtractMetadataQueueAll');
static const assetExtractMetadata = JobName._(r'AssetExtractMetadata');
static const assetFileMigration = JobName._(r'AssetFileMigration');
static const assetGenerateThumbnailsQueueAll = JobName._(r'AssetGenerateThumbnailsQueueAll');
static const assetGenerateThumbnails = JobName._(r'AssetGenerateThumbnails');
static const auditTableCleanup = JobName._(r'AuditTableCleanup');
static const databaseBackup = JobName._(r'DatabaseBackup');
static const facialRecognitionQueueAll = JobName._(r'FacialRecognitionQueueAll');
static const facialRecognition = JobName._(r'FacialRecognition');
static const fileDelete = JobName._(r'FileDelete');
static const fileMigrationQueueAll = JobName._(r'FileMigrationQueueAll');
static const libraryDeleteCheck = JobName._(r'LibraryDeleteCheck');
static const libraryDelete = JobName._(r'LibraryDelete');
static const libraryRemoveAsset = JobName._(r'LibraryRemoveAsset');
static const libraryScanAssetsQueueAll = JobName._(r'LibraryScanAssetsQueueAll');
static const librarySyncAssets = JobName._(r'LibrarySyncAssets');
static const librarySyncFilesQueueAll = JobName._(r'LibrarySyncFilesQueueAll');
static const librarySyncFiles = JobName._(r'LibrarySyncFiles');
static const libraryScanQueueAll = JobName._(r'LibraryScanQueueAll');
static const hlsSessionCleanup = JobName._(r'HlsSessionCleanup');
static const memoryCleanup = JobName._(r'MemoryCleanup');
static const memoryGenerate = JobName._(r'MemoryGenerate');
static const notificationsCleanup = JobName._(r'NotificationsCleanup');
static const notifyUserSignup = JobName._(r'NotifyUserSignup');
static const notifyAlbumInvite = JobName._(r'NotifyAlbumInvite');
static const notifyAlbumUpdate = JobName._(r'NotifyAlbumUpdate');
static const userDelete = JobName._(r'UserDelete');
static const userDeleteCheck = JobName._(r'UserDeleteCheck');
static const userSyncUsage = JobName._(r'UserSyncUsage');
static const personCleanup = JobName._(r'PersonCleanup');
static const personFileMigration = JobName._(r'PersonFileMigration');
static const personGenerateThumbnail = JobName._(r'PersonGenerateThumbnail');
static const sessionCleanup = JobName._(r'SessionCleanup');
static const sendMail = JobName._(r'SendMail');
static const sidecarQueueAll = JobName._(r'SidecarQueueAll');
static const sidecarCheck = JobName._(r'SidecarCheck');
static const sidecarWrite = JobName._(r'SidecarWrite');
static const smartSearchQueueAll = JobName._(r'SmartSearchQueueAll');
static const smartSearch = JobName._(r'SmartSearch');
static const storageTemplateMigration = JobName._(r'StorageTemplateMigration');
static const storageTemplateMigrationSingle = JobName._(r'StorageTemplateMigrationSingle');
static const tagCleanup = JobName._(r'TagCleanup');
static const versionCheck = JobName._(r'VersionCheck');
static const ocrQueueAll = JobName._(r'OcrQueueAll');
static const ocr = JobName._(r'Ocr');
static const workflowAssetTrigger = JobName._(r'WorkflowAssetTrigger');
static const integrityUntrackedFilesQueueAll = JobName._(r'IntegrityUntrackedFilesQueueAll');
static const integrityUntrackedFiles = JobName._(r'IntegrityUntrackedFiles');
static const integrityUntrackedRefresh = JobName._(r'IntegrityUntrackedRefresh');
static const integrityMissingFilesQueueAll = JobName._(r'IntegrityMissingFilesQueueAll');
static const integrityMissingFiles = JobName._(r'IntegrityMissingFiles');
static const integrityMissingFilesRefresh = JobName._(r'IntegrityMissingFilesRefresh');
static const integrityChecksumFiles = JobName._(r'IntegrityChecksumFiles');
static const integrityChecksumFilesRefresh = JobName._(r'IntegrityChecksumFilesRefresh');
static const integrityDeleteReportType = JobName._(r'IntegrityDeleteReportType');
static const integrityDeleteReports = JobName._(r'IntegrityDeleteReports');
/// List of all possible values in this [enum][JobName].
static const values = <JobName>[
assetDelete,
assetDeleteCheck,
assetDetectFacesQueueAll,
assetDetectFaces,
assetDetectDuplicatesQueueAll,
assetDetectDuplicates,
assetEditThumbnailGeneration,
assetEncodeVideoQueueAll,
assetEncodeVideo,
assetEmptyTrash,
assetExtractMetadataQueueAll,
assetExtractMetadata,
assetFileMigration,
assetGenerateThumbnailsQueueAll,
assetGenerateThumbnails,
auditTableCleanup,
databaseBackup,
facialRecognitionQueueAll,
facialRecognition,
fileDelete,
fileMigrationQueueAll,
libraryDeleteCheck,
libraryDelete,
libraryRemoveAsset,
libraryScanAssetsQueueAll,
librarySyncAssets,
librarySyncFilesQueueAll,
librarySyncFiles,
libraryScanQueueAll,
hlsSessionCleanup,
memoryCleanup,
memoryGenerate,
notificationsCleanup,
notifyUserSignup,
notifyAlbumInvite,
notifyAlbumUpdate,
userDelete,
userDeleteCheck,
userSyncUsage,
personCleanup,
personFileMigration,
personGenerateThumbnail,
sessionCleanup,
sendMail,
sidecarQueueAll,
sidecarCheck,
sidecarWrite,
smartSearchQueueAll,
smartSearch,
storageTemplateMigration,
storageTemplateMigrationSingle,
tagCleanup,
versionCheck,
ocrQueueAll,
ocr,
workflowAssetTrigger,
integrityUntrackedFilesQueueAll,
integrityUntrackedFiles,
integrityUntrackedRefresh,
integrityMissingFilesQueueAll,
integrityMissingFiles,
integrityMissingFilesRefresh,
integrityChecksumFiles,
integrityChecksumFilesRefresh,
integrityDeleteReportType,
integrityDeleteReports,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [JobName] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static JobName? fromJson(dynamic value) => JobNameTypeTransformer().decode(value);
/// Returns a [List] containing instances of [JobName]
/// that were successfully decoded from the passed [JSON][json].
static List<JobName> listFromJson(dynamic json, {bool growable = false,}) {
final result = <JobName>[];
if (json is List && json.isNotEmpty) {
@@ -183,9 +119,11 @@ class JobNameTypeTransformer {
const JobNameTypeTransformer._();
String encode(JobName data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(JobName data) => data._value;
/// Decodes a [dynamic value][data] to a JobName.
/// Returns the instance of [JobName] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -194,6 +132,9 @@ class JobNameTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
JobName? decode(dynamic data, {bool allowNull = true}) {
if (data is JobName) {
return data;
}
if (data != null) {
switch (data) {
case r'AssetDelete': return JobName.assetDelete;
@@ -271,7 +212,7 @@ class JobNameTypeTransformer {
return null;
}
/// Singleton [JobNameTypeTransformer] instance.
/// The singleton instance of this transformer.
static JobNameTypeTransformer? _instance;
}

View File

@@ -11,37 +11,33 @@
part of openapi.api;
/// Log level
class LogLevel {
/// Instantiate a new enum with the provided [value].
const LogLevel._(this.value);
enum LogLevel {
verbose._(r'verbose'),
debug._(r'debug'),
log._(r'log'),
warn._(r'warn'),
error._(r'error'),
fatal._(r'fatal'),
;
/// Instantiate a new enum with the provided value.
const LogLevel._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const verbose = LogLevel._(r'verbose');
static const debug = LogLevel._(r'debug');
static const log = LogLevel._(r'log');
static const warn = LogLevel._(r'warn');
static const error = LogLevel._(r'error');
static const fatal = LogLevel._(r'fatal');
/// List of all possible values in this [enum][LogLevel].
static const values = <LogLevel>[
verbose,
debug,
log,
warn,
error,
fatal,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [LogLevel] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static LogLevel? fromJson(dynamic value) => LogLevelTypeTransformer().decode(value);
/// Returns a [List] containing instances of [LogLevel]
/// that were successfully decoded from the passed [JSON][json].
static List<LogLevel> listFromJson(dynamic json, {bool growable = false,}) {
final result = <LogLevel>[];
if (json is List && json.isNotEmpty) {
@@ -63,9 +59,11 @@ class LogLevelTypeTransformer {
const LogLevelTypeTransformer._();
String encode(LogLevel data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(LogLevel data) => data._value;
/// Decodes a [dynamic value][data] to a LogLevel.
/// Returns the instance of [LogLevel] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -74,6 +72,9 @@ class LogLevelTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
LogLevel? decode(dynamic data, {bool allowNull = true}) {
if (data is LogLevel) {
return data;
}
if (data != null) {
switch (data) {
case r'verbose': return LogLevel.verbose;
@@ -91,7 +92,7 @@ class LogLevelTypeTransformer {
return null;
}
/// Singleton [LogLevelTypeTransformer] instance.
/// The singleton instance of this transformer.
static LogLevelTypeTransformer? _instance;
}

View File

@@ -11,33 +11,31 @@
part of openapi.api;
/// Maintenance action
class MaintenanceAction {
/// Instantiate a new enum with the provided [value].
const MaintenanceAction._(this.value);
enum MaintenanceAction {
start._(r'start'),
end._(r'end'),
selectDatabaseRestore._(r'select_database_restore'),
restoreDatabase._(r'restore_database'),
;
/// Instantiate a new enum with the provided value.
const MaintenanceAction._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const start = MaintenanceAction._(r'start');
static const end = MaintenanceAction._(r'end');
static const selectDatabaseRestore = MaintenanceAction._(r'select_database_restore');
static const restoreDatabase = MaintenanceAction._(r'restore_database');
/// List of all possible values in this [enum][MaintenanceAction].
static const values = <MaintenanceAction>[
start,
end,
selectDatabaseRestore,
restoreDatabase,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [MaintenanceAction] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static MaintenanceAction? fromJson(dynamic value) => MaintenanceActionTypeTransformer().decode(value);
/// Returns a [List] containing instances of [MaintenanceAction]
/// that were successfully decoded from the passed [JSON][json].
static List<MaintenanceAction> listFromJson(dynamic json, {bool growable = false,}) {
final result = <MaintenanceAction>[];
if (json is List && json.isNotEmpty) {
@@ -59,9 +57,11 @@ class MaintenanceActionTypeTransformer {
const MaintenanceActionTypeTransformer._();
String encode(MaintenanceAction data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(MaintenanceAction data) => data._value;
/// Decodes a [dynamic value][data] to a MaintenanceAction.
/// Returns the instance of [MaintenanceAction] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -70,6 +70,9 @@ class MaintenanceActionTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
MaintenanceAction? decode(dynamic data, {bool allowNull = true}) {
if (data is MaintenanceAction) {
return data;
}
if (data != null) {
switch (data) {
case r'start': return MaintenanceAction.start;
@@ -85,7 +88,7 @@ class MaintenanceActionTypeTransformer {
return null;
}
/// Singleton [MaintenanceActionTypeTransformer] instance.
/// The singleton instance of this transformer.
static MaintenanceActionTypeTransformer? _instance;
}

View File

@@ -11,55 +11,42 @@
part of openapi.api;
/// Manual job name
class ManualJobName {
/// Instantiate a new enum with the provided [value].
const ManualJobName._(this.value);
enum ManualJobName {
personCleanup._(r'person-cleanup'),
tagCleanup._(r'tag-cleanup'),
userCleanup._(r'user-cleanup'),
memoryCleanup._(r'memory-cleanup'),
memoryCreate._(r'memory-create'),
backupDatabase._(r'backup-database'),
integrityMissingFiles._(r'integrity-missing-files'),
integrityUntrackedFiles._(r'integrity-untracked-files'),
integrityChecksumMismatch._(r'integrity-checksum-mismatch'),
integrityMissingFilesRefresh._(r'integrity-missing-files-refresh'),
integrityUntrackedFilesRefresh._(r'integrity-untracked-files-refresh'),
integrityChecksumMismatchRefresh._(r'integrity-checksum-mismatch-refresh'),
integrityMissingFilesDeleteAll._(r'integrity-missing-files-delete-all'),
integrityUntrackedFilesDeleteAll._(r'integrity-untracked-files-delete-all'),
integrityChecksumMismatchDeleteAll._(r'integrity-checksum-mismatch-delete-all'),
;
/// Instantiate a new enum with the provided value.
const ManualJobName._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const personCleanup = ManualJobName._(r'person-cleanup');
static const tagCleanup = ManualJobName._(r'tag-cleanup');
static const userCleanup = ManualJobName._(r'user-cleanup');
static const memoryCleanup = ManualJobName._(r'memory-cleanup');
static const memoryCreate = ManualJobName._(r'memory-create');
static const backupDatabase = ManualJobName._(r'backup-database');
static const integrityMissingFiles = ManualJobName._(r'integrity-missing-files');
static const integrityUntrackedFiles = ManualJobName._(r'integrity-untracked-files');
static const integrityChecksumMismatch = ManualJobName._(r'integrity-checksum-mismatch');
static const integrityMissingFilesRefresh = ManualJobName._(r'integrity-missing-files-refresh');
static const integrityUntrackedFilesRefresh = ManualJobName._(r'integrity-untracked-files-refresh');
static const integrityChecksumMismatchRefresh = ManualJobName._(r'integrity-checksum-mismatch-refresh');
static const integrityMissingFilesDeleteAll = ManualJobName._(r'integrity-missing-files-delete-all');
static const integrityUntrackedFilesDeleteAll = ManualJobName._(r'integrity-untracked-files-delete-all');
static const integrityChecksumMismatchDeleteAll = ManualJobName._(r'integrity-checksum-mismatch-delete-all');
/// List of all possible values in this [enum][ManualJobName].
static const values = <ManualJobName>[
personCleanup,
tagCleanup,
userCleanup,
memoryCleanup,
memoryCreate,
backupDatabase,
integrityMissingFiles,
integrityUntrackedFiles,
integrityChecksumMismatch,
integrityMissingFilesRefresh,
integrityUntrackedFilesRefresh,
integrityChecksumMismatchRefresh,
integrityMissingFilesDeleteAll,
integrityUntrackedFilesDeleteAll,
integrityChecksumMismatchDeleteAll,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [ManualJobName] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static ManualJobName? fromJson(dynamic value) => ManualJobNameTypeTransformer().decode(value);
/// Returns a [List] containing instances of [ManualJobName]
/// that were successfully decoded from the passed [JSON][json].
static List<ManualJobName> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ManualJobName>[];
if (json is List && json.isNotEmpty) {
@@ -81,9 +68,11 @@ class ManualJobNameTypeTransformer {
const ManualJobNameTypeTransformer._();
String encode(ManualJobName data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(ManualJobName data) => data._value;
/// Decodes a [dynamic value][data] to a ManualJobName.
/// Returns the instance of [ManualJobName] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -92,6 +81,9 @@ class ManualJobNameTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
ManualJobName? decode(dynamic data, {bool allowNull = true}) {
if (data is ManualJobName) {
return data;
}
if (data != null) {
switch (data) {
case r'person-cleanup': return ManualJobName.personCleanup;
@@ -118,7 +110,7 @@ class ManualJobNameTypeTransformer {
return null;
}
/// Singleton [ManualJobNameTypeTransformer] instance.
/// The singleton instance of this transformer.
static ManualJobNameTypeTransformer? _instance;
}

View File

@@ -11,31 +11,30 @@
part of openapi.api;
/// Sort order
class MemorySearchOrder {
/// Instantiate a new enum with the provided [value].
const MemorySearchOrder._(this.value);
enum MemorySearchOrder {
asc._(r'asc'),
desc._(r'desc'),
random._(r'random'),
;
/// Instantiate a new enum with the provided value.
const MemorySearchOrder._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const asc = MemorySearchOrder._(r'asc');
static const desc = MemorySearchOrder._(r'desc');
static const random = MemorySearchOrder._(r'random');
/// List of all possible values in this [enum][MemorySearchOrder].
static const values = <MemorySearchOrder>[
asc,
desc,
random,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [MemorySearchOrder] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static MemorySearchOrder? fromJson(dynamic value) => MemorySearchOrderTypeTransformer().decode(value);
/// Returns a [List] containing instances of [MemorySearchOrder]
/// that were successfully decoded from the passed [JSON][json].
static List<MemorySearchOrder> listFromJson(dynamic json, {bool growable = false,}) {
final result = <MemorySearchOrder>[];
if (json is List && json.isNotEmpty) {
@@ -57,9 +56,11 @@ class MemorySearchOrderTypeTransformer {
const MemorySearchOrderTypeTransformer._();
String encode(MemorySearchOrder data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(MemorySearchOrder data) => data._value;
/// Decodes a [dynamic value][data] to a MemorySearchOrder.
/// Returns the instance of [MemorySearchOrder] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -68,6 +69,9 @@ class MemorySearchOrderTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
MemorySearchOrder? decode(dynamic data, {bool allowNull = true}) {
if (data is MemorySearchOrder) {
return data;
}
if (data != null) {
switch (data) {
case r'asc': return MemorySearchOrder.asc;
@@ -82,7 +86,7 @@ class MemorySearchOrderTypeTransformer {
return null;
}
/// Singleton [MemorySearchOrderTypeTransformer] instance.
/// The singleton instance of this transformer.
static MemorySearchOrderTypeTransformer? _instance;
}

View File

@@ -11,27 +11,28 @@
part of openapi.api;
/// Memory type
class MemoryType {
/// Instantiate a new enum with the provided [value].
const MemoryType._(this.value);
enum MemoryType {
onThisDay._(r'on_this_day'),
;
/// Instantiate a new enum with the provided value.
const MemoryType._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const onThisDay = MemoryType._(r'on_this_day');
/// List of all possible values in this [enum][MemoryType].
static const values = <MemoryType>[
onThisDay,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [MemoryType] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static MemoryType? fromJson(dynamic value) => MemoryTypeTypeTransformer().decode(value);
/// Returns a [List] containing instances of [MemoryType]
/// that were successfully decoded from the passed [JSON][json].
static List<MemoryType> listFromJson(dynamic json, {bool growable = false,}) {
final result = <MemoryType>[];
if (json is List && json.isNotEmpty) {
@@ -53,9 +54,11 @@ class MemoryTypeTypeTransformer {
const MemoryTypeTypeTransformer._();
String encode(MemoryType data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(MemoryType data) => data._value;
/// Decodes a [dynamic value][data] to a MemoryType.
/// Returns the instance of [MemoryType] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -64,6 +67,9 @@ class MemoryTypeTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
MemoryType? decode(dynamic data, {bool allowNull = true}) {
if (data is MemoryType) {
return data;
}
if (data != null) {
switch (data) {
case r'on_this_day': return MemoryType.onThisDay;
@@ -76,7 +82,7 @@ class MemoryTypeTypeTransformer {
return null;
}
/// Singleton [MemoryTypeTypeTransformer] instance.
/// The singleton instance of this transformer.
static MemoryTypeTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Axis to mirror along
class MirrorAxis {
/// Instantiate a new enum with the provided [value].
const MirrorAxis._(this.value);
enum MirrorAxis {
horizontal._(r'horizontal'),
vertical._(r'vertical'),
;
/// Instantiate a new enum with the provided value.
const MirrorAxis._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const horizontal = MirrorAxis._(r'horizontal');
static const vertical = MirrorAxis._(r'vertical');
/// List of all possible values in this [enum][MirrorAxis].
static const values = <MirrorAxis>[
horizontal,
vertical,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [MirrorAxis] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static MirrorAxis? fromJson(dynamic value) => MirrorAxisTypeTransformer().decode(value);
/// Returns a [List] containing instances of [MirrorAxis]
/// that were successfully decoded from the passed [JSON][json].
static List<MirrorAxis> listFromJson(dynamic json, {bool growable = false,}) {
final result = <MirrorAxis>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class MirrorAxisTypeTransformer {
const MirrorAxisTypeTransformer._();
String encode(MirrorAxis data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(MirrorAxis data) => data._value;
/// Decodes a [dynamic value][data] to a MirrorAxis.
/// Returns the instance of [MirrorAxis] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class MirrorAxisTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
MirrorAxis? decode(dynamic data, {bool allowNull = true}) {
if (data is MirrorAxis) {
return data;
}
if (data != null) {
switch (data) {
case r'horizontal': return MirrorAxis.horizontal;
@@ -79,7 +84,7 @@ class MirrorAxisTypeTransformer {
return null;
}
/// Singleton [MirrorAxisTypeTransformer] instance.
/// The singleton instance of this transformer.
static MirrorAxisTypeTransformer? _instance;
}

View File

@@ -11,33 +11,31 @@
part of openapi.api;
/// Notification level
class NotificationLevel {
/// Instantiate a new enum with the provided [value].
const NotificationLevel._(this.value);
enum NotificationLevel {
success._(r'success'),
error._(r'error'),
warning._(r'warning'),
info._(r'info'),
;
/// Instantiate a new enum with the provided value.
const NotificationLevel._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const success = NotificationLevel._(r'success');
static const error = NotificationLevel._(r'error');
static const warning = NotificationLevel._(r'warning');
static const info = NotificationLevel._(r'info');
/// List of all possible values in this [enum][NotificationLevel].
static const values = <NotificationLevel>[
success,
error,
warning,
info,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [NotificationLevel] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static NotificationLevel? fromJson(dynamic value) => NotificationLevelTypeTransformer().decode(value);
/// Returns a [List] containing instances of [NotificationLevel]
/// that were successfully decoded from the passed [JSON][json].
static List<NotificationLevel> listFromJson(dynamic json, {bool growable = false,}) {
final result = <NotificationLevel>[];
if (json is List && json.isNotEmpty) {
@@ -59,9 +57,11 @@ class NotificationLevelTypeTransformer {
const NotificationLevelTypeTransformer._();
String encode(NotificationLevel data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(NotificationLevel data) => data._value;
/// Decodes a [dynamic value][data] to a NotificationLevel.
/// Returns the instance of [NotificationLevel] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -70,6 +70,9 @@ class NotificationLevelTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
NotificationLevel? decode(dynamic data, {bool allowNull = true}) {
if (data is NotificationLevel) {
return data;
}
if (data != null) {
switch (data) {
case r'success': return NotificationLevel.success;
@@ -85,7 +88,7 @@ class NotificationLevelTypeTransformer {
return null;
}
/// Singleton [NotificationLevelTypeTransformer] instance.
/// The singleton instance of this transformer.
static NotificationLevelTypeTransformer? _instance;
}

View File

@@ -11,37 +11,33 @@
part of openapi.api;
/// Notification type
class NotificationType {
/// Instantiate a new enum with the provided [value].
const NotificationType._(this.value);
enum NotificationType {
jobFailed._(r'JobFailed'),
backupFailed._(r'BackupFailed'),
systemMessage._(r'SystemMessage'),
albumInvite._(r'AlbumInvite'),
albumUpdate._(r'AlbumUpdate'),
custom._(r'Custom'),
;
/// Instantiate a new enum with the provided value.
const NotificationType._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const jobFailed = NotificationType._(r'JobFailed');
static const backupFailed = NotificationType._(r'BackupFailed');
static const systemMessage = NotificationType._(r'SystemMessage');
static const albumInvite = NotificationType._(r'AlbumInvite');
static const albumUpdate = NotificationType._(r'AlbumUpdate');
static const custom = NotificationType._(r'Custom');
/// List of all possible values in this [enum][NotificationType].
static const values = <NotificationType>[
jobFailed,
backupFailed,
systemMessage,
albumInvite,
albumUpdate,
custom,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [NotificationType] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static NotificationType? fromJson(dynamic value) => NotificationTypeTypeTransformer().decode(value);
/// Returns a [List] containing instances of [NotificationType]
/// that were successfully decoded from the passed [JSON][json].
static List<NotificationType> listFromJson(dynamic json, {bool growable = false,}) {
final result = <NotificationType>[];
if (json is List && json.isNotEmpty) {
@@ -63,9 +59,11 @@ class NotificationTypeTypeTransformer {
const NotificationTypeTypeTransformer._();
String encode(NotificationType data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(NotificationType data) => data._value;
/// Decodes a [dynamic value][data] to a NotificationType.
/// Returns the instance of [NotificationType] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -74,6 +72,9 @@ class NotificationTypeTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
NotificationType? decode(dynamic data, {bool allowNull = true}) {
if (data is NotificationType) {
return data;
}
if (data != null) {
switch (data) {
case r'JobFailed': return NotificationType.jobFailed;
@@ -91,7 +92,7 @@ class NotificationTypeTypeTransformer {
return null;
}
/// Singleton [NotificationTypeTypeTransformer] instance.
/// The singleton instance of this transformer.
static NotificationTypeTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// OAuth token endpoint auth method
class OAuthTokenEndpointAuthMethod {
/// Instantiate a new enum with the provided [value].
const OAuthTokenEndpointAuthMethod._(this.value);
enum OAuthTokenEndpointAuthMethod {
clientSecretPost._(r'client_secret_post'),
clientSecretBasic._(r'client_secret_basic'),
;
/// Instantiate a new enum with the provided value.
const OAuthTokenEndpointAuthMethod._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const clientSecretPost = OAuthTokenEndpointAuthMethod._(r'client_secret_post');
static const clientSecretBasic = OAuthTokenEndpointAuthMethod._(r'client_secret_basic');
/// List of all possible values in this [enum][OAuthTokenEndpointAuthMethod].
static const values = <OAuthTokenEndpointAuthMethod>[
clientSecretPost,
clientSecretBasic,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [OAuthTokenEndpointAuthMethod] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static OAuthTokenEndpointAuthMethod? fromJson(dynamic value) => OAuthTokenEndpointAuthMethodTypeTransformer().decode(value);
/// Returns a [List] containing instances of [OAuthTokenEndpointAuthMethod]
/// that were successfully decoded from the passed [JSON][json].
static List<OAuthTokenEndpointAuthMethod> listFromJson(dynamic json, {bool growable = false,}) {
final result = <OAuthTokenEndpointAuthMethod>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class OAuthTokenEndpointAuthMethodTypeTransformer {
const OAuthTokenEndpointAuthMethodTypeTransformer._();
String encode(OAuthTokenEndpointAuthMethod data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(OAuthTokenEndpointAuthMethod data) => data._value;
/// Decodes a [dynamic value][data] to a OAuthTokenEndpointAuthMethod.
/// Returns the instance of [OAuthTokenEndpointAuthMethod] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class OAuthTokenEndpointAuthMethodTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
OAuthTokenEndpointAuthMethod? decode(dynamic data, {bool allowNull = true}) {
if (data is OAuthTokenEndpointAuthMethod) {
return data;
}
if (data != null) {
switch (data) {
case r'client_secret_post': return OAuthTokenEndpointAuthMethod.clientSecretPost;
@@ -79,7 +84,7 @@ class OAuthTokenEndpointAuthMethodTypeTransformer {
return null;
}
/// Singleton [OAuthTokenEndpointAuthMethodTypeTransformer] instance.
/// The singleton instance of this transformer.
static OAuthTokenEndpointAuthMethodTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Partner direction
class PartnerDirection {
/// Instantiate a new enum with the provided [value].
const PartnerDirection._(this.value);
enum PartnerDirection {
sharedBy._(r'shared-by'),
sharedWith._(r'shared-with'),
;
/// Instantiate a new enum with the provided value.
const PartnerDirection._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const sharedBy = PartnerDirection._(r'shared-by');
static const sharedWith = PartnerDirection._(r'shared-with');
/// List of all possible values in this [enum][PartnerDirection].
static const values = <PartnerDirection>[
sharedBy,
sharedWith,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [PartnerDirection] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static PartnerDirection? fromJson(dynamic value) => PartnerDirectionTypeTransformer().decode(value);
/// Returns a [List] containing instances of [PartnerDirection]
/// that were successfully decoded from the passed [JSON][json].
static List<PartnerDirection> listFromJson(dynamic json, {bool growable = false,}) {
final result = <PartnerDirection>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class PartnerDirectionTypeTransformer {
const PartnerDirectionTypeTransformer._();
String encode(PartnerDirection data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(PartnerDirection data) => data._value;
/// Decodes a [dynamic value][data] to a PartnerDirection.
/// Returns the instance of [PartnerDirection] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class PartnerDirectionTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
PartnerDirection? decode(dynamic data, {bool allowNull = true}) {
if (data is PartnerDirection) {
return data;
}
if (data != null) {
switch (data) {
case r'shared-by': return PartnerDirection.sharedBy;
@@ -79,7 +84,7 @@ class PartnerDirectionTypeTransformer {
return null;
}
/// Singleton [PartnerDirectionTypeTransformer] instance.
/// The singleton instance of this transformer.
static PartnerDirectionTypeTransformer? _instance;
}

View File

@@ -11,335 +11,182 @@
part of openapi.api;
/// List of permissions
class Permission {
/// Instantiate a new enum with the provided [value].
const Permission._(this.value);
enum Permission {
all._(r'all'),
activityPeriodCreate._(r'activity.create'),
activityPeriodRead._(r'activity.read'),
activityPeriodUpdate._(r'activity.update'),
activityPeriodDelete._(r'activity.delete'),
activityPeriodStatistics._(r'activity.statistics'),
apiKeyPeriodCreate._(r'apiKey.create'),
apiKeyPeriodRead._(r'apiKey.read'),
apiKeyPeriodUpdate._(r'apiKey.update'),
apiKeyPeriodDelete._(r'apiKey.delete'),
assetPeriodRead._(r'asset.read'),
assetPeriodUpdate._(r'asset.update'),
assetPeriodDelete._(r'asset.delete'),
assetPeriodStatistics._(r'asset.statistics'),
assetPeriodShare._(r'asset.share'),
assetPeriodView._(r'asset.view'),
assetPeriodDownload._(r'asset.download'),
assetPeriodUpload._(r'asset.upload'),
assetPeriodCopy._(r'asset.copy'),
assetPeriodDerive._(r'asset.derive'),
assetPeriodEditPeriodGet._(r'asset.edit.get'),
assetPeriodEditPeriodCreate._(r'asset.edit.create'),
assetPeriodEditPeriodDelete._(r'asset.edit.delete'),
albumPeriodCreate._(r'album.create'),
albumPeriodRead._(r'album.read'),
albumPeriodUpdate._(r'album.update'),
albumPeriodDelete._(r'album.delete'),
albumPeriodStatistics._(r'album.statistics'),
albumPeriodShare._(r'album.share'),
albumPeriodDownload._(r'album.download'),
albumAssetPeriodCreate._(r'albumAsset.create'),
albumAssetPeriodDelete._(r'albumAsset.delete'),
albumUserPeriodCreate._(r'albumUser.create'),
albumUserPeriodUpdate._(r'albumUser.update'),
albumUserPeriodDelete._(r'albumUser.delete'),
authPeriodChangePassword._(r'auth.changePassword'),
authDevicePeriodDelete._(r'authDevice.delete'),
archivePeriodRead._(r'archive.read'),
backupPeriodList._(r'backup.list'),
backupPeriodDownload._(r'backup.download'),
backupPeriodUpload._(r'backup.upload'),
backupPeriodDelete._(r'backup.delete'),
duplicatePeriodRead._(r'duplicate.read'),
duplicatePeriodDelete._(r'duplicate.delete'),
facePeriodCreate._(r'face.create'),
facePeriodRead._(r'face.read'),
facePeriodUpdate._(r'face.update'),
facePeriodDelete._(r'face.delete'),
folderPeriodRead._(r'folder.read'),
jobPeriodCreate._(r'job.create'),
jobPeriodRead._(r'job.read'),
libraryPeriodCreate._(r'library.create'),
libraryPeriodRead._(r'library.read'),
libraryPeriodUpdate._(r'library.update'),
libraryPeriodDelete._(r'library.delete'),
libraryPeriodStatistics._(r'library.statistics'),
timelinePeriodRead._(r'timeline.read'),
timelinePeriodDownload._(r'timeline.download'),
maintenance._(r'maintenance'),
mapPeriodRead._(r'map.read'),
mapPeriodSearch._(r'map.search'),
memoryPeriodCreate._(r'memory.create'),
memoryPeriodRead._(r'memory.read'),
memoryPeriodUpdate._(r'memory.update'),
memoryPeriodDelete._(r'memory.delete'),
memoryPeriodStatistics._(r'memory.statistics'),
memoryAssetPeriodCreate._(r'memoryAsset.create'),
memoryAssetPeriodDelete._(r'memoryAsset.delete'),
notificationPeriodCreate._(r'notification.create'),
notificationPeriodRead._(r'notification.read'),
notificationPeriodUpdate._(r'notification.update'),
notificationPeriodDelete._(r'notification.delete'),
partnerPeriodCreate._(r'partner.create'),
partnerPeriodRead._(r'partner.read'),
partnerPeriodUpdate._(r'partner.update'),
partnerPeriodDelete._(r'partner.delete'),
personPeriodCreate._(r'person.create'),
personPeriodRead._(r'person.read'),
personPeriodUpdate._(r'person.update'),
personPeriodDelete._(r'person.delete'),
personPeriodStatistics._(r'person.statistics'),
personPeriodMerge._(r'person.merge'),
personPeriodReassign._(r'person.reassign'),
pinCodePeriodCreate._(r'pinCode.create'),
pinCodePeriodUpdate._(r'pinCode.update'),
pinCodePeriodDelete._(r'pinCode.delete'),
pluginPeriodCreate._(r'plugin.create'),
pluginPeriodRead._(r'plugin.read'),
pluginPeriodUpdate._(r'plugin.update'),
pluginPeriodDelete._(r'plugin.delete'),
serverPeriodAbout._(r'server.about'),
serverPeriodApkLinks._(r'server.apkLinks'),
serverPeriodStorage._(r'server.storage'),
serverPeriodStatistics._(r'server.statistics'),
serverPeriodVersionCheck._(r'server.versionCheck'),
serverLicensePeriodRead._(r'serverLicense.read'),
serverLicensePeriodUpdate._(r'serverLicense.update'),
serverLicensePeriodDelete._(r'serverLicense.delete'),
sessionPeriodCreate._(r'session.create'),
sessionPeriodRead._(r'session.read'),
sessionPeriodUpdate._(r'session.update'),
sessionPeriodDelete._(r'session.delete'),
sessionPeriodLock._(r'session.lock'),
sharedLinkPeriodCreate._(r'sharedLink.create'),
sharedLinkPeriodRead._(r'sharedLink.read'),
sharedLinkPeriodUpdate._(r'sharedLink.update'),
sharedLinkPeriodDelete._(r'sharedLink.delete'),
stackPeriodCreate._(r'stack.create'),
stackPeriodRead._(r'stack.read'),
stackPeriodUpdate._(r'stack.update'),
stackPeriodDelete._(r'stack.delete'),
syncPeriodStream._(r'sync.stream'),
syncCheckpointPeriodRead._(r'syncCheckpoint.read'),
syncCheckpointPeriodUpdate._(r'syncCheckpoint.update'),
syncCheckpointPeriodDelete._(r'syncCheckpoint.delete'),
systemConfigPeriodRead._(r'systemConfig.read'),
systemConfigPeriodUpdate._(r'systemConfig.update'),
systemMetadataPeriodRead._(r'systemMetadata.read'),
systemMetadataPeriodUpdate._(r'systemMetadata.update'),
tagPeriodCreate._(r'tag.create'),
tagPeriodRead._(r'tag.read'),
tagPeriodUpdate._(r'tag.update'),
tagPeriodDelete._(r'tag.delete'),
tagPeriodAsset._(r'tag.asset'),
userPeriodRead._(r'user.read'),
userPeriodUpdate._(r'user.update'),
userLicensePeriodCreate._(r'userLicense.create'),
userLicensePeriodRead._(r'userLicense.read'),
userLicensePeriodUpdate._(r'userLicense.update'),
userLicensePeriodDelete._(r'userLicense.delete'),
userOnboardingPeriodRead._(r'userOnboarding.read'),
userOnboardingPeriodUpdate._(r'userOnboarding.update'),
userOnboardingPeriodDelete._(r'userOnboarding.delete'),
userPreferencePeriodRead._(r'userPreference.read'),
userPreferencePeriodUpdate._(r'userPreference.update'),
userProfileImagePeriodCreate._(r'userProfileImage.create'),
userProfileImagePeriodRead._(r'userProfileImage.read'),
userProfileImagePeriodUpdate._(r'userProfileImage.update'),
userProfileImagePeriodDelete._(r'userProfileImage.delete'),
queuePeriodRead._(r'queue.read'),
queuePeriodUpdate._(r'queue.update'),
queueJobPeriodCreate._(r'queueJob.create'),
queueJobPeriodRead._(r'queueJob.read'),
queueJobPeriodUpdate._(r'queueJob.update'),
queueJobPeriodDelete._(r'queueJob.delete'),
workflowPeriodCreate._(r'workflow.create'),
workflowPeriodRead._(r'workflow.read'),
workflowPeriodUpdate._(r'workflow.update'),
workflowPeriodDelete._(r'workflow.delete'),
adminUserPeriodCreate._(r'adminUser.create'),
adminUserPeriodRead._(r'adminUser.read'),
adminUserPeriodUpdate._(r'adminUser.update'),
adminUserPeriodDelete._(r'adminUser.delete'),
adminSessionPeriodRead._(r'adminSession.read'),
adminAuthPeriodUnlinkAll._(r'adminAuth.unlinkAll'),
;
/// Instantiate a new enum with the provided value.
const Permission._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const all = Permission._(r'all');
static const activityPeriodCreate = Permission._(r'activity.create');
static const activityPeriodRead = Permission._(r'activity.read');
static const activityPeriodUpdate = Permission._(r'activity.update');
static const activityPeriodDelete = Permission._(r'activity.delete');
static const activityPeriodStatistics = Permission._(r'activity.statistics');
static const apiKeyPeriodCreate = Permission._(r'apiKey.create');
static const apiKeyPeriodRead = Permission._(r'apiKey.read');
static const apiKeyPeriodUpdate = Permission._(r'apiKey.update');
static const apiKeyPeriodDelete = Permission._(r'apiKey.delete');
static const assetPeriodRead = Permission._(r'asset.read');
static const assetPeriodUpdate = Permission._(r'asset.update');
static const assetPeriodDelete = Permission._(r'asset.delete');
static const assetPeriodStatistics = Permission._(r'asset.statistics');
static const assetPeriodShare = Permission._(r'asset.share');
static const assetPeriodView = Permission._(r'asset.view');
static const assetPeriodDownload = Permission._(r'asset.download');
static const assetPeriodUpload = Permission._(r'asset.upload');
static const assetPeriodCopy = Permission._(r'asset.copy');
static const assetPeriodDerive = Permission._(r'asset.derive');
static const assetPeriodEditPeriodGet = Permission._(r'asset.edit.get');
static const assetPeriodEditPeriodCreate = Permission._(r'asset.edit.create');
static const assetPeriodEditPeriodDelete = Permission._(r'asset.edit.delete');
static const albumPeriodCreate = Permission._(r'album.create');
static const albumPeriodRead = Permission._(r'album.read');
static const albumPeriodUpdate = Permission._(r'album.update');
static const albumPeriodDelete = Permission._(r'album.delete');
static const albumPeriodStatistics = Permission._(r'album.statistics');
static const albumPeriodShare = Permission._(r'album.share');
static const albumPeriodDownload = Permission._(r'album.download');
static const albumAssetPeriodCreate = Permission._(r'albumAsset.create');
static const albumAssetPeriodDelete = Permission._(r'albumAsset.delete');
static const albumUserPeriodCreate = Permission._(r'albumUser.create');
static const albumUserPeriodUpdate = Permission._(r'albumUser.update');
static const albumUserPeriodDelete = Permission._(r'albumUser.delete');
static const authPeriodChangePassword = Permission._(r'auth.changePassword');
static const authDevicePeriodDelete = Permission._(r'authDevice.delete');
static const archivePeriodRead = Permission._(r'archive.read');
static const backupPeriodList = Permission._(r'backup.list');
static const backupPeriodDownload = Permission._(r'backup.download');
static const backupPeriodUpload = Permission._(r'backup.upload');
static const backupPeriodDelete = Permission._(r'backup.delete');
static const duplicatePeriodRead = Permission._(r'duplicate.read');
static const duplicatePeriodDelete = Permission._(r'duplicate.delete');
static const facePeriodCreate = Permission._(r'face.create');
static const facePeriodRead = Permission._(r'face.read');
static const facePeriodUpdate = Permission._(r'face.update');
static const facePeriodDelete = Permission._(r'face.delete');
static const folderPeriodRead = Permission._(r'folder.read');
static const jobPeriodCreate = Permission._(r'job.create');
static const jobPeriodRead = Permission._(r'job.read');
static const libraryPeriodCreate = Permission._(r'library.create');
static const libraryPeriodRead = Permission._(r'library.read');
static const libraryPeriodUpdate = Permission._(r'library.update');
static const libraryPeriodDelete = Permission._(r'library.delete');
static const libraryPeriodStatistics = Permission._(r'library.statistics');
static const timelinePeriodRead = Permission._(r'timeline.read');
static const timelinePeriodDownload = Permission._(r'timeline.download');
static const maintenance = Permission._(r'maintenance');
static const mapPeriodRead = Permission._(r'map.read');
static const mapPeriodSearch = Permission._(r'map.search');
static const memoryPeriodCreate = Permission._(r'memory.create');
static const memoryPeriodRead = Permission._(r'memory.read');
static const memoryPeriodUpdate = Permission._(r'memory.update');
static const memoryPeriodDelete = Permission._(r'memory.delete');
static const memoryPeriodStatistics = Permission._(r'memory.statistics');
static const memoryAssetPeriodCreate = Permission._(r'memoryAsset.create');
static const memoryAssetPeriodDelete = Permission._(r'memoryAsset.delete');
static const notificationPeriodCreate = Permission._(r'notification.create');
static const notificationPeriodRead = Permission._(r'notification.read');
static const notificationPeriodUpdate = Permission._(r'notification.update');
static const notificationPeriodDelete = Permission._(r'notification.delete');
static const partnerPeriodCreate = Permission._(r'partner.create');
static const partnerPeriodRead = Permission._(r'partner.read');
static const partnerPeriodUpdate = Permission._(r'partner.update');
static const partnerPeriodDelete = Permission._(r'partner.delete');
static const personPeriodCreate = Permission._(r'person.create');
static const personPeriodRead = Permission._(r'person.read');
static const personPeriodUpdate = Permission._(r'person.update');
static const personPeriodDelete = Permission._(r'person.delete');
static const personPeriodStatistics = Permission._(r'person.statistics');
static const personPeriodMerge = Permission._(r'person.merge');
static const personPeriodReassign = Permission._(r'person.reassign');
static const pinCodePeriodCreate = Permission._(r'pinCode.create');
static const pinCodePeriodUpdate = Permission._(r'pinCode.update');
static const pinCodePeriodDelete = Permission._(r'pinCode.delete');
static const pluginPeriodCreate = Permission._(r'plugin.create');
static const pluginPeriodRead = Permission._(r'plugin.read');
static const pluginPeriodUpdate = Permission._(r'plugin.update');
static const pluginPeriodDelete = Permission._(r'plugin.delete');
static const serverPeriodAbout = Permission._(r'server.about');
static const serverPeriodApkLinks = Permission._(r'server.apkLinks');
static const serverPeriodStorage = Permission._(r'server.storage');
static const serverPeriodStatistics = Permission._(r'server.statistics');
static const serverPeriodVersionCheck = Permission._(r'server.versionCheck');
static const serverLicensePeriodRead = Permission._(r'serverLicense.read');
static const serverLicensePeriodUpdate = Permission._(r'serverLicense.update');
static const serverLicensePeriodDelete = Permission._(r'serverLicense.delete');
static const sessionPeriodCreate = Permission._(r'session.create');
static const sessionPeriodRead = Permission._(r'session.read');
static const sessionPeriodUpdate = Permission._(r'session.update');
static const sessionPeriodDelete = Permission._(r'session.delete');
static const sessionPeriodLock = Permission._(r'session.lock');
static const sharedLinkPeriodCreate = Permission._(r'sharedLink.create');
static const sharedLinkPeriodRead = Permission._(r'sharedLink.read');
static const sharedLinkPeriodUpdate = Permission._(r'sharedLink.update');
static const sharedLinkPeriodDelete = Permission._(r'sharedLink.delete');
static const stackPeriodCreate = Permission._(r'stack.create');
static const stackPeriodRead = Permission._(r'stack.read');
static const stackPeriodUpdate = Permission._(r'stack.update');
static const stackPeriodDelete = Permission._(r'stack.delete');
static const syncPeriodStream = Permission._(r'sync.stream');
static const syncCheckpointPeriodRead = Permission._(r'syncCheckpoint.read');
static const syncCheckpointPeriodUpdate = Permission._(r'syncCheckpoint.update');
static const syncCheckpointPeriodDelete = Permission._(r'syncCheckpoint.delete');
static const systemConfigPeriodRead = Permission._(r'systemConfig.read');
static const systemConfigPeriodUpdate = Permission._(r'systemConfig.update');
static const systemMetadataPeriodRead = Permission._(r'systemMetadata.read');
static const systemMetadataPeriodUpdate = Permission._(r'systemMetadata.update');
static const tagPeriodCreate = Permission._(r'tag.create');
static const tagPeriodRead = Permission._(r'tag.read');
static const tagPeriodUpdate = Permission._(r'tag.update');
static const tagPeriodDelete = Permission._(r'tag.delete');
static const tagPeriodAsset = Permission._(r'tag.asset');
static const userPeriodRead = Permission._(r'user.read');
static const userPeriodUpdate = Permission._(r'user.update');
static const userLicensePeriodCreate = Permission._(r'userLicense.create');
static const userLicensePeriodRead = Permission._(r'userLicense.read');
static const userLicensePeriodUpdate = Permission._(r'userLicense.update');
static const userLicensePeriodDelete = Permission._(r'userLicense.delete');
static const userOnboardingPeriodRead = Permission._(r'userOnboarding.read');
static const userOnboardingPeriodUpdate = Permission._(r'userOnboarding.update');
static const userOnboardingPeriodDelete = Permission._(r'userOnboarding.delete');
static const userPreferencePeriodRead = Permission._(r'userPreference.read');
static const userPreferencePeriodUpdate = Permission._(r'userPreference.update');
static const userProfileImagePeriodCreate = Permission._(r'userProfileImage.create');
static const userProfileImagePeriodRead = Permission._(r'userProfileImage.read');
static const userProfileImagePeriodUpdate = Permission._(r'userProfileImage.update');
static const userProfileImagePeriodDelete = Permission._(r'userProfileImage.delete');
static const queuePeriodRead = Permission._(r'queue.read');
static const queuePeriodUpdate = Permission._(r'queue.update');
static const queueJobPeriodCreate = Permission._(r'queueJob.create');
static const queueJobPeriodRead = Permission._(r'queueJob.read');
static const queueJobPeriodUpdate = Permission._(r'queueJob.update');
static const queueJobPeriodDelete = Permission._(r'queueJob.delete');
static const workflowPeriodCreate = Permission._(r'workflow.create');
static const workflowPeriodRead = Permission._(r'workflow.read');
static const workflowPeriodUpdate = Permission._(r'workflow.update');
static const workflowPeriodDelete = Permission._(r'workflow.delete');
static const adminUserPeriodCreate = Permission._(r'adminUser.create');
static const adminUserPeriodRead = Permission._(r'adminUser.read');
static const adminUserPeriodUpdate = Permission._(r'adminUser.update');
static const adminUserPeriodDelete = Permission._(r'adminUser.delete');
static const adminSessionPeriodRead = Permission._(r'adminSession.read');
static const adminAuthPeriodUnlinkAll = Permission._(r'adminAuth.unlinkAll');
/// List of all possible values in this [enum][Permission].
static const values = <Permission>[
all,
activityPeriodCreate,
activityPeriodRead,
activityPeriodUpdate,
activityPeriodDelete,
activityPeriodStatistics,
apiKeyPeriodCreate,
apiKeyPeriodRead,
apiKeyPeriodUpdate,
apiKeyPeriodDelete,
assetPeriodRead,
assetPeriodUpdate,
assetPeriodDelete,
assetPeriodStatistics,
assetPeriodShare,
assetPeriodView,
assetPeriodDownload,
assetPeriodUpload,
assetPeriodCopy,
assetPeriodDerive,
assetPeriodEditPeriodGet,
assetPeriodEditPeriodCreate,
assetPeriodEditPeriodDelete,
albumPeriodCreate,
albumPeriodRead,
albumPeriodUpdate,
albumPeriodDelete,
albumPeriodStatistics,
albumPeriodShare,
albumPeriodDownload,
albumAssetPeriodCreate,
albumAssetPeriodDelete,
albumUserPeriodCreate,
albumUserPeriodUpdate,
albumUserPeriodDelete,
authPeriodChangePassword,
authDevicePeriodDelete,
archivePeriodRead,
backupPeriodList,
backupPeriodDownload,
backupPeriodUpload,
backupPeriodDelete,
duplicatePeriodRead,
duplicatePeriodDelete,
facePeriodCreate,
facePeriodRead,
facePeriodUpdate,
facePeriodDelete,
folderPeriodRead,
jobPeriodCreate,
jobPeriodRead,
libraryPeriodCreate,
libraryPeriodRead,
libraryPeriodUpdate,
libraryPeriodDelete,
libraryPeriodStatistics,
timelinePeriodRead,
timelinePeriodDownload,
maintenance,
mapPeriodRead,
mapPeriodSearch,
memoryPeriodCreate,
memoryPeriodRead,
memoryPeriodUpdate,
memoryPeriodDelete,
memoryPeriodStatistics,
memoryAssetPeriodCreate,
memoryAssetPeriodDelete,
notificationPeriodCreate,
notificationPeriodRead,
notificationPeriodUpdate,
notificationPeriodDelete,
partnerPeriodCreate,
partnerPeriodRead,
partnerPeriodUpdate,
partnerPeriodDelete,
personPeriodCreate,
personPeriodRead,
personPeriodUpdate,
personPeriodDelete,
personPeriodStatistics,
personPeriodMerge,
personPeriodReassign,
pinCodePeriodCreate,
pinCodePeriodUpdate,
pinCodePeriodDelete,
pluginPeriodCreate,
pluginPeriodRead,
pluginPeriodUpdate,
pluginPeriodDelete,
serverPeriodAbout,
serverPeriodApkLinks,
serverPeriodStorage,
serverPeriodStatistics,
serverPeriodVersionCheck,
serverLicensePeriodRead,
serverLicensePeriodUpdate,
serverLicensePeriodDelete,
sessionPeriodCreate,
sessionPeriodRead,
sessionPeriodUpdate,
sessionPeriodDelete,
sessionPeriodLock,
sharedLinkPeriodCreate,
sharedLinkPeriodRead,
sharedLinkPeriodUpdate,
sharedLinkPeriodDelete,
stackPeriodCreate,
stackPeriodRead,
stackPeriodUpdate,
stackPeriodDelete,
syncPeriodStream,
syncCheckpointPeriodRead,
syncCheckpointPeriodUpdate,
syncCheckpointPeriodDelete,
systemConfigPeriodRead,
systemConfigPeriodUpdate,
systemMetadataPeriodRead,
systemMetadataPeriodUpdate,
tagPeriodCreate,
tagPeriodRead,
tagPeriodUpdate,
tagPeriodDelete,
tagPeriodAsset,
userPeriodRead,
userPeriodUpdate,
userLicensePeriodCreate,
userLicensePeriodRead,
userLicensePeriodUpdate,
userLicensePeriodDelete,
userOnboardingPeriodRead,
userOnboardingPeriodUpdate,
userOnboardingPeriodDelete,
userPreferencePeriodRead,
userPreferencePeriodUpdate,
userProfileImagePeriodCreate,
userProfileImagePeriodRead,
userProfileImagePeriodUpdate,
userProfileImagePeriodDelete,
queuePeriodRead,
queuePeriodUpdate,
queueJobPeriodCreate,
queueJobPeriodRead,
queueJobPeriodUpdate,
queueJobPeriodDelete,
workflowPeriodCreate,
workflowPeriodRead,
workflowPeriodUpdate,
workflowPeriodDelete,
adminUserPeriodCreate,
adminUserPeriodRead,
adminUserPeriodUpdate,
adminUserPeriodDelete,
adminSessionPeriodRead,
adminAuthPeriodUnlinkAll,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [Permission] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static Permission? fromJson(dynamic value) => PermissionTypeTransformer().decode(value);
/// Returns a [List] containing instances of [Permission]
/// that were successfully decoded from the passed [JSON][json].
static List<Permission> listFromJson(dynamic json, {bool growable = false,}) {
final result = <Permission>[];
if (json is List && json.isNotEmpty) {
@@ -361,9 +208,11 @@ class PermissionTypeTransformer {
const PermissionTypeTransformer._();
String encode(Permission data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(Permission data) => data._value;
/// Decodes a [dynamic value][data] to a Permission.
/// Returns the instance of [Permission] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -372,6 +221,9 @@ class PermissionTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
Permission? decode(dynamic data, {bool allowNull = true}) {
if (data is Permission) {
return data;
}
if (data != null) {
switch (data) {
case r'all': return Permission.all;
@@ -538,7 +390,7 @@ class PermissionTypeTransformer {
return null;
}
/// Singleton [PermissionTypeTransformer] instance.
/// The singleton instance of this transformer.
static PermissionTypeTransformer? _instance;
}

View File

@@ -11,35 +11,32 @@
part of openapi.api;
/// Queue command to execute
class QueueCommand {
/// Instantiate a new enum with the provided [value].
const QueueCommand._(this.value);
enum QueueCommand {
start._(r'start'),
pause._(r'pause'),
resume._(r'resume'),
empty._(r'empty'),
clearFailed._(r'clear-failed'),
;
/// Instantiate a new enum with the provided value.
const QueueCommand._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const start = QueueCommand._(r'start');
static const pause = QueueCommand._(r'pause');
static const resume = QueueCommand._(r'resume');
static const empty = QueueCommand._(r'empty');
static const clearFailed = QueueCommand._(r'clear-failed');
/// List of all possible values in this [enum][QueueCommand].
static const values = <QueueCommand>[
start,
pause,
resume,
empty,
clearFailed,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [QueueCommand] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static QueueCommand? fromJson(dynamic value) => QueueCommandTypeTransformer().decode(value);
/// Returns a [List] containing instances of [QueueCommand]
/// that were successfully decoded from the passed [JSON][json].
static List<QueueCommand> listFromJson(dynamic json, {bool growable = false,}) {
final result = <QueueCommand>[];
if (json is List && json.isNotEmpty) {
@@ -61,9 +58,11 @@ class QueueCommandTypeTransformer {
const QueueCommandTypeTransformer._();
String encode(QueueCommand data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(QueueCommand data) => data._value;
/// Decodes a [dynamic value][data] to a QueueCommand.
/// Returns the instance of [QueueCommand] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -72,6 +71,9 @@ class QueueCommandTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
QueueCommand? decode(dynamic data, {bool allowNull = true}) {
if (data is QueueCommand) {
return data;
}
if (data != null) {
switch (data) {
case r'start': return QueueCommand.start;
@@ -88,7 +90,7 @@ class QueueCommandTypeTransformer {
return null;
}
/// Singleton [QueueCommandTypeTransformer] instance.
/// The singleton instance of this transformer.
static QueueCommandTypeTransformer? _instance;
}

View File

@@ -11,37 +11,33 @@
part of openapi.api;
/// Queue job status
class QueueJobStatus {
/// Instantiate a new enum with the provided [value].
const QueueJobStatus._(this.value);
enum QueueJobStatus {
active._(r'active'),
failed._(r'failed'),
completed._(r'completed'),
delayed._(r'delayed'),
waiting._(r'waiting'),
paused._(r'paused'),
;
/// Instantiate a new enum with the provided value.
const QueueJobStatus._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const active = QueueJobStatus._(r'active');
static const failed = QueueJobStatus._(r'failed');
static const completed = QueueJobStatus._(r'completed');
static const delayed = QueueJobStatus._(r'delayed');
static const waiting = QueueJobStatus._(r'waiting');
static const paused = QueueJobStatus._(r'paused');
/// List of all possible values in this [enum][QueueJobStatus].
static const values = <QueueJobStatus>[
active,
failed,
completed,
delayed,
waiting,
paused,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [QueueJobStatus] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static QueueJobStatus? fromJson(dynamic value) => QueueJobStatusTypeTransformer().decode(value);
/// Returns a [List] containing instances of [QueueJobStatus]
/// that were successfully decoded from the passed [JSON][json].
static List<QueueJobStatus> listFromJson(dynamic json, {bool growable = false,}) {
final result = <QueueJobStatus>[];
if (json is List && json.isNotEmpty) {
@@ -63,9 +59,11 @@ class QueueJobStatusTypeTransformer {
const QueueJobStatusTypeTransformer._();
String encode(QueueJobStatus data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(QueueJobStatus data) => data._value;
/// Decodes a [dynamic value][data] to a QueueJobStatus.
/// Returns the instance of [QueueJobStatus] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -74,6 +72,9 @@ class QueueJobStatusTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
QueueJobStatus? decode(dynamic data, {bool allowNull = true}) {
if (data is QueueJobStatus) {
return data;
}
if (data != null) {
switch (data) {
case r'active': return QueueJobStatus.active;
@@ -91,7 +92,7 @@ class QueueJobStatusTypeTransformer {
return null;
}
/// Singleton [QueueJobStatusTypeTransformer] instance.
/// The singleton instance of this transformer.
static QueueJobStatusTypeTransformer? _instance;
}

View File

@@ -11,63 +11,46 @@
part of openapi.api;
/// Queue name
class QueueName {
/// Instantiate a new enum with the provided [value].
const QueueName._(this.value);
enum QueueName {
thumbnailGeneration._(r'thumbnailGeneration'),
metadataExtraction._(r'metadataExtraction'),
videoConversion._(r'videoConversion'),
faceDetection._(r'faceDetection'),
facialRecognition._(r'facialRecognition'),
smartSearch._(r'smartSearch'),
duplicateDetection._(r'duplicateDetection'),
backgroundTask._(r'backgroundTask'),
storageTemplateMigration._(r'storageTemplateMigration'),
migration._(r'migration'),
search._(r'search'),
sidecar._(r'sidecar'),
library_._(r'library'),
notifications._(r'notifications'),
backupDatabase._(r'backupDatabase'),
ocr._(r'ocr'),
workflow._(r'workflow'),
integrityCheck._(r'integrityCheck'),
editor._(r'editor'),
;
/// Instantiate a new enum with the provided value.
const QueueName._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const thumbnailGeneration = QueueName._(r'thumbnailGeneration');
static const metadataExtraction = QueueName._(r'metadataExtraction');
static const videoConversion = QueueName._(r'videoConversion');
static const faceDetection = QueueName._(r'faceDetection');
static const facialRecognition = QueueName._(r'facialRecognition');
static const smartSearch = QueueName._(r'smartSearch');
static const duplicateDetection = QueueName._(r'duplicateDetection');
static const backgroundTask = QueueName._(r'backgroundTask');
static const storageTemplateMigration = QueueName._(r'storageTemplateMigration');
static const migration = QueueName._(r'migration');
static const search = QueueName._(r'search');
static const sidecar = QueueName._(r'sidecar');
static const library_ = QueueName._(r'library');
static const notifications = QueueName._(r'notifications');
static const backupDatabase = QueueName._(r'backupDatabase');
static const ocr = QueueName._(r'ocr');
static const workflow = QueueName._(r'workflow');
static const integrityCheck = QueueName._(r'integrityCheck');
static const editor = QueueName._(r'editor');
/// List of all possible values in this [enum][QueueName].
static const values = <QueueName>[
thumbnailGeneration,
metadataExtraction,
videoConversion,
faceDetection,
facialRecognition,
smartSearch,
duplicateDetection,
backgroundTask,
storageTemplateMigration,
migration,
search,
sidecar,
library_,
notifications,
backupDatabase,
ocr,
workflow,
integrityCheck,
editor,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [QueueName] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static QueueName? fromJson(dynamic value) => QueueNameTypeTransformer().decode(value);
/// Returns a [List] containing instances of [QueueName]
/// that were successfully decoded from the passed [JSON][json].
static List<QueueName> listFromJson(dynamic json, {bool growable = false,}) {
final result = <QueueName>[];
if (json is List && json.isNotEmpty) {
@@ -89,9 +72,11 @@ class QueueNameTypeTransformer {
const QueueNameTypeTransformer._();
String encode(QueueName data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(QueueName data) => data._value;
/// Decodes a [dynamic value][data] to a QueueName.
/// Returns the instance of [QueueName] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -100,6 +85,9 @@ class QueueNameTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
QueueName? decode(dynamic data, {bool allowNull = true}) {
if (data is QueueName) {
return data;
}
if (data != null) {
switch (data) {
case r'thumbnailGeneration': return QueueName.thumbnailGeneration;
@@ -130,7 +118,7 @@ class QueueNameTypeTransformer {
return null;
}
/// Singleton [QueueNameTypeTransformer] instance.
/// The singleton instance of this transformer.
static QueueNameTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Reaction level
class ReactionLevel {
/// Instantiate a new enum with the provided [value].
const ReactionLevel._(this.value);
enum ReactionLevel {
album._(r'album'),
asset._(r'asset'),
;
/// Instantiate a new enum with the provided value.
const ReactionLevel._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const album = ReactionLevel._(r'album');
static const asset = ReactionLevel._(r'asset');
/// List of all possible values in this [enum][ReactionLevel].
static const values = <ReactionLevel>[
album,
asset,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [ReactionLevel] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static ReactionLevel? fromJson(dynamic value) => ReactionLevelTypeTransformer().decode(value);
/// Returns a [List] containing instances of [ReactionLevel]
/// that were successfully decoded from the passed [JSON][json].
static List<ReactionLevel> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ReactionLevel>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class ReactionLevelTypeTransformer {
const ReactionLevelTypeTransformer._();
String encode(ReactionLevel data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(ReactionLevel data) => data._value;
/// Decodes a [dynamic value][data] to a ReactionLevel.
/// Returns the instance of [ReactionLevel] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class ReactionLevelTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
ReactionLevel? decode(dynamic data, {bool allowNull = true}) {
if (data is ReactionLevel) {
return data;
}
if (data != null) {
switch (data) {
case r'album': return ReactionLevel.album;
@@ -79,7 +84,7 @@ class ReactionLevelTypeTransformer {
return null;
}
/// Singleton [ReactionLevelTypeTransformer] instance.
/// The singleton instance of this transformer.
static ReactionLevelTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Reaction type
class ReactionType {
/// Instantiate a new enum with the provided [value].
const ReactionType._(this.value);
enum ReactionType {
comment._(r'comment'),
like._(r'like'),
;
/// Instantiate a new enum with the provided value.
const ReactionType._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const comment = ReactionType._(r'comment');
static const like = ReactionType._(r'like');
/// List of all possible values in this [enum][ReactionType].
static const values = <ReactionType>[
comment,
like,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [ReactionType] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static ReactionType? fromJson(dynamic value) => ReactionTypeTypeTransformer().decode(value);
/// Returns a [List] containing instances of [ReactionType]
/// that were successfully decoded from the passed [JSON][json].
static List<ReactionType> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ReactionType>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class ReactionTypeTypeTransformer {
const ReactionTypeTypeTransformer._();
String encode(ReactionType data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(ReactionType data) => data._value;
/// Decodes a [dynamic value][data] to a ReactionType.
/// Returns the instance of [ReactionType] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class ReactionTypeTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
ReactionType? decode(dynamic data, {bool allowNull = true}) {
if (data is ReactionType) {
return data;
}
if (data != null) {
switch (data) {
case r'comment': return ReactionType.comment;
@@ -79,7 +84,7 @@ class ReactionTypeTypeTransformer {
return null;
}
/// Singleton [ReactionTypeTypeTransformer] instance.
/// The singleton instance of this transformer.
static ReactionTypeTypeTransformer? _instance;
}

View File

@@ -11,29 +11,29 @@
part of openapi.api;
/// Release channel
class ReleaseChannel {
/// Instantiate a new enum with the provided [value].
const ReleaseChannel._(this.value);
enum ReleaseChannel {
stable._(r'stable'),
releaseCandidate._(r'releaseCandidate'),
;
/// Instantiate a new enum with the provided value.
const ReleaseChannel._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const stable = ReleaseChannel._(r'stable');
static const releaseCandidate = ReleaseChannel._(r'releaseCandidate');
/// List of all possible values in this [enum][ReleaseChannel].
static const values = <ReleaseChannel>[
stable,
releaseCandidate,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [ReleaseChannel] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static ReleaseChannel? fromJson(dynamic value) => ReleaseChannelTypeTransformer().decode(value);
/// Returns a [List] containing instances of [ReleaseChannel]
/// that were successfully decoded from the passed [JSON][json].
static List<ReleaseChannel> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ReleaseChannel>[];
if (json is List && json.isNotEmpty) {
@@ -55,9 +55,11 @@ class ReleaseChannelTypeTransformer {
const ReleaseChannelTypeTransformer._();
String encode(ReleaseChannel data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(ReleaseChannel data) => data._value;
/// Decodes a [dynamic value][data] to a ReleaseChannel.
/// Returns the instance of [ReleaseChannel] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -66,6 +68,9 @@ class ReleaseChannelTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
ReleaseChannel? decode(dynamic data, {bool allowNull = true}) {
if (data is ReleaseChannel) {
return data;
}
if (data != null) {
switch (data) {
case r'stable': return ReleaseChannel.stable;
@@ -79,7 +84,7 @@ class ReleaseChannelTypeTransformer {
return null;
}
/// Singleton [ReleaseChannelTypeTransformer] instance.
/// The singleton instance of this transformer.
static ReleaseChannelTypeTransformer? _instance;
}

View File

@@ -11,39 +11,34 @@
part of openapi.api;
class ReleaseType {
/// Instantiate a new enum with the provided [value].
const ReleaseType._(this.value);
enum ReleaseType {
major._(r'major'),
premajor._(r'premajor'),
minor._(r'minor'),
preminor._(r'preminor'),
patch_._(r'patch'),
prepatch._(r'prepatch'),
prerelease._(r'prerelease'),
;
/// Instantiate a new enum with the provided value.
const ReleaseType._(this._value);
/// The underlying value of this enum member.
final String value;
final String _value;
@override
String toString() => value;
String toString() => _value;
String toJson() => value;
static const major = ReleaseType._(r'major');
static const premajor = ReleaseType._(r'premajor');
static const minor = ReleaseType._(r'minor');
static const preminor = ReleaseType._(r'preminor');
static const patch_ = ReleaseType._(r'patch');
static const prepatch = ReleaseType._(r'prepatch');
static const prerelease = ReleaseType._(r'prerelease');
/// List of all possible values in this [enum][ReleaseType].
static const values = <ReleaseType>[
major,
premajor,
minor,
preminor,
patch_,
prepatch,
prerelease,
];
/// Encodes this enum as a value suitable for JSON.
String toJson() => _value;
/// Returns the instance of [ReleaseType] that was successfully decoded
/// from the passed [value] on success, null otherwise.
static ReleaseType? fromJson(dynamic value) => ReleaseTypeTypeTransformer().decode(value);
/// Returns a [List] containing instances of [ReleaseType]
/// that were successfully decoded from the passed [JSON][json].
static List<ReleaseType> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ReleaseType>[];
if (json is List && json.isNotEmpty) {
@@ -65,9 +60,11 @@ class ReleaseTypeTypeTransformer {
const ReleaseTypeTypeTransformer._();
String encode(ReleaseType data) => data.value;
/// Encodes this enum as a value suitable for JSON.
String encode(ReleaseType data) => data._value;
/// Decodes a [dynamic value][data] to a ReleaseType.
/// Returns the instance of [ReleaseType] that was successfully decoded
/// from the passed [data] value on success, null otherwise.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
@@ -76,6 +73,9 @@ class ReleaseTypeTypeTransformer {
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
ReleaseType? decode(dynamic data, {bool allowNull = true}) {
if (data is ReleaseType) {
return data;
}
if (data != null) {
switch (data) {
case r'major': return ReleaseType.major;
@@ -94,7 +94,7 @@ class ReleaseTypeTypeTransformer {
return null;
}
/// Singleton [ReleaseTypeTypeTransformer] instance.
/// The singleton instance of this transformer.
static ReleaseTypeTypeTransformer? _instance;
}

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