mirror of
https://github.com/immich-app/immich.git
synced 2026-07-21 13:54:36 +03:00
Compare commits
28 Commits
agg23/appb
...
renovate/t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1f92e1c38 | ||
|
|
1cda6d96cd | ||
|
|
e918658cc1 | ||
|
|
2e587fc7e8 | ||
|
|
df970da59e | ||
|
|
8061a2e5ff | ||
|
|
77091b0107 | ||
|
|
4c754f2999 | ||
|
|
6fa3f2feac | ||
|
|
3f6897ef80 | ||
|
|
89d0a9d59f | ||
|
|
45a6ea84af | ||
|
|
bf64f3867b | ||
|
|
4a4d468aa2 | ||
|
|
522def1ed6 | ||
|
|
3adc3920fb | ||
|
|
00cb50cc67 | ||
|
|
f2b0b696f6 | ||
|
|
b5401eb120 | ||
|
|
12fc8bac18 | ||
|
|
f2c00c107d | ||
|
|
f19f30ec66 | ||
|
|
297316c7b8 | ||
|
|
f18065b3c2 | ||
|
|
a3dd19cd2f | ||
|
|
9cea3f2375 | ||
|
|
507448d797 | ||
|
|
fe3eb7d865 |
38
.vscode/settings.json
vendored
38
.vscode/settings.json
vendored
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -7,7 +7,7 @@ sidebar_position: 85
|
||||
:::note
|
||||
This is a community contribution and not officially supported by the Immich team, but included here for convenience.
|
||||
|
||||
Community support can be found in the dedicated channel on the [Discord Server](https://discord.immich.app/).
|
||||
Community support should be directed to Synology-specific support platforms.
|
||||
:::
|
||||
|
||||
Immich can easily be installed on a Synology NAS using Container Manager within DSM. If you have not installed Container Manager already, you can install it in the Packages Center. Refer to the [Container Manager docs](https://kb.synology.com/en-us/DSM/help/ContainerManager/docker_desc?version=7) for more information on using Container Manager.
|
||||
|
||||
@@ -121,7 +121,7 @@ alt="Go to Docker Tab and visit the address listed next to immich-web"
|
||||
width="90%"
|
||||
alt="Go to Docker Tab and visit the address listed next to immich-web"
|
||||
/>
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
:::tip
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html
|
||||
|
||||
[[tools.wrangler]]
|
||||
version = "4.100.0"
|
||||
version = "4.110.0"
|
||||
backend = "npm:wrangler"
|
||||
|
||||
[tools.wrangler.options]
|
||||
|
||||
@@ -28,4 +28,4 @@ run = "prettier --write ."
|
||||
run = "wrangler pages deploy build --project-name=${PROJECT_NAME} --branch=${BRANCH_NAME}"
|
||||
|
||||
[tools]
|
||||
wrangler = "4.100.0"
|
||||
wrangler = "4.111.0"
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@socket.io/component-emitter": "^3.1.2",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^24.13.2",
|
||||
"@types/node": "^24.13.3",
|
||||
"@types/pg": "^8.15.1",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/supertest": "^7.0.0",
|
||||
@@ -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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) }),
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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' }],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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 });
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable unicorn/no-this-outside-of-class */
|
||||
import type { AssetResponseDto } from '@immich/sdk';
|
||||
import { expect, Page } from '@playwright/test';
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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`)) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"resolveJsonModule": true,
|
||||
"target": "es2023",
|
||||
"lib": ["dom", "ESNext"],
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"incremental": true,
|
||||
|
||||
38
mise.lock
38
mise.lock
@@ -287,43 +287,43 @@ url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.
|
||||
url_api = "https://api.github.com/repos/opentofu/opentofu/releases/assets/391536406"
|
||||
|
||||
[[tools.pnpm]]
|
||||
version = "11.6.0"
|
||||
version = "11.13.1"
|
||||
backend = "aqua:pnpm/pnpm"
|
||||
|
||||
[tools.pnpm."platforms.linux-arm64"]
|
||||
checksum = "sha256:2fec653ff6dadab340d1c3d2214688a7451cc471f39710839440b293ca7c53b0"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-arm64.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120174"
|
||||
checksum = "sha256:b52db99d215ed7dc9563aed815953c62a6c1ffd7cd75803d3a07ad7e4f246aed"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.13.1/pnpm-linux-arm64.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/478563983"
|
||||
provenance = "github-attestations"
|
||||
|
||||
[tools.pnpm."platforms.linux-arm64-musl"]
|
||||
checksum = "sha256:56a78c08cf22adf29e7dacb6f7f100139731693863d20fb94a7883463a62169e"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-arm64-musl.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120177"
|
||||
checksum = "sha256:2cadd4fc815c591f498a0a84c9e74a836e3e8c1236275f6e1cfd355bae6ae957"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.13.1/pnpm-linux-arm64-musl.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/478563985"
|
||||
provenance = "github-attestations"
|
||||
|
||||
[tools.pnpm."platforms.linux-x64"]
|
||||
checksum = "sha256:74d64c1646385fb21691f32f0ab6aca1a9f5c829ba54d3cda3a24838a228e68c"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-x64.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120176"
|
||||
checksum = "sha256:bd6d4b0e14536207ad76bc838f5980cecd968da15f69aae0b207380cca3f2e98"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.13.1/pnpm-linux-x64.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/478563986"
|
||||
provenance = "github-attestations"
|
||||
|
||||
[tools.pnpm."platforms.linux-x64-musl"]
|
||||
checksum = "sha256:7a0c463a09d912fba6b7d9eca0a946bc228ea50f3015a05c09a29e7e85a932d7"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-x64-musl.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120175"
|
||||
checksum = "sha256:ba19690f4ed1b64f1203ade14e9216352b46232d5582468b26a0160e0c9618c5"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.13.1/pnpm-linux-x64-musl.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/478563980"
|
||||
provenance = "github-attestations"
|
||||
|
||||
[tools.pnpm."platforms.macos-arm64"]
|
||||
checksum = "sha256:87c901635a14481fb30566a3749041134ffd4317bc6fe866c345b69fdf9b6b85"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-darwin-arm64.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120180"
|
||||
checksum = "sha256:765c2bf04e8129cb58c0f946e324262e418370b35a203b50b1f06a0567ef8bc1"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.13.1/pnpm-darwin-arm64.tar.gz"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/478563984"
|
||||
provenance = "github-attestations"
|
||||
|
||||
[tools.pnpm."platforms.windows-x64"]
|
||||
checksum = "sha256:91c753435542b04859c689304fae0dd64eba6b40937cfa426a48485b712e4e9c"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-win32-x64.zip"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120173"
|
||||
checksum = "sha256:d8bebbc71df2702961c1d34a5e61196bc0aa3bbde33c33253f6afa3dd4546a6d"
|
||||
url = "https://github.com/pnpm/pnpm/releases/download/v11.13.1/pnpm-win32-x64.zip"
|
||||
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/478563981"
|
||||
provenance = "github-attestations"
|
||||
|
||||
[[tools.terragrunt]]
|
||||
|
||||
@@ -16,7 +16,7 @@ config_roots = [
|
||||
|
||||
[tools]
|
||||
node = "24.15.0"
|
||||
pnpm = "11.6.0"
|
||||
pnpm = "11.13.1"
|
||||
terragrunt = "1.0.3"
|
||||
opentofu = "1.11.6"
|
||||
"npm:oazapfts" = "7.5.0"
|
||||
|
||||
@@ -89,13 +89,6 @@ flutter {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
constraints {
|
||||
implementation("androidx.glance:glance-appwidget") {
|
||||
version { strictly libs.versions.glance.get() }
|
||||
because 'home_widget requests 1.+ which can resolve to pre-releases incompatible with our compileSdk/AGP'
|
||||
}
|
||||
}
|
||||
|
||||
implementation libs.okhttp
|
||||
implementation libs.cronet.embedded
|
||||
implementation libs.media3.datasource.okhttp
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -12,12 +12,8 @@ PODS:
|
||||
- Flutter
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- home_widget (0.0.1):
|
||||
- Flutter
|
||||
- native_video_player (1.0.0):
|
||||
- Flutter
|
||||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- share_handler_ios (0.0.14):
|
||||
- Flutter
|
||||
- share_handler_ios/share_handler_ios_models (= 0.0.14)
|
||||
@@ -34,9 +30,7 @@ DEPENDENCIES:
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- home_widget (from `.symlinks/plugins/home_widget/ios`)
|
||||
- native_video_player (from `.symlinks/plugins/native_video_player/ios`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- share_handler_ios (from `.symlinks/plugins/share_handler_ios/ios`)
|
||||
- share_handler_ios_models (from `.symlinks/plugins/share_handler_ios/ios/Models`)
|
||||
|
||||
@@ -53,12 +47,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
home_widget:
|
||||
:path: ".symlinks/plugins/home_widget/ios"
|
||||
native_video_player:
|
||||
:path: ".symlinks/plugins/native_video_player/ios"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
share_handler_ios:
|
||||
:path: ".symlinks/plugins/share_handler_ios/ios"
|
||||
share_handler_ios_models:
|
||||
@@ -71,12 +61,10 @@ SPEC CHECKSUMS:
|
||||
flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
|
||||
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
|
||||
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
|
||||
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
|
||||
native_video_player: b65c58951ede2f93d103a25366bdebca95081265
|
||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||
share_handler_ios: e2244e990f826b2c8eaa291ac3831569438ba0fb
|
||||
share_handler_ios_models: fc638c9b4330dc7f082586c92aee9dfa0b87b871
|
||||
|
||||
PODFILE CHECKSUM: 938abbae4114b9c2140c550a2a0d8f7c674f5dfe
|
||||
PODFILE CHECKSUM: 3c43a700a4bffb4120bf696cad263aefd4bb3c8c
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
||||
@@ -154,11 +154,15 @@
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
B231F52D2E93A44A00BC45D1 /* Core */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = Core;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = Sync;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -180,6 +184,8 @@
|
||||
};
|
||||
FEE084F22EC172080045228E /* Schemas */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = Schemas;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -372,7 +378,6 @@
|
||||
FAC6F89A2D287C890078CB2F /* Embed Foundation Extensions */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
513DA7292DED6106813332F4 /* [CP] Embed Pods Frameworks */,
|
||||
2FA39DEC809D6D7C4A01EFCB /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -466,7 +471,7 @@
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
packageReferences = (
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
|
||||
FEE084F62EC172460045228E /* XCRemoteSwiftPackageReference "sqlite-data" */,
|
||||
FEE084F92EC1725A0045228E /* XCRemoteSwiftPackageReference "swift-http-structured-headers" */,
|
||||
);
|
||||
@@ -513,27 +518,6 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
2FA39DEC809D6D7C4A01EFCB /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@@ -558,14 +542,10 @@
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
@@ -606,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;
|
||||
@@ -1266,7 +1246,7 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
|
||||
45
mobile/ios/scripts/xcode_flutter_build.sh
Executable file
45
mobile/ios/scripts/xcode_flutter_build.sh
Executable 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]}"
|
||||
@@ -70,6 +70,10 @@ class RemoteAsset extends BaseAsset {
|
||||
|
||||
bool get isTrashed => deletedAt != null;
|
||||
|
||||
bool get isStacked => stackId != null;
|
||||
|
||||
bool get isArchived => visibility == .archive;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''Asset {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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'),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,16 +44,7 @@ final class $$AssetEditEntityTableReferences
|
||||
static i5.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$AssetEditEntityTable>('asset_edit_entity')
|
||||
.assetId,
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('asset_edit_entity__asset_id__remote_asset_entity__id');
|
||||
|
||||
i5.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
final $_column = $_itemColumn<String>('asset_id')!;
|
||||
|
||||
@@ -59,16 +59,7 @@ final class $$AssetFaceEntityTableReferences
|
||||
static i4.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$AssetFaceEntityTable>('asset_face_entity')
|
||||
.assetId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i4.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('asset_face_entity__asset_id__remote_asset_entity__id');
|
||||
|
||||
i4.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
final $_column = $_itemColumn<String>('asset_id')!;
|
||||
@@ -91,16 +82,7 @@ final class $$AssetFaceEntityTableReferences
|
||||
static i6.$PersonEntityTable _personIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i6.$PersonEntityTable>('person_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$AssetFaceEntityTable>('asset_face_entity')
|
||||
.personId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i6.$PersonEntityTable>('person_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('asset_face_entity__person_id__person_entity__id');
|
||||
|
||||
i6.$$PersonEntityTableProcessedTableManager? get personId {
|
||||
final $_column = $_itemColumn<String>('person_id');
|
||||
|
||||
@@ -61,16 +61,7 @@ final class $$AssetOcrEntityTableReferences
|
||||
static i4.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i1.$AssetOcrEntityTable>('asset_ocr_entity').assetId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i4.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('asset_ocr_entity__asset_id__remote_asset_entity__id');
|
||||
|
||||
i4.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
final $_column = $_itemColumn<String>('asset_id')!;
|
||||
|
||||
@@ -75,16 +75,7 @@ final class $$RemoteExifEntityTableReferences
|
||||
static i3.$RemoteAssetEntityTable _assetIdTable(i0.GeneratedDatabase db) =>
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteExifEntityTable>('remote_exif_entity')
|
||||
.assetId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('remote_exif_entity__asset_id__remote_asset_entity__id');
|
||||
|
||||
i3.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
final $_column = $_itemColumn<String>('asset_id')!;
|
||||
|
||||
@@ -50,14 +50,7 @@ final class $$LocalAlbumEntityTableReferences
|
||||
) => i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$LocalAlbumEntityTable>('local_album_entity')
|
||||
.linkedRemoteAlbumId,
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity').id,
|
||||
),
|
||||
'local_album_entity__linked_remote_album_id__remote_album_entity__id',
|
||||
);
|
||||
|
||||
i5.$$RemoteAlbumEntityTableProcessedTableManager? get linkedRemoteAlbumId {
|
||||
|
||||
@@ -41,16 +41,7 @@ final class $$LocalAlbumAssetEntityTableReferences
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i3.$LocalAssetEntityTable>('local_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$LocalAlbumAssetEntityTable>(
|
||||
'local_album_asset_entity',
|
||||
)
|
||||
.assetId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i3.$LocalAssetEntityTable>('local_asset_entity').id,
|
||||
),
|
||||
'local_album_asset_entity__asset_id__local_asset_entity__id',
|
||||
);
|
||||
|
||||
i3.$$LocalAssetEntityTableProcessedTableManager get assetId {
|
||||
@@ -75,16 +66,7 @@ final class $$LocalAlbumAssetEntityTableReferences
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$LocalAlbumEntityTable>('local_album_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$LocalAlbumAssetEntityTable>(
|
||||
'local_album_asset_entity',
|
||||
)
|
||||
.albumId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$LocalAlbumEntityTable>('local_album_entity').id,
|
||||
),
|
||||
'local_album_asset_entity__album_id__local_album_entity__id',
|
||||
);
|
||||
|
||||
i5.$$LocalAlbumEntityTableProcessedTableManager get albumId {
|
||||
|
||||
@@ -53,16 +53,7 @@ final class $$MemoryEntityTableReferences
|
||||
static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i1.$MemoryEntityTable>('memory_entity').ownerId,
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('memory_entity__owner_id__user_entity__id');
|
||||
|
||||
i5.$$UserEntityTableProcessedTableManager get ownerId {
|
||||
final $_column = $_itemColumn<String>('owner_id')!;
|
||||
|
||||
@@ -39,14 +39,7 @@ final class $$MemoryAssetEntityTableReferences
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$MemoryAssetEntityTable>('memory_asset_entity')
|
||||
.assetId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
'memory_asset_entity__asset_id__remote_asset_entity__id',
|
||||
);
|
||||
|
||||
i3.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
@@ -70,16 +63,7 @@ final class $$MemoryAssetEntityTableReferences
|
||||
static i5.$MemoryEntityTable _memoryIdTable(i0.GeneratedDatabase db) =>
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$MemoryEntityTable>('memory_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$MemoryAssetEntityTable>('memory_asset_entity')
|
||||
.memoryId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$MemoryEntityTable>('memory_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('memory_asset_entity__memory_id__memory_entity__id');
|
||||
|
||||
i5.$$MemoryEntityTableProcessedTableManager get memoryId {
|
||||
final $_column = $_itemColumn<String>('memory_id')!;
|
||||
|
||||
@@ -39,16 +39,7 @@ final class $$PartnerEntityTableReferences
|
||||
static i4.$UserEntityTable _sharedByIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i1.$PartnerEntityTable>('partner_entity').sharedById,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i4.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('partner_entity__shared_by_id__user_entity__id');
|
||||
|
||||
i4.$$UserEntityTableProcessedTableManager get sharedById {
|
||||
final $_column = $_itemColumn<String>('shared_by_id')!;
|
||||
@@ -71,16 +62,7 @@ final class $$PartnerEntityTableReferences
|
||||
static i4.$UserEntityTable _sharedWithIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$PartnerEntityTable>('partner_entity')
|
||||
.sharedWithId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i4.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('partner_entity__shared_with_id__user_entity__id');
|
||||
|
||||
i4.$$UserEntityTableProcessedTableManager get sharedWithId {
|
||||
final $_column = $_itemColumn<String>('shared_with_id')!;
|
||||
|
||||
@@ -48,16 +48,7 @@ final class $$PersonEntityTableReferences
|
||||
static i4.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i1.$PersonEntityTable>('person_entity').ownerId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i4.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('person_entity__owner_id__user_entity__id');
|
||||
|
||||
i4.$$UserEntityTableProcessedTableManager get ownerId {
|
||||
final $_column = $_itemColumn<String>('owner_id')!;
|
||||
|
||||
@@ -52,14 +52,7 @@ final class $$RemoteAlbumEntityTableReferences
|
||||
) => i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.thumbnailAssetId,
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
'remote_album_entity__thumbnail_asset_id__remote_asset_entity__id',
|
||||
);
|
||||
|
||||
i5.$$RemoteAssetEntityTableProcessedTableManager? get thumbnailAssetId {
|
||||
|
||||
@@ -39,16 +39,7 @@ final class $$RemoteAlbumAssetEntityTableReferences
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumAssetEntityTable>(
|
||||
'remote_album_asset_entity',
|
||||
)
|
||||
.assetId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
'remote_album_asset_entity__asset_id__remote_asset_entity__id',
|
||||
);
|
||||
|
||||
i3.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
@@ -73,16 +64,7 @@ final class $$RemoteAlbumAssetEntityTableReferences
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumAssetEntityTable>(
|
||||
'remote_album_asset_entity',
|
||||
)
|
||||
.albumId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$RemoteAlbumEntityTable>('remote_album_entity').id,
|
||||
),
|
||||
'remote_album_asset_entity__album_id__remote_album_entity__id',
|
||||
);
|
||||
|
||||
i5.$$RemoteAlbumEntityTableProcessedTableManager get albumId {
|
||||
|
||||
@@ -42,16 +42,7 @@ final class $$RemoteAlbumUserEntityTableReferences
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumUserEntityTable>(
|
||||
'remote_album_user_entity',
|
||||
)
|
||||
.albumId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i4.$RemoteAlbumEntityTable>('remote_album_entity').id,
|
||||
),
|
||||
'remote_album_user_entity__album_id__remote_album_entity__id',
|
||||
);
|
||||
|
||||
i4.$$RemoteAlbumEntityTableProcessedTableManager get albumId {
|
||||
@@ -75,18 +66,7 @@ final class $$RemoteAlbumUserEntityTableReferences
|
||||
static i6.$UserEntityTable _userIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i6.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAlbumUserEntityTable>(
|
||||
'remote_album_user_entity',
|
||||
)
|
||||
.userId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i6.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('remote_album_user_entity__user_id__user_entity__id');
|
||||
|
||||
i6.$$UserEntityTableProcessedTableManager get userId {
|
||||
final $_column = $_itemColumn<String>('user_id')!;
|
||||
|
||||
@@ -74,16 +74,7 @@ final class $$RemoteAssetEntityTableReferences
|
||||
static i5.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.ownerId,
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('remote_asset_entity__owner_id__user_entity__id');
|
||||
|
||||
i5.$$UserEntityTableProcessedTableManager get ownerId {
|
||||
final $_column = $_itemColumn<String>('owner_id')!;
|
||||
|
||||
@@ -45,16 +45,7 @@ final class $$RemoteAssetCloudIdEntityTableReferences
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i4.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$RemoteAssetCloudIdEntityTable>(
|
||||
'remote_asset_cloud_id_entity',
|
||||
)
|
||||
.assetId,
|
||||
i4.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i3.$RemoteAssetEntityTable>('remote_asset_entity').id,
|
||||
),
|
||||
'remote_asset_cloud_id_entity__asset_id__remote_asset_entity__id',
|
||||
);
|
||||
|
||||
i3.$$RemoteAssetEntityTableProcessedTableManager get assetId {
|
||||
|
||||
@@ -38,16 +38,7 @@ final class $$StackEntityTableReferences
|
||||
static i4.$UserEntityTable _ownerIdTable(i0.GeneratedDatabase db) =>
|
||||
i5.ReadDatabaseContainer(db)
|
||||
.resultSet<i4.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i1.$StackEntityTable>('stack_entity').ownerId,
|
||||
i5.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i4.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('stack_entity__owner_id__user_entity__id');
|
||||
|
||||
i4.$$UserEntityTableProcessedTableManager get ownerId {
|
||||
final $_column = $_itemColumn<String>('owner_id')!;
|
||||
|
||||
@@ -40,18 +40,7 @@ final class $$UserMetadataEntityTableReferences
|
||||
static i5.$UserEntityTable _userIdTable(i0.GeneratedDatabase db) =>
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i5.$UserEntityTable>('user_entity')
|
||||
.createAlias(
|
||||
i0.$_aliasNameGenerator(
|
||||
i6.ReadDatabaseContainer(db)
|
||||
.resultSet<i1.$UserMetadataEntityTable>(
|
||||
'user_metadata_entity',
|
||||
)
|
||||
.userId,
|
||||
i6.ReadDatabaseContainer(
|
||||
db,
|
||||
).resultSet<i5.$UserEntityTable>('user_entity').id,
|
||||
),
|
||||
);
|
||||
.createAlias('user_metadata_entity__user_id__user_entity__id');
|
||||
|
||||
i5.$$UserEntityTableProcessedTableManager get userId {
|
||||
final $_column = $_itemColumn<String>('user_id')!;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,25 +3,23 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/generated/translations.g.dart';
|
||||
import 'package:immich_mobile/presentation/actions/action.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||
import 'package:immich_mobile/utils/asset_filter.dart';
|
||||
import 'package:immich_ui/immich_ui.dart';
|
||||
|
||||
class FavoriteAction extends AssetAction<RemoteAsset> {
|
||||
final bool shouldFavorite;
|
||||
final bool favorite;
|
||||
|
||||
FavoriteAction({required super.assets}) : shouldFavorite = assets.any((asset) => !asset.isFavorite);
|
||||
FavoriteAction({required super.assets}) : favorite = assets.any((asset) => !asset.isFavorite);
|
||||
|
||||
@override
|
||||
IconData get icon => shouldFavorite ? Icons.favorite_border_rounded : Icons.favorite_rounded;
|
||||
IconData get icon => favorite ? Icons.favorite_border_rounded : Icons.favorite_rounded;
|
||||
|
||||
@override
|
||||
String label(ActionScope scope) => shouldFavorite ? scope.context.t.favorite : scope.context.t.unfavorite;
|
||||
String label(ActionScope scope) => favorite ? scope.context.t.favorite : scope.context.t.unfavorite;
|
||||
|
||||
@override
|
||||
Iterable<RemoteAsset> filter(ActionScope scope) => assets
|
||||
.where(
|
||||
(asset) => asset is RemoteAsset && asset.ownerId == scope.authUser.id && asset.isFavorite == !shouldFavorite,
|
||||
)
|
||||
.cast<RemoteAsset>();
|
||||
Iterable<RemoteAsset> filter(ActionScope scope) =>
|
||||
AssetFilter(assets).owned(scope.authUser.id).favorite(isFavorite: !favorite);
|
||||
|
||||
@override
|
||||
bool isVisible(ActionScope scope) => filter(scope).isNotEmpty;
|
||||
@@ -31,8 +29,8 @@ class FavoriteAction extends AssetAction<RemoteAsset> {
|
||||
final ActionScope(:ref) = scope;
|
||||
final assets = filter(scope).map((asset) => asset.id).toList(growable: false);
|
||||
|
||||
await ref.read(assetServiceProvider).updateFavorite(assets, shouldFavorite);
|
||||
final message = shouldFavorite
|
||||
await ref.read(assetServiceProvider).updateFavorite(assets, favorite);
|
||||
final message = favorite
|
||||
? StaticTranslations.instance.favorite_action_prompt(count: assets.length)
|
||||
: StaticTranslations.instance.unfavorite_action_prompt(count: assets.length);
|
||||
snackbar.success(message);
|
||||
|
||||
@@ -1,17 +1,49 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/memory/memory_lane.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/tab_page.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/types.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/feature_message/feature_message_dialog.widget.dart';
|
||||
import 'package:immich_mobile/providers/feature_message.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/memory.provider.dart';
|
||||
|
||||
@RoutePage()
|
||||
class MainTimelinePage extends TabPage {
|
||||
class MainTimelinePage extends ConsumerStatefulWidget {
|
||||
const MainTimelinePage({super.key});
|
||||
|
||||
@override
|
||||
Widget scopeBuilder(BuildContext context, Widget child) => timelineChromeScope(context, child);
|
||||
ConsumerState<MainTimelinePage> createState() => _MainTimelinePageState();
|
||||
}
|
||||
|
||||
class _MainTimelinePageState extends ConsumerState<MainTimelinePage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final service = ref.read(featureMessageServiceProvider);
|
||||
if (!service.shouldShow()) {
|
||||
return;
|
||||
}
|
||||
|
||||
await service.markSeen();
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
await showFeatureMessageDialog(context);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
ProviderListenable<PageChromeContent> get content => timelineChromeProvider;
|
||||
Widget build(BuildContext context) {
|
||||
final hasMemories = ref.watch(driftMemoryFutureProvider.select((state) => state.value?.isNotEmpty ?? false));
|
||||
return Timeline(
|
||||
topSliverWidget: const SliverToBoxAdapter(child: DriftMemoryLane()),
|
||||
topSliverWidgetHeight: hasMemories ? 200 : 0,
|
||||
showStorageIndicator: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -5,70 +7,64 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/tab_page.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/types.dart';
|
||||
import 'package:immich_mobile/widgets/common/primary_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
||||
|
||||
@RoutePage()
|
||||
class DriftAlbumsPage extends TabPage {
|
||||
class DriftAlbumsPage extends ConsumerStatefulWidget {
|
||||
const DriftAlbumsPage({super.key});
|
||||
|
||||
@override
|
||||
ProviderListenable<PageChromeContent> get content => Provider<PageChromeContent>((ref) {
|
||||
ConsumerState<DriftAlbumsPage> createState() => _DriftAlbumsPageState();
|
||||
}
|
||||
|
||||
class _DriftAlbumsPageState extends ConsumerState<DriftAlbumsPage> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
Future<void> onRefresh() async {
|
||||
await ref.read(remoteAlbumProvider.notifier).refresh();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final albumCount = ref.watch(remoteAlbumProvider.select((state) => state.albums.length));
|
||||
final showScrollbar = albumCount > 20;
|
||||
|
||||
return PageChromeContent(
|
||||
final scrollView = CustomScrollView(
|
||||
controller: _scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
appBar: const PrimaryAppBar(
|
||||
snap: false,
|
||||
floating: false,
|
||||
pinned: true,
|
||||
showUploadButton: false,
|
||||
actions: [_CreateAlbumAction()],
|
||||
),
|
||||
viewportBuilder: (scrollView) => _AlbumRefreshWrapper(showScrollbar: showScrollbar, scrollView: scrollView),
|
||||
slivers: [const _AlbumSelectorSliver()],
|
||||
slivers: [
|
||||
ImmichSliverAppBar(
|
||||
snap: false,
|
||||
floating: false,
|
||||
pinned: true,
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () => context.pushRoute(const DriftCreateAlbumRoute()),
|
||||
icon: const Icon(Icons.add_rounded),
|
||||
),
|
||||
],
|
||||
showUploadButton: false,
|
||||
),
|
||||
AlbumSelector(
|
||||
onAlbumSelected: (album) {
|
||||
context.router.push(RemoteAlbumRoute(album: album));
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
class _CreateAlbumAction extends StatelessWidget {
|
||||
const _CreateAlbumAction();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: () => context.pushRoute(const DriftCreateAlbumRoute()),
|
||||
icon: const Icon(Icons.add_rounded),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AlbumSelectorSliver extends StatelessWidget {
|
||||
const _AlbumSelectorSliver();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlbumSelector(onAlbumSelected: (album) => context.router.push(RemoteAlbumRoute(album: album)));
|
||||
}
|
||||
}
|
||||
|
||||
class _AlbumRefreshWrapper extends ConsumerWidget {
|
||||
final bool showScrollbar;
|
||||
final CustomScrollView scrollView;
|
||||
|
||||
const _AlbumRefreshWrapper({required this.showScrollbar, required this.scrollView});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final controller = PrimaryScrollController.of(context);
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => ref.read(remoteAlbumProvider.notifier).refresh(),
|
||||
onRefresh: onRefresh,
|
||||
edgeOffset: 100,
|
||||
child: showScrollbar
|
||||
? RawScrollbar(
|
||||
controller: controller,
|
||||
controller: _scrollController,
|
||||
interactive: true,
|
||||
thickness: 8,
|
||||
radius: const Radius.circular(4),
|
||||
|
||||
@@ -16,23 +16,27 @@ import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/providers/user.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/tab_page.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/types.dart';
|
||||
import 'package:immich_mobile/widgets/common/primary_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
|
||||
@RoutePage()
|
||||
class DriftLibraryPage extends TabPage {
|
||||
class DriftLibraryPage extends ConsumerWidget {
|
||||
const DriftLibraryPage({super.key});
|
||||
|
||||
@override
|
||||
ProviderListenable<PageChromeContent> get content => Provider<PageChromeContent>((ref) {
|
||||
return const PageChromeContent(
|
||||
appBar: PrimaryAppBar(snap: false, floating: false, pinned: true, showUploadButton: false),
|
||||
slivers: [_ActionButtonGrid(), _CollectionCards(), _QuickAccessButtonList()],
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return const Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
ImmichSliverAppBar(snap: false, floating: false, pinned: true, showUploadButton: false),
|
||||
_ActionButtonGrid(),
|
||||
_CollectionCards(),
|
||||
_QuickAccessButtonList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _ActionButtonGrid extends ConsumerWidget {
|
||||
|
||||
@@ -7,7 +7,6 @@ import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/constants/enums.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/settings_key.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/generated/translations.g.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||
@@ -129,12 +128,6 @@ class ShareActionButton extends ConsumerWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
await ref.read(settingsProvider).write(SettingsKey.shareFileType, fileType);
|
||||
|
||||
if (!context.mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
await _share(context, ref, fileType);
|
||||
}
|
||||
|
||||
|
||||
@@ -745,10 +745,15 @@ class AddToAlbumHeader extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
Future<void> onCreateAlbum() async {
|
||||
final albumName = await showDialog<String?>(context: context, builder: (context) => const NewAlbumNameModal());
|
||||
if (albumName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final selectedAssets = ref.read(multiSelectProvider).selectedAssets;
|
||||
final newAlbum = await ref
|
||||
.read(remoteAlbumProvider.notifier)
|
||||
.createAlbumWithAssets(title: "Untitled Album", assets: selectedAssets);
|
||||
.createAlbumWithAssets(title: albumName, assets: selectedAssets);
|
||||
|
||||
if (newAlbum == null) {
|
||||
ImmichToast.show(context: context, toastType: ToastType.error, msg: 'errors.failed_to_create_album'.tr());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -63,7 +63,7 @@ class ViewerTopAppBar extends ConsumerWidget implements PreferredSizeWidget {
|
||||
|
||||
ActionIconButtonWidget(action: FavoriteAction(assets: assetForAction)),
|
||||
|
||||
ViewerKebabMenu(originalTheme: originalTheme),
|
||||
ImmichColorOverride(color: null, child: ViewerKebabMenu(originalTheme: originalTheme)),
|
||||
];
|
||||
|
||||
final lockedViewActions = <Widget>[ViewerKebabMenu(originalTheme: originalTheme)];
|
||||
|
||||
@@ -7,7 +7,6 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||
@@ -17,23 +16,17 @@ import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/download_status_floating_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/feature_message/feature_message_dialog.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/memory/memory_lane.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/scrubber.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/segment.model.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline_drag_region.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline_scroll.provider.dart';
|
||||
import 'package:immich_mobile/providers/feature_message.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/memory.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/types.dart';
|
||||
import 'package:immich_mobile/widgets/common/primary_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/selection_sliver_app_bar.dart';
|
||||
|
||||
class Timeline extends ConsumerWidget {
|
||||
@@ -44,7 +37,7 @@ class Timeline extends ConsumerWidget {
|
||||
this.bottomSliverWidget,
|
||||
this.showStorageIndicator = false,
|
||||
this.withStack = false,
|
||||
this.appBar = const PrimaryAppBar(floating: true, pinned: false, snap: false),
|
||||
this.appBar = const ImmichSliverAppBar(floating: true, pinned: false, snap: false),
|
||||
this.bottomSheet = const GeneralBottomSheet(minChildSize: 0.23),
|
||||
this.groupBy,
|
||||
this.withScrubber = true,
|
||||
@@ -755,225 +748,3 @@ class CustomScaleGestureRecognizer extends ScaleGestureRecognizer {
|
||||
acceptGesture(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PageChrome (Photos) path
|
||||
//
|
||||
// The shared `PageChrome` owns the Scaffold + scroll view + app bar. The
|
||||
// timeline contributes a [PageChromeContent] via [timelineChromeProvider],
|
||||
// read inside [timelineChromeScope] (which overrides `timelineArgsProvider`
|
||||
// from the real layout constraints). The controller/observer/scroll logic
|
||||
// lives in [timelineScrollProvider] so the chrome can read the controller
|
||||
// before it builds the scroll view (same frame).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Wraps the chrome body in the timeline's `ProviderScope`, overriding
|
||||
/// `timelineArgsProvider` from the actual scroll-view constraints via a
|
||||
/// `LayoutBuilder` (built during layout, so the value is real, not a guess).
|
||||
Widget timelineChromeScope(BuildContext context, Widget child) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final columnCount = ref.watch(appConfigProvider.select((config) => config.timeline.tilesPerRow));
|
||||
return ProviderScope(
|
||||
overrides: [
|
||||
timelineArgsProvider.overrideWithValue(
|
||||
TimelineArgs(
|
||||
maxWidth: constraints.maxWidth,
|
||||
maxHeight: constraints.maxHeight,
|
||||
columnCount: columnCount,
|
||||
showStorageIndicator: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
child: _TimelineChromePopScope(child: child),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Pops out of multiselect (instead of the route) while a selection is active.
|
||||
class _TimelineChromePopScope extends ConsumerWidget {
|
||||
final Widget child;
|
||||
|
||||
const _TimelineChromePopScope({required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled));
|
||||
return PopScope(
|
||||
canPop: !isMultiSelectEnabled,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (!didPop && isMultiSelectEnabled) {
|
||||
ref.read(multiSelectProvider.notifier).reset();
|
||||
}
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final timelineChromeProvider = Provider<PageChromeContent>((ref) {
|
||||
final scroll = ref.watch(timelineScrollProvider.notifier);
|
||||
final physics = ref.watch(timelineScrollProvider.select((s) => s.physics));
|
||||
final maxHeight = ref.watch(timelineArgsProvider.select((args) => args.maxHeight));
|
||||
final isSelectionMode = ref.watch(multiSelectProvider.select((s) => s.forceEnable));
|
||||
|
||||
return PageChromeContent(
|
||||
controller: scroll.controller,
|
||||
physics: physics,
|
||||
scrollCacheExtent: ScrollCacheExtent.pixels(maxHeight * 2),
|
||||
appBar: isSelectionMode
|
||||
? const SelectionSliverAppBar()
|
||||
: const PrimaryAppBar(floating: true, pinned: false, snap: false),
|
||||
slivers: const [_TimelineChromeContent()],
|
||||
viewportBuilder: (scrollView) => _TimelineChromeViewport(scrollView: scrollView),
|
||||
floatingActionButton: const DownloadStatusFloatingButton(),
|
||||
overlays: const [_TimelineChromeOverlays()],
|
||||
);
|
||||
}, dependencies: [timelineServiceProvider, timelineArgsProvider, timelineScrollProvider, multiSelectProvider]);
|
||||
|
||||
/// The timeline's content slivers (memory lane, the segmented grid, bottom
|
||||
/// padding). Mounted by the chrome inside its scroll view, so the ambient
|
||||
/// `PrimaryScrollController` is the chrome's controller.
|
||||
class _TimelineChromeContent extends ConsumerWidget {
|
||||
const _TimelineChromeContent();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// A reload event forces the grid to rebuild.
|
||||
ref.listen(timelineSegmentProvider, (_, __) {});
|
||||
|
||||
final asyncSegments = ref.watch(timelineSegmentProvider);
|
||||
final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled));
|
||||
final hasMemories = ref.watch(driftMemoryFutureProvider.select((state) => state.value?.isNotEmpty ?? false));
|
||||
|
||||
return asyncSegments.when(
|
||||
loading: () => const SliverToBoxAdapter(child: SizedBox.shrink()),
|
||||
error: (_, __) => const SliverToBoxAdapter(child: SizedBox.shrink()),
|
||||
data: (segments) {
|
||||
final childCount = (segments.lastOrNull?.lastIndex ?? -1) + 1;
|
||||
const bottomSheetOpenModifier = 120.0;
|
||||
final contentBottomPadding = context.padding.bottom + (isMultiSelectEnabled ? bottomSheetOpenModifier : 0);
|
||||
|
||||
return SliverMainAxisGroup(
|
||||
slivers: [
|
||||
if (hasMemories) const SliverToBoxAdapter(child: DriftMemoryLane()),
|
||||
_SliverSegmentedList(
|
||||
segments: segments,
|
||||
delegate: SliverChildBuilderDelegate((ctx, index) {
|
||||
if (index >= childCount) {
|
||||
return null;
|
||||
}
|
||||
final segment = segments.findByIndex(index);
|
||||
return segment?.builder(ctx, index) ?? const SizedBox.shrink();
|
||||
}, childCount: childCount, addAutomaticKeepAlives: false, addRepaintBoundaries: false),
|
||||
),
|
||||
SliverPadding(padding: EdgeInsets.only(bottom: contentBottomPadding)),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps the shared scroll view in the pinch-to-scale gesture, drag selection
|
||||
/// region and the scrubber.
|
||||
class _TimelineChromeViewport extends ConsumerWidget {
|
||||
final CustomScrollView scrollView;
|
||||
|
||||
const _TimelineChromeViewport({required this.scrollView});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final scroll = ref.read(timelineScrollProvider.notifier);
|
||||
final isReadonlyModeEnabled = ref.watch(readonlyModeProvider);
|
||||
final maxHeight = ref.watch(timelineArgsProvider.select((args) => args.maxHeight));
|
||||
final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled));
|
||||
final hasMemories = ref.watch(driftMemoryFutureProvider.select((state) => state.value?.isNotEmpty ?? false));
|
||||
final segments = ref.watch(timelineSegmentProvider).valueOrNull ?? const [];
|
||||
|
||||
final topPadding = context.padding.top + kToolbarHeight + 10;
|
||||
const bottomSheetOpenModifier = 120.0;
|
||||
final contentBottomPadding = context.padding.bottom + (isMultiSelectEnabled ? bottomSheetOpenModifier : 0);
|
||||
final scrubberBottomPadding = contentBottomPadding + kScrubberThumbHeight;
|
||||
|
||||
final timeline = Scrubber(
|
||||
layoutSegments: segments,
|
||||
timelineHeight: maxHeight,
|
||||
topPadding: topPadding,
|
||||
bottomPadding: scrubberBottomPadding,
|
||||
monthSegmentSnappingOffset: hasMemories ? 200 : 0,
|
||||
hasAppBar: true,
|
||||
child: scrollView,
|
||||
);
|
||||
|
||||
return RawGestureDetector(
|
||||
gestures: {
|
||||
CustomScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers<CustomScaleGestureRecognizer>(
|
||||
() => CustomScaleGestureRecognizer(),
|
||||
(CustomScaleGestureRecognizer recognizer) {
|
||||
recognizer.onStart = (_) => scroll.onScaleStart();
|
||||
recognizer.onUpdate = (details) => scroll.onScaleUpdate(details.scale, segments);
|
||||
},
|
||||
),
|
||||
},
|
||||
child: TimelineDragRegion(
|
||||
onStart: !isReadonlyModeEnabled ? scroll.setDragStartIndex : null,
|
||||
onAssetEnter: scroll.handleDragAssetEnter,
|
||||
onEnd: !isReadonlyModeEnabled ? scroll.stopDrag : null,
|
||||
onScroll: scroll.dragScroll,
|
||||
onScrollStart: scroll.onScrollStart,
|
||||
child: timeline,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The multiselect status button + bottom sheet stacked on top of the timeline.
|
||||
class _TimelineChromeOverlays extends HookConsumerWidget {
|
||||
const _TimelineChromeOverlays();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// Show the "what's new" feature message once, when the timeline mounts.
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
if (!context.mounted) {
|
||||
return;
|
||||
}
|
||||
final service = ref.read(featureMessageServiceProvider);
|
||||
if (!service.shouldShow()) {
|
||||
return;
|
||||
}
|
||||
await service.markSeen();
|
||||
if (!context.mounted) {
|
||||
return;
|
||||
}
|
||||
await showFeatureMessageDialog(context);
|
||||
});
|
||||
return null;
|
||||
}, const []);
|
||||
|
||||
final isSelectionMode = ref.watch(multiSelectProvider.select((s) => s.forceEnable));
|
||||
final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled));
|
||||
final isVisible = !isSelectionMode && isMultiSelectEnabled;
|
||||
if (!isVisible) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned(
|
||||
top: MediaQuery.paddingOf(context).top,
|
||||
left: 25,
|
||||
child: const SizedBox(height: kToolbarHeight, child: Center(child: _MultiSelectStatusButton())),
|
||||
),
|
||||
const GeneralBottomSheet(minChildSize: 0.23),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||
import 'package:immich_mobile/domain/models/settings_key.dart';
|
||||
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/segment.model.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline_drag_region.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||
|
||||
/// Transient interaction state of the chrome timeline that drives rebuilds of
|
||||
/// the content slivers + viewport (scale/drag/physics).
|
||||
class TimelineScrollState {
|
||||
final int perRow;
|
||||
final double scaleFactor;
|
||||
final bool dragging;
|
||||
final ScrollPhysics? physics;
|
||||
|
||||
const TimelineScrollState({this.perRow = 4, this.scaleFactor = 3.0, this.dragging = false, this.physics});
|
||||
|
||||
TimelineScrollState copyWith({int? perRow, double? scaleFactor, bool? dragging, ScrollPhysics? physics}) {
|
||||
return TimelineScrollState(
|
||||
perRow: perRow ?? this.perRow,
|
||||
scaleFactor: scaleFactor ?? this.scaleFactor,
|
||||
dragging: dragging ?? this.dragging,
|
||||
// physics is nullable-by-design; pass explicitly to clear.
|
||||
physics: physics,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Owns the chrome timeline's [ScrollController] and everything bound to it:
|
||||
/// the iOS status-bar-tap observer, the scroll event subscription, position
|
||||
/// restore, pinch-to-scale and drag-selection logic.
|
||||
///
|
||||
/// This lives in a provider (not a widget [State]) so the shared `PageChrome`
|
||||
/// can read the controller *before* it builds the scroll view, keeping the
|
||||
/// timeline's chrome same-frame. Scoped under the timeline's `ProviderScope`
|
||||
/// (via [timelineServiceProvider]/[timelineArgsProvider]) so each timeline gets
|
||||
/// its own instance.
|
||||
class TimelineScrollController extends Notifier<TimelineScrollState> with WidgetsBindingObserver {
|
||||
late final ScrollController controller;
|
||||
StreamSubscription? _eventSubscription;
|
||||
|
||||
// Drag selection
|
||||
TimelineAssetIndex? _dragAnchorIndex;
|
||||
final Set<BaseAsset> _draggedAssets = HashSet();
|
||||
|
||||
double _baseScaleFactor = 3.0;
|
||||
int? _restoreAssetIndex;
|
||||
|
||||
@override
|
||||
TimelineScrollState build() {
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
controller = ScrollController(onAttach: _restoreAssetPosition);
|
||||
_eventSubscription = EventStream.shared.listen(_onEvent);
|
||||
|
||||
final perRow = ref.read(appConfigProvider.select((config) => config.timeline.tilesPerRow));
|
||||
_baseScaleFactor = 7.0 - perRow;
|
||||
|
||||
ref.listen(multiSelectProvider.select((s) => s.isEnabled), _onMultiSelectionToggled);
|
||||
|
||||
// Remember scroll position across width changes (orientation / rail toggle)
|
||||
// so it can be restored after the segments regenerate.
|
||||
ref.listen(timelineArgsProvider.select((a) => a.maxWidth), (previous, next) {
|
||||
if (previous != null && previous != next) {
|
||||
final segments = ref.read(timelineSegmentProvider).valueOrNull;
|
||||
if (segments != null && controller.hasClients) {
|
||||
_restoreAssetIndex = _getCurrentAssetIndex(segments);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
controller.dispose();
|
||||
_eventSubscription?.cancel();
|
||||
});
|
||||
|
||||
return TimelineScrollState(perRow: perRow, scaleFactor: _baseScaleFactor);
|
||||
}
|
||||
|
||||
// Capture iOS status bar tap
|
||||
@override
|
||||
void handleStatusBarTap() => scrollToTop();
|
||||
|
||||
void _onEvent(Event event) {
|
||||
switch (event) {
|
||||
case ScrollToTopEvent():
|
||||
scrollToTop();
|
||||
case ScrollToDateEvent scrollToDateEvent:
|
||||
scrollToDate(scrollToDateEvent.date);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _restoreAssetPosition(_) {
|
||||
if (_restoreAssetIndex == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final asyncSegments = ref.read(timelineSegmentProvider);
|
||||
asyncSegments.whenData((segments) {
|
||||
final targetSegment = segments.lastWhereOrNull((segment) => segment.firstAssetIndex <= _restoreAssetIndex!);
|
||||
if (targetSegment != null) {
|
||||
final assetIndexInSegment = _restoreAssetIndex! - targetSegment.firstAssetIndex;
|
||||
final newColumnCount = ref.read(timelineArgsProvider).columnCount;
|
||||
final rowIndexInSegment = (assetIndexInSegment / newColumnCount).floor();
|
||||
final targetRowIndex = targetSegment.firstIndex + 1 + rowIndexInSegment;
|
||||
final targetOffset = targetSegment.indexToLayoutOffset(targetRowIndex);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (controller.hasClients) {
|
||||
controller.jumpTo(targetOffset.clamp(0.0, controller.position.maxScrollExtent));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
_restoreAssetIndex = null;
|
||||
}
|
||||
|
||||
void _onMultiSelectionToggled(_, bool isEnabled) {
|
||||
EventStream.shared.emit(MultiSelectToggleEvent(isEnabled));
|
||||
}
|
||||
|
||||
int? getCurrentAssetIndex(List<Segment> segments) => _getCurrentAssetIndex(segments);
|
||||
|
||||
int? _getCurrentAssetIndex(List<Segment> segments) {
|
||||
final currentOffset = controller.offset.clamp(0.0, controller.position.maxScrollExtent);
|
||||
final segment = segments.findByOffset(currentOffset) ?? segments.lastOrNull;
|
||||
int? targetAssetIndex;
|
||||
if (segment != null) {
|
||||
final rowIndex = segment.getMinChildIndexForScrollOffset(currentOffset);
|
||||
if (rowIndex > segment.firstIndex) {
|
||||
final rowIndexInSegment = rowIndex - (segment.firstIndex + 1);
|
||||
final assetsPerRow = ref.read(timelineArgsProvider).columnCount;
|
||||
final assetIndexInSegment = rowIndexInSegment * assetsPerRow;
|
||||
targetAssetIndex = segment.firstAssetIndex + assetIndexInSegment;
|
||||
} else {
|
||||
targetAssetIndex = segment.firstAssetIndex;
|
||||
}
|
||||
}
|
||||
return targetAssetIndex;
|
||||
}
|
||||
|
||||
void scrollToTop() {
|
||||
if (!controller.hasClients) {
|
||||
return;
|
||||
}
|
||||
|
||||
final timelineState = ref.read(timelineStateProvider.notifier);
|
||||
timelineState.setScrubbing(true);
|
||||
controller
|
||||
.animateTo(0, duration: const Duration(milliseconds: 250), curve: Curves.easeInOut)
|
||||
.whenComplete(() => timelineState.setScrubbing(false));
|
||||
}
|
||||
|
||||
void scrollToDate(DateTime date) {
|
||||
final timelineState = ref.read(timelineStateProvider.notifier);
|
||||
final asyncSegments = ref.read(timelineSegmentProvider);
|
||||
asyncSegments.whenData((segments) {
|
||||
final targetSegment = segments.firstWhereOrNull((segment) {
|
||||
if (segment.bucket is TimeBucket) {
|
||||
final segmentDate = (segment.bucket as TimeBucket).date;
|
||||
return segmentDate.year == date.year && segmentDate.month == date.month && segmentDate.day == date.day;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
final fallbackSegment =
|
||||
targetSegment ??
|
||||
segments.firstWhereOrNull((segment) {
|
||||
if (segment.bucket is TimeBucket) {
|
||||
final segmentDate = (segment.bucket as TimeBucket).date;
|
||||
return segmentDate.year == date.year && segmentDate.month == date.month;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (fallbackSegment != null) {
|
||||
final targetOffset = fallbackSegment.startOffset - 50;
|
||||
timelineState.setScrubbing(true);
|
||||
controller
|
||||
.animateTo(
|
||||
targetOffset.clamp(0.0, controller.position.maxScrollExtent),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
)
|
||||
.whenComplete(() => timelineState.setScrubbing(false));
|
||||
} else {
|
||||
timelineState.setScrubbing(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Pinch to scale
|
||||
void onScaleStart() {
|
||||
_baseScaleFactor = state.scaleFactor;
|
||||
}
|
||||
|
||||
void onScaleUpdate(double scale, List<Segment> segments) {
|
||||
final newScaleFactor = math.max(math.min(5.0, _baseScaleFactor * scale), 1.0);
|
||||
final newPerRow = 7 - newScaleFactor.toInt();
|
||||
if (newPerRow != state.perRow) {
|
||||
_restoreAssetIndex = _getCurrentAssetIndex(segments);
|
||||
state = state.copyWith(scaleFactor: newScaleFactor, perRow: newPerRow, physics: state.physics);
|
||||
ref.read(settingsProvider).write(SettingsKey.timelineTilesPerRow, newPerRow);
|
||||
}
|
||||
}
|
||||
|
||||
// Drag selection
|
||||
void setDragStartIndex(TimelineAssetIndex index) {
|
||||
_dragAnchorIndex = index;
|
||||
state = state.copyWith(dragging: true, physics: const ClampingScrollPhysics());
|
||||
}
|
||||
|
||||
void stopDrag() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// Reset physics post frame to prevent a sudden change on iOS.
|
||||
state = state.copyWith(dragging: state.dragging, physics: null);
|
||||
});
|
||||
_draggedAssets.clear();
|
||||
state = state.copyWith(dragging: false, physics: state.physics);
|
||||
final timelineState = ref.read(timelineStateProvider.notifier);
|
||||
Future.delayed(const Duration(milliseconds: 300), () {
|
||||
timelineState.setScrolling(false);
|
||||
});
|
||||
}
|
||||
|
||||
void dragScroll(ScrollDirection direction) {
|
||||
controller.animateTo(
|
||||
controller.offset + (direction == ScrollDirection.forward ? 175 : -175),
|
||||
duration: const Duration(milliseconds: 125),
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
}
|
||||
|
||||
void onScrollStart() {
|
||||
ref.read(timelineStateProvider.notifier).setScrolling(true);
|
||||
}
|
||||
|
||||
void handleDragAssetEnter(TimelineAssetIndex index) {
|
||||
if (_dragAnchorIndex == null || !state.dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
final timelineService = ref.read(timelineServiceProvider);
|
||||
final dragAnchorIndex = _dragAnchorIndex!;
|
||||
|
||||
final startIndex = math.min(dragAnchorIndex.assetIndex, index.assetIndex);
|
||||
final endIndex = math.max(dragAnchorIndex.assetIndex, index.assetIndex);
|
||||
final count = endIndex - startIndex + 1;
|
||||
|
||||
if (timelineService.hasRange(startIndex, count)) {
|
||||
final selectedAssets = timelineService.getAssets(startIndex, count);
|
||||
final multiSelectNotifier = ref.read(multiSelectProvider.notifier);
|
||||
for (final asset in _draggedAssets) {
|
||||
multiSelectNotifier.deselectAsset(asset);
|
||||
}
|
||||
_draggedAssets.clear();
|
||||
for (final asset in selectedAssets) {
|
||||
multiSelectNotifier.selectAsset(asset);
|
||||
_draggedAssets.add(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final timelineScrollProvider = NotifierProvider<TimelineScrollController, TimelineScrollState>(
|
||||
TimelineScrollController.new,
|
||||
dependencies: [timelineServiceProvider, timelineArgsProvider, multiSelectProvider, timelineSegmentProvider],
|
||||
);
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)
|
||||
|
||||
22
mobile/lib/utils/asset_filter.dart
Normal file
22
mobile/lib/utils/asset_filter.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
|
||||
extension type const AssetFilter<T extends BaseAsset>(Iterable<T> assets) implements Iterable<T> {
|
||||
AssetFilter<T> where(bool Function(T asset) test) => AssetFilter(assets.where(test));
|
||||
AssetFilter<T> whereNot(bool Function(T asset) test) => AssetFilter(assets.where((asset) => !test(asset)));
|
||||
|
||||
AssetFilter<T> type(AssetType type) => where((asset) => asset.type == type);
|
||||
AssetFilter<T> favorite({bool isFavorite = true}) => where((asset) => asset.isFavorite == isFavorite);
|
||||
|
||||
AssetFilter<RemoteAsset> remote() => AssetFilter(assets.whereType<RemoteAsset>());
|
||||
AssetFilter<RemoteAsset> owned(String ownerId) => remote().where((asset) => asset.ownerId == ownerId);
|
||||
AssetFilter<RemoteAsset> visibility(AssetVisibility visibility) =>
|
||||
remote().where((asset) => asset.visibility == visibility);
|
||||
AssetFilter<RemoteAsset> notVisibility(AssetVisibility visibility) =>
|
||||
remote().where((asset) => asset.visibility != visibility);
|
||||
AssetFilter<RemoteAsset> archived({bool isArchived = true}) =>
|
||||
remote().where((asset) => asset.isArchived == isArchived);
|
||||
AssetFilter<RemoteAsset> stacked({bool isStacked = true}) => remote().where((asset) => asset.isStacked == isStacked);
|
||||
|
||||
AssetFilter<LocalAsset> local() => AssetFilter(assets.whereType<LocalAsset>());
|
||||
AssetFilter<LocalAsset> backedUp() => local().where((asset) => asset.remoteAssetId != null);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -20,23 +20,17 @@ import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/widgets/asset_viewer/cast_dialog.dart';
|
||||
import 'package:immich_mobile/widgets/common/app_bar_dialog/app_bar_dialog.dart';
|
||||
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
|
||||
import 'package:immich_ui/immich_ui.dart';
|
||||
|
||||
/// The app's standard app bar. Composes Immich-specific indicators (sync,
|
||||
/// backup, profile, cast) and the multiselect dim behaviour onto the generic
|
||||
/// [ImmichSliverAppBar] primitive from the ui package.
|
||||
class PrimaryAppBar extends ConsumerWidget {
|
||||
class ImmichSliverAppBar extends ConsumerWidget {
|
||||
final List<Widget>? actions;
|
||||
final bool showUploadButton;
|
||||
final bool floating;
|
||||
final bool pinned;
|
||||
final bool snap;
|
||||
final Widget? title;
|
||||
final Widget? leading;
|
||||
final bool automaticallyImplyLeading;
|
||||
final double? expandedHeight;
|
||||
|
||||
const PrimaryAppBar({
|
||||
const ImmichSliverAppBar({
|
||||
super.key,
|
||||
this.actions,
|
||||
this.showUploadButton = true,
|
||||
@@ -44,8 +38,6 @@ class PrimaryAppBar extends ConsumerWidget {
|
||||
this.pinned = false,
|
||||
this.snap = true,
|
||||
this.title,
|
||||
this.leading,
|
||||
this.automaticallyImplyLeading = false,
|
||||
this.expandedHeight,
|
||||
});
|
||||
|
||||
@@ -55,27 +47,38 @@ class PrimaryAppBar extends ConsumerWidget {
|
||||
final isReadonlyModeEnabled = ref.watch(readonlyModeProvider);
|
||||
final isMultiSelectEnabled = ref.watch(multiSelectProvider.select((s) => s.isEnabled));
|
||||
|
||||
return ImmichSliverAppBar(
|
||||
floating: floating,
|
||||
pinned: pinned,
|
||||
snap: snap,
|
||||
expandedHeight: expandedHeight,
|
||||
dimmed: isMultiSelectEnabled,
|
||||
automaticallyImplyLeading: automaticallyImplyLeading,
|
||||
leading: leading,
|
||||
title: title ?? const _ImmichLogoWithText(),
|
||||
actions: [
|
||||
const _SyncStatusIndicator(),
|
||||
if (isCasting && !isReadonlyModeEnabled)
|
||||
IconButton(
|
||||
onPressed: () => showDialog(context: context, builder: (context) => const CastDialog()),
|
||||
icon: Icon(isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded),
|
||||
),
|
||||
if (actions != null) ...actions!,
|
||||
if (showUploadButton && !isReadonlyModeEnabled) const _BackupIndicator(),
|
||||
const _ProfileIndicator(),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
return SliverIgnorePointer(
|
||||
ignoring: isMultiSelectEnabled,
|
||||
sliver: SliverAnimatedOpacity(
|
||||
duration: Durations.medium1,
|
||||
opacity: isMultiSelectEnabled ? 0 : 1,
|
||||
sliver: SliverAppBar(
|
||||
backgroundColor: context.colorScheme.surface,
|
||||
surfaceTintColor: context.colorScheme.surfaceTint,
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 1.0,
|
||||
floating: floating,
|
||||
pinned: pinned,
|
||||
snap: snap,
|
||||
expandedHeight: expandedHeight,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(5))),
|
||||
automaticallyImplyLeading: false,
|
||||
centerTitle: false,
|
||||
title: title ?? const _ImmichLogoWithText(),
|
||||
actions: [
|
||||
const _SyncStatusIndicator(),
|
||||
if (isCasting && !isReadonlyModeEnabled)
|
||||
IconButton(
|
||||
onPressed: () => showDialog(context: context, builder: (context) => const CastDialog()),
|
||||
icon: Icon(isCasting ? Icons.cast_connected_rounded : Icons.cast_rounded),
|
||||
),
|
||||
if (actions != null) ...actions!,
|
||||
if (showUploadButton && !isReadonlyModeEnabled) const _BackupIndicator(),
|
||||
const _ProfileIndicator(),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/types.dart';
|
||||
|
||||
/// The shared page chrome. Authored once; tabs never instantiate it directly
|
||||
/// (they extend `TabPage`, whose `build` renders this beneath the tab's scope).
|
||||
///
|
||||
/// Owns the [Scaffold], the single [CustomScrollView] and its
|
||||
/// [PrimaryScrollController]. Reads the active tab's [PageChromeContent] from
|
||||
/// [content] (available in the same frame, since this is a descendant of the
|
||||
/// tab's scope) and renders its app bar + content slivers.
|
||||
class PageChrome extends ConsumerStatefulWidget {
|
||||
final ProviderListenable<PageChromeContent> content;
|
||||
|
||||
const PageChrome({super.key, required this.content});
|
||||
|
||||
@override
|
||||
ConsumerState<PageChrome> createState() => _PageChromeState();
|
||||
}
|
||||
|
||||
class _PageChromeState extends ConsumerState<PageChrome> {
|
||||
ScrollController? _ownController;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_ownController?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final content = ref.watch(widget.content);
|
||||
|
||||
// The tab's controller, or a chrome-owned default created lazily.
|
||||
final controller = content.controller ?? (_ownController ??= ScrollController());
|
||||
|
||||
final scrollView = CustomScrollView(
|
||||
controller: controller,
|
||||
physics: content.physics,
|
||||
scrollCacheExtent: content.scrollCacheExtent,
|
||||
slivers: [content.appBar, ...content.slivers],
|
||||
);
|
||||
|
||||
Widget body = content.viewportBuilder != null ? content.viewportBuilder!(scrollView) : scrollView;
|
||||
|
||||
if (content.overlays.isNotEmpty) {
|
||||
body = Stack(clipBehavior: Clip.none, children: [body, ...content.overlays]);
|
||||
}
|
||||
|
||||
body = Scaffold(
|
||||
// Removes the built-in Scaffold `handleStatusBarTap`, avoiding duplicate
|
||||
// events when a tab (e.g. the timeline) provides its own.
|
||||
primary: false,
|
||||
resizeToAvoidBottomInset: false,
|
||||
floatingActionButton: content.floatingActionButton,
|
||||
body: body,
|
||||
);
|
||||
|
||||
// The chrome owns the single scroll view; mark its controller primary so
|
||||
// the scrubber's `PrimaryScrollController.of` and iOS status-bar-tap both
|
||||
// resolve it. Wrapping the Scaffold preserves status-bar-tap resolution.
|
||||
return PrimaryScrollController(controller: controller, child: body);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/page_chrome.dart';
|
||||
import 'package:immich_mobile/widgets/common/page_chrome/types.dart';
|
||||
|
||||
/// The base type for a page rendered as a primary tab.
|
||||
///
|
||||
/// Extending [TabPage] is the *only* place that knows the page is a tab: a
|
||||
/// subclass declares its chrome [content] provider and, if needed, the
|
||||
/// [scopeBuilder] the provider must be read within. The [PageChrome] is
|
||||
/// rendered automatically beneath that scope, so it reads the tab's content
|
||||
/// provider as a descendant (same frame). Nothing beneath the chrome has any
|
||||
/// knowledge of tabs.
|
||||
abstract class TabPage extends ConsumerWidget {
|
||||
const TabPage({super.key});
|
||||
|
||||
/// The provider that yields this tab's chrome content (app bar + slivers +
|
||||
/// controller + decorators). Read beneath [scopeBuilder].
|
||||
ProviderListenable<PageChromeContent> get content;
|
||||
|
||||
/// Produces the scope the [content] provider must be read within (e.g. the
|
||||
/// timeline's `LayoutBuilder` + `timelineArgsProvider` override). Defaults to
|
||||
/// the identity scope.
|
||||
Widget scopeBuilder(BuildContext context, Widget child) => child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return scopeBuilder(context, PageChrome(content: content));
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
/// Everything a tab contributes to the single shared `PageChrome`.
|
||||
///
|
||||
/// Published per-tab via a `Provider<PageChromeContent>`; the chrome reads the
|
||||
/// active tab's value (within that tab's scope) and renders it. Data flows
|
||||
/// downward, so the chrome renders with the active tab's content in the same
|
||||
/// frame.
|
||||
class PageChromeContent {
|
||||
/// The app bar sliver placed first in the shared scroll view. The tab decides
|
||||
/// which bar it wants (e.g. a primary bar, or a selection bar during
|
||||
/// multiselect).
|
||||
final Widget appBar;
|
||||
|
||||
/// The tab's content slivers, rendered after [appBar].
|
||||
final List<Widget> slivers;
|
||||
|
||||
/// Scroll controller for the shared scroll view. Provided by the tab when it
|
||||
/// needs custom behaviour (e.g. the timeline's position restore). When `null`,
|
||||
/// the chrome creates and owns a default controller.
|
||||
final ScrollController? controller;
|
||||
|
||||
/// Optionally decorates the shared scroll view, e.g. wrapping it in the
|
||||
/// timeline's `Scrubber`. Receives the built scroll view and returns the
|
||||
/// widget to place in the body.
|
||||
final Widget Function(CustomScrollView scrollView)? viewportBuilder;
|
||||
|
||||
final Widget? floatingActionButton;
|
||||
|
||||
/// Widgets stacked on top of the scroll view (e.g. bottom sheet, multiselect
|
||||
/// status button).
|
||||
final List<Widget> overlays;
|
||||
|
||||
final ScrollPhysics? physics;
|
||||
|
||||
/// Forwarded to the shared [CustomScrollView] (e.g. the timeline's larger
|
||||
/// cache extent).
|
||||
final ScrollCacheExtent? scrollCacheExtent;
|
||||
|
||||
const PageChromeContent({
|
||||
required this.appBar,
|
||||
this.slivers = const [],
|
||||
this.controller,
|
||||
this.viewportBuilder,
|
||||
this.floatingActionButton,
|
||||
this.overlays = const [],
|
||||
this.physics,
|
||||
this.scrollCacheExtent,
|
||||
});
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
7.22.0
|
||||
7.24.0
|
||||
|
||||
4
mobile/openapi/README.md
generated
4
mobile/openapi/README.md
generated
@@ -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
|
||||
|
||||
|
||||
4
mobile/openapi/lib/api_client.dart
generated
4
mobile/openapi/lib/api_client.dart
generated
@@ -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;
|
||||
|
||||
44
mobile/openapi/lib/model/album_user_role.dart
generated
44
mobile/openapi/lib/model/album_user_role.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
44
mobile/openapi/lib/model/asset_edit_action.dart
generated
44
mobile/openapi/lib/model/asset_edit_action.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
44
mobile/openapi/lib/model/asset_id_error_reason.dart
generated
44
mobile/openapi/lib/model/asset_id_error_reason.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
47
mobile/openapi/lib/model/asset_job_name.dart
generated
47
mobile/openapi/lib/model/asset_job_name.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
47
mobile/openapi/lib/model/asset_media_size.dart
generated
47
mobile/openapi/lib/model/asset_media_size.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/asset_media_status.dart
generated
41
mobile/openapi/lib/model/asset_media_status.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/asset_order.dart
generated
41
mobile/openapi/lib/model/asset_order.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/asset_order_by.dart
generated
41
mobile/openapi/lib/model/asset_order_by.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/asset_reject_reason.dart
generated
41
mobile/openapi/lib/model/asset_reject_reason.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
47
mobile/openapi/lib/model/asset_type_enum.dart
generated
47
mobile/openapi/lib/model/asset_type_enum.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/asset_upload_action.dart
generated
41
mobile/openapi/lib/model/asset_upload_action.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
47
mobile/openapi/lib/model/asset_visibility.dart
generated
47
mobile/openapi/lib/model/asset_visibility.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
47
mobile/openapi/lib/model/audio_codec.dart
generated
47
mobile/openapi/lib/model/audio_codec.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
50
mobile/openapi/lib/model/bulk_id_error_reason.dart
generated
50
mobile/openapi/lib/model/bulk_id_error_reason.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/calendar_heatmap_type.dart
generated
41
mobile/openapi/lib/model/calendar_heatmap_type.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/colorspace.dart
generated
41
mobile/openapi/lib/model/colorspace.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
44
mobile/openapi/lib/model/cq_mode.dart
generated
44
mobile/openapi/lib/model/cq_mode.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
50
mobile/openapi/lib/model/hls_video_resolution.dart
generated
50
mobile/openapi/lib/model/hls_video_resolution.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
41
mobile/openapi/lib/model/image_format.dart
generated
41
mobile/openapi/lib/model/image_format.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
44
mobile/openapi/lib/model/integrity_report.dart
generated
44
mobile/openapi/lib/model/integrity_report.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
233
mobile/openapi/lib/model/job_name.dart
generated
233
mobile/openapi/lib/model/job_name.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
53
mobile/openapi/lib/model/log_level.dart
generated
53
mobile/openapi/lib/model/log_level.dart
generated
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user