mirror of
https://github.com/immich-app/immich.git
synced 2025-12-14 08:40:42 -08:00
Compare commits
1 Commits
feat/widge
...
fix/web-no
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e62071fda0 |
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -461,7 +461,7 @@ jobs:
|
|||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Install Playwright Browsers
|
- name: Install Playwright Browsers
|
||||||
run: npx playwright install chromium --only-shell
|
run: npx playwright install --with-deps chromium
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Docker build
|
- name: Docker build
|
||||||
@@ -644,7 +644,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.1
|
||||||
env:
|
env:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
|
|||||||
6
cli/package-lock.json
generated
6
cli/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^4.0.3",
|
"chokidar": "^4.0.3",
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"description": "Command Line Interface (CLI) for Immich",
|
"description": "Command Line Interface (CLI) for Immich",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": "./dist/index.js",
|
"exports": "./dist/index.js",
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ services:
|
|||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.2-pgvectors0.2.0
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ services:
|
|||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.2-pgvectors0.2.0
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
|
|
||||||
database:
|
database:
|
||||||
container_name: immich_postgres
|
container_name: immich_postgres
|
||||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
|
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.2-pgvectors0.2.0
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
POSTGRES_USER: ${DB_USERNAME}
|
POSTGRES_USER: ${DB_USERNAME}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ alt="Dot Env Example"
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
- Change the default `DB_PASSWORD`, and add custom database connection information if necessary.
|
- Change the default `DB_PASSWORD`, and add custom database connection information if necessary.
|
||||||
- Change `DB_DATA_LOCATION` to a folder (absolute path) where the database will be saved to disk.
|
- Change `DB_DATA_LOCATION` to a folder where the database will be saved to disk.
|
||||||
- Change `UPLOAD_LOCATION` to a folder (absolute path) where media (uploaded and generated) will be stored.
|
- Change `UPLOAD_LOCATION` to a folder where media (uploaded and generated) will be stored.
|
||||||
|
|
||||||
11. Click on "**Deploy the stack**".
|
11. Click on "**Deploy the stack**".
|
||||||
|
|
||||||
|
|||||||
12
docs/static/archived-versions.json
vendored
12
docs/static/archived-versions.json
vendored
@@ -1,16 +1,4 @@
|
|||||||
[
|
[
|
||||||
{
|
|
||||||
"label": "v1.135.3",
|
|
||||||
"url": "https://v1.135.3.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.2",
|
|
||||||
"url": "https://v1.135.2.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "v1.135.1",
|
|
||||||
"url": "https://v1.135.1.archive.immich.app"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "v1.135.0",
|
"label": "v1.135.0",
|
||||||
"url": "https://v1.135.0.archive.immich.app"
|
"url": "https://v1.135.0.archive.immich.app"
|
||||||
|
|||||||
8
e2e/package-lock.json
generated
8
e2e/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
},
|
},
|
||||||
"../cli": {
|
"../cli": {
|
||||||
"name": "@immich/cli",
|
"name": "@immich/cli",
|
||||||
"version": "2.2.72",
|
"version": "2.2.69",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
},
|
},
|
||||||
"../open-api/typescript-sdk": {
|
"../open-api/typescript-sdk": {
|
||||||
"name": "@immich/sdk",
|
"name": "@immich/sdk",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "GNU Affero General Public License version 3",
|
"license": "GNU Affero General Public License version 3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "immich-e2e",
|
"name": "immich-e2e",
|
||||||
"version": "1.135.3",
|
"version": "1.135.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ describe('/people', () => {
|
|||||||
let nameAlicePerson: PersonResponseDto;
|
let nameAlicePerson: PersonResponseDto;
|
||||||
let nameBobPerson: PersonResponseDto;
|
let nameBobPerson: PersonResponseDto;
|
||||||
let nameCharliePerson: PersonResponseDto;
|
let nameCharliePerson: PersonResponseDto;
|
||||||
let nameNullPerson4Assets: PersonResponseDto;
|
let nameNullPerson: PersonResponseDto;
|
||||||
let nameNullPerson3Assets: PersonResponseDto;
|
|
||||||
let nameNullPerson1Asset: PersonResponseDto;
|
|
||||||
let nameBillPersonFavourite: PersonResponseDto;
|
|
||||||
let nameFreddyPersonFavourite: PersonResponseDto;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await utils.resetDatabase();
|
await utils.resetDatabase();
|
||||||
@@ -31,11 +27,7 @@ describe('/people', () => {
|
|||||||
nameCharliePerson,
|
nameCharliePerson,
|
||||||
nameBobPerson,
|
nameBobPerson,
|
||||||
nameAlicePerson,
|
nameAlicePerson,
|
||||||
nameNullPerson4Assets,
|
nameNullPerson,
|
||||||
nameNullPerson3Assets,
|
|
||||||
nameNullPerson1Asset,
|
|
||||||
nameBillPersonFavourite,
|
|
||||||
nameFreddyPersonFavourite,
|
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
utils.createPerson(admin.accessToken, {
|
utils.createPerson(admin.accessToken, {
|
||||||
name: 'visible_person',
|
name: 'visible_person',
|
||||||
@@ -60,26 +52,11 @@ describe('/people', () => {
|
|||||||
utils.createPerson(admin.accessToken, {
|
utils.createPerson(admin.accessToken, {
|
||||||
name: '',
|
name: '',
|
||||||
}),
|
}),
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: '',
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: '',
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: 'Bill',
|
|
||||||
isFavorite: true,
|
|
||||||
}),
|
|
||||||
utils.createPerson(admin.accessToken, {
|
|
||||||
name: 'Freddy',
|
|
||||||
isFavorite: true,
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const asset1 = await utils.createAsset(admin.accessToken);
|
const asset1 = await utils.createAsset(admin.accessToken);
|
||||||
const asset2 = await utils.createAsset(admin.accessToken);
|
const asset2 = await utils.createAsset(admin.accessToken);
|
||||||
const asset3 = await utils.createAsset(admin.accessToken);
|
const asset3 = await utils.createAsset(admin.accessToken);
|
||||||
const asset4 = await utils.createAsset(admin.accessToken);
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
||||||
@@ -87,27 +64,15 @@ describe('/people', () => {
|
|||||||
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
|
utils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
|
||||||
utils.createFace({ assetId: asset3.id, personId: multipleAssetsPerson.id }), // 4 assets
|
utils.createFace({ assetId: asset3.id, personId: multipleAssetsPerson.id }),
|
||||||
// Named persons
|
// Named persons
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
|
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
|
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
|
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
|
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
|
||||||
// Null-named person 4 assets
|
// Null-named person
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson4Assets.id }),
|
utils.createFace({ assetId: asset1.id, personId: nameNullPerson.id }),
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson4Assets.id }),
|
utils.createFace({ assetId: asset2.id, personId: nameNullPerson.id }), // 2 assets
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson4Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset4.id, personId: nameNullPerson4Assets.id }), // 4 assets
|
|
||||||
// Null-named person 3 assets
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameNullPerson3Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameNullPerson3Assets.id }),
|
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson3Assets.id }), // 3 assets
|
|
||||||
// Null-named person 1 asset
|
|
||||||
utils.createFace({ assetId: asset3.id, personId: nameNullPerson1Asset.id }),
|
|
||||||
// Favourite People
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameFreddyPersonFavourite.id }),
|
|
||||||
utils.createFace({ assetId: asset2.id, personId: nameFreddyPersonFavourite.id }),
|
|
||||||
utils.createFace({ assetId: asset1.id, personId: nameBillPersonFavourite.id }),
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,19 +87,15 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
expect.objectContaining({ name: 'Freddy' }),
|
|
||||||
expect.objectContaining({ name: 'Bill' }),
|
|
||||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'Bob' }),
|
expect.objectContaining({ name: 'Bob' }),
|
||||||
expect.objectContaining({ name: 'Alice' }),
|
expect.objectContaining({ name: 'Alice' }),
|
||||||
expect.objectContaining({ name: 'Charlie' }),
|
expect.objectContaining({ name: 'Charlie' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson4Assets.id, name: '' }),
|
expect.objectContaining({ name: 'hidden_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson3Assets.id, name: '' }),
|
|
||||||
expect.objectContaining({ name: 'hidden_person' }), // Should really be before the null names
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -144,21 +105,17 @@ describe('/people', () => {
|
|||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body.hasNextPage).toBe(false);
|
expect(body.hasNextPage).toBe(false);
|
||||||
expect(body.total).toBe(11); // All persons
|
expect(body.total).toBe(7); // All persons
|
||||||
expect(body.hidden).toBe(1); // 'hidden_person'
|
expect(body.hidden).toBe(1); // 'hidden_person'
|
||||||
|
|
||||||
const people = body.people as PersonResponseDto[];
|
const people = body.people as PersonResponseDto[];
|
||||||
|
|
||||||
expect(people.map((p) => p.id)).toEqual([
|
expect(people.map((p) => p.id)).toEqual([
|
||||||
nameFreddyPersonFavourite.id, // name: 'Freddy', count: 2
|
|
||||||
nameBillPersonFavourite.id, // name: 'Bill', count: 1
|
|
||||||
multipleAssetsPerson.id, // name: 'multiple_assets_person', count: 3
|
multipleAssetsPerson.id, // name: 'multiple_assets_person', count: 3
|
||||||
nameBobPerson.id, // name: 'Bob', count: 2
|
nameBobPerson.id, // name: 'Bob', count: 2
|
||||||
nameAlicePerson.id, // name: 'Alice', count: 1
|
nameAlicePerson.id, // name: 'Alice', count: 1
|
||||||
nameCharliePerson.id, // name: 'Charlie', count: 1
|
nameCharliePerson.id, // name: 'Charlie', count: 1
|
||||||
visiblePerson.id, // name: 'visible_person', count: 1
|
visiblePerson.id, // name: 'visible_person', count: 1
|
||||||
nameNullPerson4Assets.id, // name: '', count: 4
|
|
||||||
nameNullPerson3Assets.id, // name: '', count: 3
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(people.some((p) => p.id === hiddenPerson.id)).toBe(false);
|
expect(people.some((p) => p.id === hiddenPerson.id)).toBe(false);
|
||||||
@@ -170,18 +127,14 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
expect.objectContaining({ name: 'Freddy' }),
|
|
||||||
expect.objectContaining({ name: 'Bill' }),
|
|
||||||
expect.objectContaining({ name: 'multiple_assets_person' }),
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'Bob' }),
|
expect.objectContaining({ name: 'Bob' }),
|
||||||
expect.objectContaining({ name: 'Alice' }),
|
expect.objectContaining({ name: 'Alice' }),
|
||||||
expect.objectContaining({ name: 'Charlie' }),
|
expect.objectContaining({ name: 'Charlie' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ id: nameNullPerson4Assets.id, name: '' }),
|
|
||||||
expect.objectContaining({ id: nameNullPerson3Assets.id, name: '' }),
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -195,9 +148,9 @@ describe('/people', () => {
|
|||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
hasNextPage: true,
|
hasNextPage: true,
|
||||||
total: 11,
|
total: 7,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [expect.objectContaining({ name: 'Alice' })],
|
people: [expect.objectContaining({ name: 'visible_person' })],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -464,6 +464,7 @@
|
|||||||
"assets": "Assets",
|
"assets": "Assets",
|
||||||
"assets_added_count": "Added {count, plural, one {# asset} other {# assets}}",
|
"assets_added_count": "Added {count, plural, one {# asset} other {# assets}}",
|
||||||
"assets_added_to_album_count": "Added {count, plural, one {# asset} other {# assets}} to the album",
|
"assets_added_to_album_count": "Added {count, plural, one {# asset} other {# assets}} to the album",
|
||||||
|
"assets_added_to_name_count": "Added {count, plural, one {# asset} other {# assets}} to {hasName, select, true {<b>{name}</b>} other {new album}}",
|
||||||
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} cannot be added to the album",
|
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} cannot be added to the album",
|
||||||
"assets_count": "{count, plural, one {# asset} other {# assets}}",
|
"assets_count": "{count, plural, one {# asset} other {# assets}}",
|
||||||
"assets_deleted_permanently": "{count} asset(s) deleted permanently",
|
"assets_deleted_permanently": "{count} asset(s) deleted permanently",
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ async def load(model: InferenceModel) -> InferenceModel:
|
|||||||
|
|
||||||
async def idle_shutdown_task() -> None:
|
async def idle_shutdown_task() -> None:
|
||||||
while True:
|
while True:
|
||||||
|
log.debug("Checking for inactivity...")
|
||||||
if (
|
if (
|
||||||
last_called is not None
|
last_called is not None
|
||||||
and not active_requests
|
and not active_requests
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ platform :android do
|
|||||||
task: 'bundle',
|
task: 'bundle',
|
||||||
build_type: 'Release',
|
build_type: 'Release',
|
||||||
properties: {
|
properties: {
|
||||||
"android.injected.version.code" => 204,
|
"android.injected.version.code" => 201,
|
||||||
"android.injected.version.name" => "1.135.3",
|
"android.injected.version.name" => "1.135.0",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||||
|
|||||||
@@ -649,7 +649,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -793,7 +793,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -823,7 +823,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -857,7 +857,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -865,7 +865,7 @@
|
|||||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -900,7 +900,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -908,7 +908,7 @@
|
|||||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -940,7 +940,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
@@ -948,7 +948,7 @@
|
|||||||
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
INFOPLIST_FILE = WidgetExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
INFOPLIST_KEY_CFBundleDisplayName = Widget;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -979,7 +979,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
@@ -1023,7 +1023,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
@@ -1064,7 +1064,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 210;
|
CURRENT_PROJECT_VERSION = 209;
|
||||||
CUSTOM_GROUP_ID = group.app.immich.share;
|
CUSTOM_GROUP_ID = group.app.immich.share;
|
||||||
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
DEVELOPMENT_TEAM = 2F67MQ8R79;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.135.1</string>
|
<string>1.135.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>210</string>
|
<string>209</string>
|
||||||
<key>FLTEnableImpeller</key>
|
<key>FLTEnableImpeller</key>
|
||||||
<true />
|
<true />
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
@@ -115,8 +115,8 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<key>NSBonjourServices</key>
|
<key>NSBonjourServices</key>
|
||||||
<array>
|
<array>
|
||||||
<string>_googlecast._tcp</string>
|
<string>_googlecast._tcp</string>
|
||||||
<string>_CC1AD845._googlecast._tcp</string>
|
<string>_CC1AD845._googlecast._tcp</string>
|
||||||
</array>
|
</array>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>We need to access the camera to let you take beautiful video using this app</string>
|
<string>We need to access the camera to let you take beautiful video using this app</string>
|
||||||
@@ -168,8 +168,5 @@
|
|||||||
<true />
|
<true />
|
||||||
<key>NSFaceIDUsageDescription</key>
|
<key>NSFaceIDUsageDescription</key>
|
||||||
<string>We need to use FaceID to allow access to your locked folder</string>
|
<string>We need to use FaceID to allow access to your locked folder</string>
|
||||||
<key>NSLocalNetworkUsageDescription</key>
|
|
||||||
<string>We need local network permission to connect to the local server using IP address and
|
|
||||||
allow the casting feature to work</string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -17,14 +17,6 @@ enum AssetType: String, Codable {
|
|||||||
case other = "OTHER"
|
case other = "OTHER"
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ServerWellKnown: Codable {
|
|
||||||
struct APIInfo: Codable{
|
|
||||||
let endpoint: String
|
|
||||||
}
|
|
||||||
|
|
||||||
let api: APIInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SearchResult: Codable {
|
struct SearchResult: Codable {
|
||||||
let id: String
|
let id: String
|
||||||
let type: AssetType
|
let type: AssetType
|
||||||
@@ -65,7 +57,7 @@ class ImmichAPI {
|
|||||||
init() async throws {
|
init() async throws {
|
||||||
// fetch the credentials from the UserDefaults store that dart placed here
|
// fetch the credentials from the UserDefaults store that dart placed here
|
||||||
guard let defaults = UserDefaults(suiteName: "group.app.immich.share"),
|
guard let defaults = UserDefaults(suiteName: "group.app.immich.share"),
|
||||||
var serverURL = defaults.string(forKey: "widget_server_url"),
|
let serverURL = defaults.string(forKey: "widget_server_url"),
|
||||||
let sessionKey = defaults.string(forKey: "widget_auth_token")
|
let sessionKey = defaults.string(forKey: "widget_auth_token")
|
||||||
else {
|
else {
|
||||||
throw WidgetError.noLogin
|
throw WidgetError.noLogin
|
||||||
@@ -74,55 +66,13 @@ class ImmichAPI {
|
|||||||
if serverURL == "" || sessionKey == "" {
|
if serverURL == "" || sessionKey == "" {
|
||||||
throw WidgetError.noLogin
|
throw WidgetError.noLogin
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrate the server list value to a JSON array if it is not already
|
serverConfig = ServerConfig(
|
||||||
if !serverURL.starts(with: "[") {
|
serverEndpoint: serverURL,
|
||||||
let newServerList = "[\"\(serverURL)\"]"
|
sessionKey: sessionKey
|
||||||
defaults.set(newServerList, forKey: "widget_server_url")
|
)
|
||||||
serverURL = newServerList
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let urls = try? JSONDecoder().decode([String].self, from: serverURL.data(using: .utf8)!) else {
|
|
||||||
throw WidgetError.noLogin
|
|
||||||
}
|
|
||||||
|
|
||||||
for url in urls {
|
|
||||||
guard let endpointURL = URL(string: url) else { continue }
|
|
||||||
|
|
||||||
if let apiURL = await Self.validateServer(at: endpointURL) {
|
|
||||||
serverConfig = ServerConfig(
|
|
||||||
serverEndpoint: apiURL.absoluteString,
|
|
||||||
sessionKey: sessionKey
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw WidgetError.fetchFailed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func validateServer(at endpointURL: URL) async -> URL? {
|
|
||||||
// build a URL that is only scheme, host, and port
|
|
||||||
var components = URLComponents()
|
|
||||||
components.scheme = endpointURL.scheme
|
|
||||||
components.host = endpointURL.host
|
|
||||||
components.port = endpointURL.port
|
|
||||||
|
|
||||||
guard let baseURL = components.url else { return nil }
|
|
||||||
|
|
||||||
var pingURL = baseURL
|
|
||||||
pingURL.appendPathComponent(".well-known")
|
|
||||||
pingURL.appendPathComponent("immich")
|
|
||||||
|
|
||||||
guard let (serverPingJSON, _) = try? await URLSession.shared.data(from: pingURL) else { return nil }
|
|
||||||
guard let apiInfo = try? JSONDecoder().decode(ServerWellKnown.self, from: serverPingJSON) else { return nil }
|
|
||||||
|
|
||||||
var apiURL = baseURL
|
|
||||||
apiURL.appendPathComponent(apiInfo.api.endpoint)
|
|
||||||
|
|
||||||
return apiURL
|
|
||||||
}
|
|
||||||
|
|
||||||
private func buildRequestURL(
|
private func buildRequestURL(
|
||||||
serverConfig: ServerConfig,
|
serverConfig: ServerConfig,
|
||||||
endpoint: String,
|
endpoint: String,
|
||||||
|
|||||||
@@ -20,11 +20,8 @@ struct ImmichMemoryProvider: TimelineProvider {
|
|||||||
completion: @escaping @Sendable (ImageEntry) -> Void
|
completion: @escaping @Sendable (ImageEntry) -> Void
|
||||||
) {
|
) {
|
||||||
Task {
|
Task {
|
||||||
var api: ImmichAPI
|
guard let api = try? await ImmichAPI() else {
|
||||||
do {
|
completion(ImageEntry(date: Date(), image: nil, error: .noLogin))
|
||||||
api = try await ImmichAPI()
|
|
||||||
} catch let error as WidgetError {
|
|
||||||
completion(ImageEntry(date: Date(), image: nil, error: error))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,13 +79,9 @@ struct ImmichMemoryProvider: TimelineProvider {
|
|||||||
Task {
|
Task {
|
||||||
var entries: [ImageEntry] = []
|
var entries: [ImageEntry] = []
|
||||||
let now = Date()
|
let now = Date()
|
||||||
|
|
||||||
|
guard let api = try? await ImmichAPI() else {
|
||||||
var api: ImmichAPI
|
entries.append(ImageEntry(date: now, image: nil, error: .noLogin))
|
||||||
do {
|
|
||||||
api = try await ImmichAPI()
|
|
||||||
} catch let error as WidgetError {
|
|
||||||
entries.append(ImageEntry(date: now, image: nil, error: error))
|
|
||||||
completion(Timeline(entries: entries, policy: .atEnd))
|
completion(Timeline(entries: entries, policy: .atEnd))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ struct RandomConfigurationAppIntent: WidgetConfigurationIntent {
|
|||||||
"Choose an album to show images from"
|
"Choose an album to show images from"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parameter(title: "Album")
|
@Parameter(title: "Album", default: NO_ALBUM)
|
||||||
var album: Album?
|
var album: Album?
|
||||||
|
|
||||||
@Parameter(title: "Show Album Name", default: false)
|
@Parameter(title: "Show Album Name", default: false)
|
||||||
@@ -63,15 +63,10 @@ struct ImmichRandomProvider: AppIntentTimelineProvider {
|
|||||||
) async
|
) async
|
||||||
-> ImageEntry
|
-> ImageEntry
|
||||||
{
|
{
|
||||||
var api: ImmichAPI
|
guard let api = try? await ImmichAPI() else {
|
||||||
do {
|
return ImageEntry(date: Date(), image: nil, error: .noLogin)
|
||||||
api = try await ImmichAPI()
|
|
||||||
} catch let error as WidgetError {
|
|
||||||
return ImageEntry(date: Date(), image: nil, error: error)
|
|
||||||
} catch {
|
|
||||||
return ImageEntry(date: Date(), image: nil, error: .fetchFailed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guard
|
guard
|
||||||
let randomImage = try? await api.fetchSearchResults(
|
let randomImage = try? await api.fetchSearchResults(
|
||||||
with: SearchFilters(size: 1)
|
with: SearchFilters(size: 1)
|
||||||
@@ -105,21 +100,15 @@ struct ImmichRandomProvider: AppIntentTimelineProvider {
|
|||||||
let now = Date()
|
let now = Date()
|
||||||
|
|
||||||
// If we don't have a server config, return an entry with an error
|
// If we don't have a server config, return an entry with an error
|
||||||
var api: ImmichAPI
|
guard let api = try? await ImmichAPI() else {
|
||||||
do {
|
entries.append(ImageEntry(date: now, image: nil, error: .noLogin))
|
||||||
api = try await ImmichAPI()
|
|
||||||
} catch let error as WidgetError {
|
|
||||||
entries.append(ImageEntry(date: now, image: nil, error: error))
|
|
||||||
return Timeline(entries: entries, policy: .atEnd)
|
|
||||||
} catch {
|
|
||||||
entries.append(ImageEntry(date: now, image: nil, error: .fetchFailed))
|
|
||||||
return Timeline(entries: entries, policy: .atEnd)
|
return Timeline(entries: entries, policy: .atEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nil if album is NONE or nil
|
// nil if album is NONE or nil
|
||||||
let albumId =
|
let albumId =
|
||||||
configuration.album?.id != "NONE" ? configuration.album?.id : nil
|
configuration.album?.id != "NONE" ? configuration.album?.id : nil
|
||||||
let albumName: String? = albumId != nil ? configuration.album?.albumName : nil
|
var albumName: String? = albumId != nil ? configuration.album?.albumName : nil
|
||||||
|
|
||||||
if albumId != nil {
|
if albumId != nil {
|
||||||
// make sure the album exists on server, otherwise show error
|
// make sure the album exists on server, otherwise show error
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ platform :ios do
|
|||||||
path: "./Runner.xcodeproj",
|
path: "./Runner.xcodeproj",
|
||||||
)
|
)
|
||||||
increment_version_number(
|
increment_version_number(
|
||||||
version_number: "1.135.3"
|
version_number: "1.135.0"
|
||||||
)
|
)
|
||||||
increment_build_number(
|
increment_build_number(
|
||||||
build_number: latest_testflight_build_number + 1,
|
build_number: latest_testflight_build_number + 1,
|
||||||
|
|||||||
@@ -10,5 +10,3 @@ enum TextSearchType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum AssetVisibilityEnum { timeline, hidden, archive, locked }
|
enum AssetVisibilityEnum { timeline, hidden, archive, locked }
|
||||||
|
|
||||||
enum SortUserBy { id }
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ const Map<String, Locale> locales = {
|
|||||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
|
||||||
'Chinese Traditional (zh_TW)':
|
'Chinese Traditional (zh_TW)':
|
||||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
||||||
'Croatian (hr)': Locale('hr'),
|
|
||||||
'Czech (cs)': Locale('cs'),
|
'Czech (cs)': Locale('cs'),
|
||||||
'Danish (da)': Locale('da'),
|
'Danish (da)': Locale('da'),
|
||||||
'Dutch (nl)': Locale('nl'),
|
'Dutch (nl)': Locale('nl'),
|
||||||
|
|||||||
10
mobile/lib/domain/interfaces/asset_media.interface.dart
Normal file
10
mobile/lib/domain/interfaces/asset_media.interface.dart
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
abstract interface class IAssetMediaRepository {
|
||||||
|
Future<Uint8List?> getThumbnail(
|
||||||
|
String id, {
|
||||||
|
int quality = 80,
|
||||||
|
Size size = const Size.square(256),
|
||||||
|
});
|
||||||
|
}
|
||||||
12
mobile/lib/domain/interfaces/device_asset.interface.dart
Normal file
12
mobile/lib/domain/interfaces/device_asset.interface.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/device_asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IDeviceAssetRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> updateAll(List<DeviceAsset> assetHash);
|
||||||
|
|
||||||
|
Future<List<DeviceAsset>> getByIds(List<String> localIds);
|
||||||
|
|
||||||
|
Future<void> deleteIds(List<String> ids);
|
||||||
|
}
|
||||||
14
mobile/lib/domain/interfaces/exif.interface.dart
Normal file
14
mobile/lib/domain/interfaces/exif.interface.dart
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IExifInfoRepository implements IDatabaseRepository {
|
||||||
|
Future<ExifInfo?> get(int assetId);
|
||||||
|
|
||||||
|
Future<ExifInfo> update(ExifInfo exifInfo);
|
||||||
|
|
||||||
|
Future<List<ExifInfo>> updateAll(List<ExifInfo> exifInfos);
|
||||||
|
|
||||||
|
Future<void> delete(int assetId);
|
||||||
|
|
||||||
|
Future<void> deleteAll();
|
||||||
|
}
|
||||||
33
mobile/lib/domain/interfaces/local_album.interface.dart
Normal file
33
mobile/lib/domain/interfaces/local_album.interface.dart
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILocalAlbumRepository implements IDatabaseRepository {
|
||||||
|
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}});
|
||||||
|
|
||||||
|
Future<List<LocalAsset>> getAssets(String albumId);
|
||||||
|
|
||||||
|
Future<List<String>> getAssetIds(String albumId);
|
||||||
|
|
||||||
|
Future<void> upsert(
|
||||||
|
LocalAlbum album, {
|
||||||
|
Iterable<LocalAsset> toUpsert = const [],
|
||||||
|
Iterable<String> toDelete = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> updateAll(Iterable<LocalAlbum> albums);
|
||||||
|
|
||||||
|
Future<void> delete(String albumId);
|
||||||
|
|
||||||
|
Future<void> processDelta({
|
||||||
|
required List<LocalAsset> updates,
|
||||||
|
required List<String> deletes,
|
||||||
|
required Map<String, List<String>> assetAlbums,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> syncDeletes(String albumId, Iterable<String> assetIdsToKeep);
|
||||||
|
|
||||||
|
Future<List<LocalAsset>> getAssetsToHash(String albumId);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum }
|
||||||
6
mobile/lib/domain/interfaces/local_asset.interface.dart
Normal file
6
mobile/lib/domain/interfaces/local_asset.interface.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILocalAssetRepository implements IDatabaseRepository {
|
||||||
|
Future<void> updateHashes(Iterable<LocalAsset> hashes);
|
||||||
|
}
|
||||||
17
mobile/lib/domain/interfaces/log.interface.dart
Normal file
17
mobile/lib/domain/interfaces/log.interface.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ILogRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> insert(LogMessage log);
|
||||||
|
|
||||||
|
Future<bool> insertAll(Iterable<LogMessage> logs);
|
||||||
|
|
||||||
|
Future<List<LogMessage>> getAll();
|
||||||
|
|
||||||
|
Future<bool> deleteAll();
|
||||||
|
|
||||||
|
/// Truncates the logs to the most recent [limit]. Defaults to recent 250 logs
|
||||||
|
Future<void> truncate({int limit = 250});
|
||||||
|
}
|
||||||
7
mobile/lib/domain/interfaces/storage.interface.dart
Normal file
7
mobile/lib/domain/interfaces/storage.interface.dart
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IStorageRepository {
|
||||||
|
Future<File?> getFileForAsset(LocalAsset asset);
|
||||||
|
}
|
||||||
20
mobile/lib/domain/interfaces/store.interface.dart
Normal file
20
mobile/lib/domain/interfaces/store.interface.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IStoreRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> insert<T>(StoreKey<T> key, T value);
|
||||||
|
|
||||||
|
Future<T?> tryGet<T>(StoreKey<T> key);
|
||||||
|
|
||||||
|
Future<List<StoreDto<Object>>> getAll();
|
||||||
|
|
||||||
|
Stream<T?> watch<T>(StoreKey<T> key);
|
||||||
|
|
||||||
|
Stream<StoreDto<Object>> watchAll();
|
||||||
|
|
||||||
|
Future<bool> update<T>(StoreKey<T> key, T value);
|
||||||
|
|
||||||
|
Future<void> delete<T>(StoreKey<T> key);
|
||||||
|
|
||||||
|
Future<void> deleteAll();
|
||||||
|
}
|
||||||
12
mobile/lib/domain/interfaces/sync_api.interface.dart
Normal file
12
mobile/lib/domain/interfaces/sync_api.interface.dart
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ISyncApiRepository {
|
||||||
|
Future<void> ack(List<String> data);
|
||||||
|
|
||||||
|
Future<void> streamChanges(
|
||||||
|
Function(List<SyncEvent>, Function() abort) onData, {
|
||||||
|
int batchSize,
|
||||||
|
http.Client? httpClient,
|
||||||
|
});
|
||||||
|
}
|
||||||
18
mobile/lib/domain/interfaces/sync_stream.interface.dart
Normal file
18
mobile/lib/domain/interfaces/sync_stream.interface.dart
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
|
abstract interface class ISyncStreamRepository implements IDatabaseRepository {
|
||||||
|
Future<void> updateUsersV1(Iterable<SyncUserV1> data);
|
||||||
|
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data);
|
||||||
|
|
||||||
|
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data);
|
||||||
|
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data);
|
||||||
|
|
||||||
|
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data);
|
||||||
|
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data);
|
||||||
|
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data);
|
||||||
|
|
||||||
|
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data);
|
||||||
|
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data);
|
||||||
|
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data);
|
||||||
|
}
|
||||||
27
mobile/lib/domain/interfaces/timeline.interface.dart
Normal file
27
mobile/lib/domain/interfaces/timeline.interface.dart
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ITimelineRepository implements IDatabaseRepository {
|
||||||
|
Stream<List<Bucket>> watchMainBucket(
|
||||||
|
List<String> timelineUsers, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getMainBucketAssets(
|
||||||
|
List<String> timelineUsers, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
});
|
||||||
|
|
||||||
|
Stream<List<Bucket>> watchLocalBucket(
|
||||||
|
String albumId, {
|
||||||
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<BaseAsset>> getLocalBucketAssets(
|
||||||
|
String albumId, {
|
||||||
|
required int offset,
|
||||||
|
required int count,
|
||||||
|
});
|
||||||
|
}
|
||||||
22
mobile/lib/domain/interfaces/user.interface.dart
Normal file
22
mobile/lib/domain/interfaces/user.interface.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/db.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IUserRepository implements IDatabaseRepository {
|
||||||
|
Future<bool> insert(UserDto user);
|
||||||
|
|
||||||
|
Future<UserDto?> getByUserId(String id);
|
||||||
|
|
||||||
|
Future<List<UserDto?>> getByUserIds(List<String> ids);
|
||||||
|
|
||||||
|
Future<List<UserDto>> getAll({SortUserBy? sortBy});
|
||||||
|
|
||||||
|
Future<bool> updateAll(List<UserDto> users);
|
||||||
|
|
||||||
|
Future<UserDto> update(UserDto user);
|
||||||
|
|
||||||
|
Future<void> delete(List<String> ids);
|
||||||
|
|
||||||
|
Future<void> deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SortUserBy { id }
|
||||||
15
mobile/lib/domain/interfaces/user_api.interface.dart
Normal file
15
mobile/lib/domain/interfaces/user_api.interface.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IUserApiRepository {
|
||||||
|
Future<UserDto?> getMyUser();
|
||||||
|
|
||||||
|
Future<List<UserDto>> getAll();
|
||||||
|
|
||||||
|
/// Saves the [data] in the server and uses it as the current users profile image
|
||||||
|
Future<String> createProfileImage({
|
||||||
|
required String name,
|
||||||
|
required Uint8List data,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/storage.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
|
||||||
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@@ -12,16 +12,16 @@ import 'package:logging/logging.dart';
|
|||||||
class HashService {
|
class HashService {
|
||||||
final int batchSizeLimit;
|
final int batchSizeLimit;
|
||||||
final int batchFileLimit;
|
final int batchFileLimit;
|
||||||
final DriftLocalAlbumRepository _localAlbumRepository;
|
final ILocalAlbumRepository _localAlbumRepository;
|
||||||
final DriftLocalAssetRepository _localAssetRepository;
|
final ILocalAssetRepository _localAssetRepository;
|
||||||
final StorageRepository _storageRepository;
|
final IStorageRepository _storageRepository;
|
||||||
final NativeSyncApi _nativeSyncApi;
|
final NativeSyncApi _nativeSyncApi;
|
||||||
final _log = Logger('HashService');
|
final _log = Logger('HashService');
|
||||||
|
|
||||||
HashService({
|
HashService({
|
||||||
required DriftLocalAlbumRepository localAlbumRepository,
|
required ILocalAlbumRepository localAlbumRepository,
|
||||||
required DriftLocalAssetRepository localAssetRepository,
|
required ILocalAssetRepository localAssetRepository,
|
||||||
required StorageRepository storageRepository,
|
required IStorageRepository storageRepository,
|
||||||
required NativeSyncApi nativeSyncApi,
|
required NativeSyncApi nativeSyncApi,
|
||||||
this.batchSizeLimit = kBatchHashSizeLimit,
|
this.batchSizeLimit = kBatchHashSizeLimit,
|
||||||
this.batchFileLimit = kBatchHashFileLimit,
|
this.batchFileLimit = kBatchHashFileLimit,
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
|
||||||
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
import 'package:immich_mobile/platform/native_sync_api.g.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||||
import 'package:immich_mobile/utils/diff.dart';
|
import 'package:immich_mobile/utils/diff.dart';
|
||||||
@@ -14,14 +14,14 @@ import 'package:logging/logging.dart';
|
|||||||
import 'package:platform/platform.dart';
|
import 'package:platform/platform.dart';
|
||||||
|
|
||||||
class LocalSyncService {
|
class LocalSyncService {
|
||||||
final DriftLocalAlbumRepository _localAlbumRepository;
|
final ILocalAlbumRepository _localAlbumRepository;
|
||||||
final NativeSyncApi _nativeSyncApi;
|
final NativeSyncApi _nativeSyncApi;
|
||||||
final Platform _platform;
|
final Platform _platform;
|
||||||
final StoreService _storeService;
|
final StoreService _storeService;
|
||||||
final Logger _log = Logger("DeviceSyncService");
|
final Logger _log = Logger("DeviceSyncService");
|
||||||
|
|
||||||
LocalSyncService({
|
LocalSyncService({
|
||||||
required DriftLocalAlbumRepository localAlbumRepository,
|
required ILocalAlbumRepository localAlbumRepository,
|
||||||
required NativeSyncApi nativeSyncApi,
|
required NativeSyncApi nativeSyncApi,
|
||||||
required StoreService storeService,
|
required StoreService storeService,
|
||||||
Platform? platform,
|
Platform? platform,
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
/// Service responsible for handling application logging.
|
/// Service responsible for handling application logging.
|
||||||
@@ -14,8 +14,8 @@ import 'package:logging/logging.dart';
|
|||||||
/// writes them to a persistent [ILogRepository], and manages log levels
|
/// writes them to a persistent [ILogRepository], and manages log levels
|
||||||
/// via [IStoreRepository]
|
/// via [IStoreRepository]
|
||||||
class LogService {
|
class LogService {
|
||||||
final IsarLogRepository _logRepository;
|
final ILogRepository _logRepository;
|
||||||
final IsarStoreRepository _storeRepository;
|
final IStoreRepository _storeRepository;
|
||||||
|
|
||||||
final List<LogMessage> _msgBuffer = [];
|
final List<LogMessage> _msgBuffer = [];
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ class LogService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<LogService> init({
|
static Future<LogService> init({
|
||||||
required IsarLogRepository logRepository,
|
required ILogRepository logRepository,
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
bool shouldBuffer = true,
|
bool shouldBuffer = true,
|
||||||
}) async {
|
}) async {
|
||||||
_instance ??= await create(
|
_instance ??= await create(
|
||||||
@@ -50,8 +50,8 @@ class LogService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<LogService> create({
|
static Future<LogService> create({
|
||||||
required IsarLogRepository logRepository,
|
required ILogRepository logRepository,
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
bool shouldBuffer = true,
|
bool shouldBuffer = true,
|
||||||
}) async {
|
}) async {
|
||||||
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
|
||||||
|
|
||||||
/// Provides access to a persistent key-value store with an in-memory cache.
|
/// Provides access to a persistent key-value store with an in-memory cache.
|
||||||
/// Listens for repository changes to keep the cache updated.
|
/// Listens for repository changes to keep the cache updated.
|
||||||
class StoreService {
|
class StoreService {
|
||||||
final IsarStoreRepository _storeRepository;
|
final IStoreRepository _storeRepository;
|
||||||
|
|
||||||
/// In-memory cache. Keys are [StoreKey.id]
|
/// In-memory cache. Keys are [StoreKey.id]
|
||||||
final Map<int, Object?> _cache = {};
|
final Map<int, Object?> _cache = {};
|
||||||
late final StreamSubscription<StoreDto> _storeUpdateSubscription;
|
late final StreamSubscription<StoreDto> _storeUpdateSubscription;
|
||||||
|
|
||||||
StoreService._({required IsarStoreRepository storeRepository})
|
StoreService._({required IStoreRepository storeRepository})
|
||||||
: _storeRepository = storeRepository;
|
: _storeRepository = storeRepository;
|
||||||
|
|
||||||
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
|
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
|
||||||
@@ -26,14 +26,14 @@ class StoreService {
|
|||||||
|
|
||||||
// TODO: Replace the implementation with the one from create after removing the typedef
|
// TODO: Replace the implementation with the one from create after removing the typedef
|
||||||
static Future<StoreService> init({
|
static Future<StoreService> init({
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
}) async {
|
}) async {
|
||||||
_instance ??= await create(storeRepository: storeRepository);
|
_instance ??= await create(storeRepository: storeRepository);
|
||||||
return _instance!;
|
return _instance!;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<StoreService> create({
|
static Future<StoreService> create({
|
||||||
required IsarStoreRepository storeRepository,
|
required IStoreRepository storeRepository,
|
||||||
}) async {
|
}) async {
|
||||||
final instance = StoreService._(storeRepository: storeRepository);
|
final instance = StoreService._(storeRepository: storeRepository);
|
||||||
await instance._populateCache();
|
await instance._populateCache();
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/sync_api.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/sync_stream.repository.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class SyncStreamService {
|
class SyncStreamService {
|
||||||
final Logger _logger = Logger('SyncStreamService');
|
final Logger _logger = Logger('SyncStreamService');
|
||||||
|
|
||||||
final SyncApiRepository _syncApiRepository;
|
final ISyncApiRepository _syncApiRepository;
|
||||||
final SyncStreamRepository _syncStreamRepository;
|
final ISyncStreamRepository _syncStreamRepository;
|
||||||
final bool Function()? _cancelChecker;
|
final bool Function()? _cancelChecker;
|
||||||
|
|
||||||
SyncStreamService({
|
SyncStreamService({
|
||||||
required SyncApiRepository syncApiRepository,
|
required ISyncApiRepository syncApiRepository,
|
||||||
required SyncStreamRepository syncStreamRepository,
|
required ISyncStreamRepository syncStreamRepository,
|
||||||
bool Function()? cancelChecker,
|
bool Function()? cancelChecker,
|
||||||
}) : _syncApiRepository = syncApiRepository,
|
}) : _syncApiRepository = syncApiRepository,
|
||||||
_syncStreamRepository = syncStreamRepository,
|
_syncStreamRepository = syncStreamRepository,
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import 'dart:math' as math;
|
|||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/timeline.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/setting.model.dart';
|
import 'package:immich_mobile/domain/models/setting.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/setting.service.dart';
|
import 'package:immich_mobile/domain/services/setting.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
|
|
||||||
import 'package:immich_mobile/utils/async_mutex.dart';
|
import 'package:immich_mobile/utils/async_mutex.dart';
|
||||||
|
|
||||||
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
||||||
@@ -18,11 +18,11 @@ typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
|||||||
typedef TimelineBucketSource = Stream<List<Bucket>> Function();
|
typedef TimelineBucketSource = Stream<List<Bucket>> Function();
|
||||||
|
|
||||||
class TimelineFactory {
|
class TimelineFactory {
|
||||||
final DriftTimelineRepository _timelineRepository;
|
final ITimelineRepository _timelineRepository;
|
||||||
final SettingsService _settingsService;
|
final SettingsService _settingsService;
|
||||||
|
|
||||||
const TimelineFactory({
|
const TimelineFactory({
|
||||||
required DriftTimelineRepository timelineRepository,
|
required ITimelineRepository timelineRepository,
|
||||||
required SettingsService settingsService,
|
required SettingsService settingsService,
|
||||||
}) : _timelineRepository = timelineRepository,
|
}) : _timelineRepository = timelineRepository,
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
class UserService {
|
class UserService {
|
||||||
final Logger _log = Logger("UserService");
|
final Logger _log = Logger("UserService");
|
||||||
final IsarUserRepository _isarUserRepository;
|
final IUserRepository _userRepository;
|
||||||
final UserApiRepository _userApiRepository;
|
final IUserApiRepository _userApiRepository;
|
||||||
final StoreService _storeService;
|
final StoreService _storeService;
|
||||||
|
|
||||||
UserService({
|
UserService({
|
||||||
required IsarUserRepository isarUserRepository,
|
required IUserRepository userRepository,
|
||||||
required UserApiRepository userApiRepository,
|
required IUserApiRepository userApiRepository,
|
||||||
required StoreService storeService,
|
required StoreService storeService,
|
||||||
}) : _isarUserRepository = isarUserRepository,
|
}) : _userRepository = userRepository,
|
||||||
_userApiRepository = userApiRepository,
|
_userApiRepository = userApiRepository,
|
||||||
_storeService = storeService;
|
_storeService = storeService;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ class UserService {
|
|||||||
final user = await _userApiRepository.getMyUser();
|
final user = await _userApiRepository.getMyUser();
|
||||||
if (user == null) return null;
|
if (user == null) return null;
|
||||||
await _storeService.put(StoreKey.currentUser, user);
|
await _storeService.put(StoreKey.currentUser, user);
|
||||||
await _isarUserRepository.update(user);
|
await _userRepository.update(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ class UserService {
|
|||||||
);
|
);
|
||||||
final updatedUser = getMyUser().copyWith(profileImagePath: path);
|
final updatedUser = getMyUser().copyWith(profileImagePath: path);
|
||||||
await _storeService.put(StoreKey.currentUser, updatedUser);
|
await _storeService.put(StoreKey.currentUser, updatedUser);
|
||||||
await _isarUserRepository.update(updatedUser);
|
await _userRepository.update(updatedUser);
|
||||||
return path;
|
return path;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_log.warning("Failed to upload profile image", e);
|
_log.warning("Failed to upload profile image", e);
|
||||||
@@ -59,10 +59,10 @@ class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<UserDto>> getAll() async {
|
Future<List<UserDto>> getAll() async {
|
||||||
return await _isarUserRepository.getAll();
|
return await _userRepository.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteAll() {
|
Future<void> deleteAll() {
|
||||||
return _isarUserRepository.deleteAll();
|
return _userRepository.deleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/asset_media.interface.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
class AssetMediaRepository {
|
class AssetMediaRepository implements IAssetMediaRepository {
|
||||||
const AssetMediaRepository();
|
const AssetMediaRepository();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Uint8List?> getThumbnail(
|
Future<Uint8List?> getThumbnail(
|
||||||
String id, {
|
String id, {
|
||||||
int quality = 80,
|
int quality = 80,
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/device_asset.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/device_asset.model.dart';
|
import 'package:immich_mobile/domain/models/device_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/device_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/device_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarDeviceAssetRepository extends IsarDatabaseRepository {
|
class IsarDeviceAssetRepository extends IsarDatabaseRepository
|
||||||
|
implements IDeviceAssetRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
|
|
||||||
const IsarDeviceAssetRepository(this._db) : super(_db);
|
const IsarDeviceAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteIds(List<String> ids) {
|
Future<void> deleteIds(List<String> ids) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.deviceAssetEntitys.deleteAllByAssetId(ids.toList());
|
await _db.deviceAssetEntitys.deleteAllByAssetId(ids.toList());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<DeviceAsset>> getByIds(List<String> localIds) {
|
Future<List<DeviceAsset>> getByIds(List<String> localIds) {
|
||||||
return _db.deviceAssetEntitys
|
return _db.deviceAssetEntitys
|
||||||
.where()
|
.where()
|
||||||
@@ -22,6 +26,7 @@ class IsarDeviceAssetRepository extends IsarDatabaseRepository {
|
|||||||
.then((value) => value.map((e) => e.toModel()).toList());
|
.then((value) => value.map((e) => e.toModel()).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> updateAll(List<DeviceAsset> assetHash) {
|
Future<bool> updateAll(List<DeviceAsset> assetHash) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.deviceAssetEntitys
|
await _db.deviceAssetEntitys
|
||||||
|
|||||||
@@ -1,30 +1,36 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.dart'
|
||||||
as entity;
|
as entity;
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarExifRepository extends IsarDatabaseRepository {
|
class IsarExifRepository extends IsarDatabaseRepository
|
||||||
|
implements IExifInfoRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
|
|
||||||
const IsarExifRepository(this._db) : super(_db);
|
const IsarExifRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete(int assetId) async {
|
Future<void> delete(int assetId) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.exifInfos.delete(assetId);
|
await _db.exifInfos.delete(assetId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteAll() async {
|
Future<void> deleteAll() async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.exifInfos.clear();
|
await _db.exifInfos.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<ExifInfo?> get(int assetId) async {
|
Future<ExifInfo?> get(int assetId) async {
|
||||||
return (await _db.exifInfos.get(assetId))?.toDto();
|
return (await _db.exifInfos.get(assetId))?.toDto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<ExifInfo> update(ExifInfo exifInfo) {
|
Future<ExifInfo> update(ExifInfo exifInfo) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.exifInfos.put(entity.ExifInfo.fromDto(exifInfo));
|
await _db.exifInfos.put(entity.ExifInfo.fromDto(exifInfo));
|
||||||
@@ -32,6 +38,7 @@ class IsarExifRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<ExifInfo>> updateAll(List<ExifInfo> exifInfos) {
|
Future<List<ExifInfo>> updateAll(List<ExifInfo> exifInfos) {
|
||||||
return transaction(() async {
|
return transaction(() async {
|
||||||
await _db.exifInfos.putAll(
|
await _db.exifInfos.putAll(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.drift.dart';
|
||||||
@@ -7,15 +8,15 @@ import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.d
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:platform/platform.dart';
|
import 'package:platform/platform.dart';
|
||||||
|
|
||||||
enum SortLocalAlbumsBy { id, backupSelection, isIosSharedAlbum }
|
class DriftLocalAlbumRepository extends DriftDatabaseRepository
|
||||||
|
implements ILocalAlbumRepository {
|
||||||
class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
final Platform _platform;
|
final Platform _platform;
|
||||||
const DriftLocalAlbumRepository(this._db, {Platform? platform})
|
const DriftLocalAlbumRepository(this._db, {Platform? platform})
|
||||||
: _platform = platform ?? const LocalPlatform(),
|
: _platform = platform ?? const LocalPlatform(),
|
||||||
super(_db);
|
super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}}) {
|
Future<List<LocalAlbum>> getAll({Set<SortLocalAlbumsBy> sortBy = const {}}) {
|
||||||
final assetCount = _db.localAlbumAssetEntity.assetId.count();
|
final assetCount = _db.localAlbumAssetEntity.assetId.count();
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete(String albumId) => transaction(() async {
|
Future<void> delete(String albumId) => transaction(() async {
|
||||||
// Remove all assets that are only in this particular album
|
// Remove all assets that are only in this particular album
|
||||||
// We cannot remove all assets in the album because they might be in other albums in iOS
|
// We cannot remove all assets in the album because they might be in other albums in iOS
|
||||||
@@ -70,6 +72,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.delete();
|
.delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> syncDeletes(
|
Future<void> syncDeletes(
|
||||||
String albumId,
|
String albumId,
|
||||||
Iterable<String> assetIdsToKeep,
|
Iterable<String> assetIdsToKeep,
|
||||||
@@ -98,6 +101,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
await deleteSmt.go();
|
await deleteSmt.go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> upsert(
|
Future<void> upsert(
|
||||||
LocalAlbum localAlbum, {
|
LocalAlbum localAlbum, {
|
||||||
Iterable<LocalAsset> toUpsert = const [],
|
Iterable<LocalAsset> toUpsert = const [],
|
||||||
@@ -130,6 +134,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateAll(Iterable<LocalAlbum> albums) {
|
Future<void> updateAll(Iterable<LocalAlbum> albums) {
|
||||||
return _db.transaction(() async {
|
return _db.transaction(() async {
|
||||||
await _db.localAlbumEntity
|
await _db.localAlbumEntity
|
||||||
@@ -180,6 +185,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LocalAsset>> getAssets(String albumId) {
|
Future<List<LocalAsset>> getAssets(String albumId) {
|
||||||
final query = _db.localAlbumAssetEntity.select().join(
|
final query = _db.localAlbumAssetEntity.select().join(
|
||||||
[
|
[
|
||||||
@@ -196,6 +202,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<String>> getAssetIds(String albumId) {
|
Future<List<String>> getAssetIds(String albumId) {
|
||||||
final query = _db.localAlbumAssetEntity.selectOnly()
|
final query = _db.localAlbumAssetEntity.selectOnly()
|
||||||
..addColumns([_db.localAlbumAssetEntity.assetId])
|
..addColumns([_db.localAlbumAssetEntity.assetId])
|
||||||
@@ -205,6 +212,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> processDelta({
|
Future<void> processDelta({
|
||||||
required List<LocalAsset> updates,
|
required List<LocalAsset> updates,
|
||||||
required List<String> deletes,
|
required List<String> deletes,
|
||||||
@@ -245,6 +253,7 @@ class DriftLocalAlbumRepository extends DriftDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LocalAsset>> getAssetsToHash(String albumId) {
|
Future<List<LocalAsset>> getAssetsToHash(String albumId) {
|
||||||
final query = _db.localAlbumAssetEntity.select().join(
|
final query = _db.localAlbumAssetEntity.select().join(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
|
|
||||||
class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
class DriftLocalAssetRepository extends DriftDatabaseRepository
|
||||||
|
implements ILocalAssetRepository {
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
const DriftLocalAssetRepository(this._db) : super(_db);
|
const DriftLocalAssetRepository(this._db) : super(_db);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
||||||
if (hashes.isEmpty) {
|
if (hashes.isEmpty) {
|
||||||
return Future.value();
|
return Future.value();
|
||||||
|
|||||||
@@ -1,23 +1,28 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/log.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/log.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/log.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarLogRepository extends IsarDatabaseRepository {
|
class IsarLogRepository extends IsarDatabaseRepository
|
||||||
|
implements ILogRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
const IsarLogRepository(super.db) : _db = db;
|
const IsarLogRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> deleteAll() async {
|
Future<bool> deleteAll() async {
|
||||||
await transaction(() async => await _db.loggerMessages.clear());
|
await transaction(() async => await _db.loggerMessages.clear());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<LogMessage>> getAll() async {
|
Future<List<LogMessage>> getAll() async {
|
||||||
final logs =
|
final logs =
|
||||||
await _db.loggerMessages.where().sortByCreatedAtDesc().findAll();
|
await _db.loggerMessages.where().sortByCreatedAtDesc().findAll();
|
||||||
return logs.map((l) => l.toDto()).toList();
|
return logs.map((l) => l.toDto()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insert(LogMessage log) async {
|
Future<bool> insert(LogMessage log) async {
|
||||||
final logEntity = LoggerMessage.fromDto(log);
|
final logEntity = LoggerMessage.fromDto(log);
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
@@ -26,6 +31,7 @@ class IsarLogRepository extends IsarDatabaseRepository {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insertAll(Iterable<LogMessage> logs) async {
|
Future<bool> insertAll(Iterable<LogMessage> logs) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
final logEntities =
|
final logEntities =
|
||||||
@@ -35,6 +41,7 @@ class IsarLogRepository extends IsarDatabaseRepository {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> truncate({int limit = 250}) async {
|
Future<void> truncate({int limit = 250}) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
final count = await _db.loggerMessages.count();
|
final count = await _db.loggerMessages.count();
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/domain/interfaces/storage.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
|
|
||||||
class StorageRepository {
|
class StorageRepository implements IStorageRepository {
|
||||||
final _log = Logger('StorageRepository');
|
final _log = Logger('StorageRepository');
|
||||||
|
|
||||||
|
@override
|
||||||
Future<File?> getFileForAsset(LocalAsset asset) async {
|
Future<File?> getFileForAsset(LocalAsset asset) async {
|
||||||
File? file;
|
File? file;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/store.entity.dart';
|
||||||
@@ -5,12 +6,14 @@ import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarStoreRepository extends IsarDatabaseRepository {
|
class IsarStoreRepository extends IsarDatabaseRepository
|
||||||
|
implements IStoreRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
final validStoreKeys = StoreKey.values.map((e) => e.id).toSet();
|
final validStoreKeys = StoreKey.values.map((e) => e.id).toSet();
|
||||||
|
|
||||||
IsarStoreRepository(super.db) : _db = db;
|
IsarStoreRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> deleteAll() async {
|
Future<bool> deleteAll() async {
|
||||||
return await transaction(() async {
|
return await transaction(() async {
|
||||||
await _db.storeValues.clear();
|
await _db.storeValues.clear();
|
||||||
@@ -18,6 +21,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<StoreDto<Object>> watchAll() {
|
Stream<StoreDto<Object>> watchAll() {
|
||||||
return _db.storeValues
|
return _db.storeValues
|
||||||
.filter()
|
.filter()
|
||||||
@@ -30,10 +34,12 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete<T>(StoreKey<T> key) async {
|
Future<void> delete<T>(StoreKey<T> key) async {
|
||||||
return await transaction(() async => await _db.storeValues.delete(key.id));
|
return await transaction(() async => await _db.storeValues.delete(key.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insert<T>(StoreKey<T> key, T value) async {
|
Future<bool> insert<T>(StoreKey<T> key, T value) async {
|
||||||
return await transaction(() async {
|
return await transaction(() async {
|
||||||
await _db.storeValues.put(await _fromValue(key, value));
|
await _db.storeValues.put(await _fromValue(key, value));
|
||||||
@@ -41,6 +47,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<T?> tryGet<T>(StoreKey<T> key) async {
|
Future<T?> tryGet<T>(StoreKey<T> key) async {
|
||||||
final entity = (await _db.storeValues.get(key.id));
|
final entity = (await _db.storeValues.get(key.id));
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
@@ -49,6 +56,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
return await _toValue(key, entity);
|
return await _toValue(key, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> update<T>(StoreKey<T> key, T value) async {
|
Future<bool> update<T>(StoreKey<T> key, T value) async {
|
||||||
return await transaction(() async {
|
return await transaction(() async {
|
||||||
await _db.storeValues.put(await _fromValue(key, value));
|
await _db.storeValues.put(await _fromValue(key, value));
|
||||||
@@ -56,6 +64,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<T?> watch<T>(StoreKey<T> key) async* {
|
Stream<T?> watch<T>(StoreKey<T> key) async* {
|
||||||
yield* _db.storeValues
|
yield* _db.storeValues
|
||||||
.watchObject(key.id, fireImmediately: true)
|
.watchObject(key.id, fireImmediately: true)
|
||||||
@@ -100,6 +109,7 @@ class IsarStoreRepository extends IsarDatabaseRepository {
|
|||||||
return StoreValue(key.id, intValue: intValue, strValue: strValue);
|
return StoreValue(key.id, intValue: intValue, strValue: strValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<StoreDto<Object>>> getAll() async {
|
Future<List<StoreDto<Object>>> getAll() async {
|
||||||
final entities = await _db.storeValues
|
final entities = await _db.storeValues
|
||||||
.filter()
|
.filter()
|
||||||
|
|||||||
@@ -3,21 +3,24 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/sync_api.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
import 'package:immich_mobile/domain/models/sync_event.model.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
import 'package:immich_mobile/presentation/pages/dev/dev_logger.dart';
|
||||||
import 'package:immich_mobile/services/api.service.dart';
|
import 'package:immich_mobile/services/api.service.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class SyncApiRepository {
|
class SyncApiRepository implements ISyncApiRepository {
|
||||||
final Logger _logger = Logger('SyncApiRepository');
|
final Logger _logger = Logger('SyncApiRepository');
|
||||||
final ApiService _api;
|
final ApiService _api;
|
||||||
SyncApiRepository(this._api);
|
SyncApiRepository(this._api);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> ack(List<String> data) {
|
Future<void> ack(List<String> data) {
|
||||||
return _api.syncApi.sendSyncAck(SyncAckSetDto(acks: data));
|
return _api.syncApi.sendSyncAck(SyncAckSetDto(acks: data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> streamChanges(
|
Future<void> streamChanges(
|
||||||
Function(List<SyncEvent>, Function() abort) onData, {
|
Function(List<SyncEvent>, Function() abort) onData, {
|
||||||
int batchSize = kSyncEventBatchSize,
|
int batchSize = kSyncEventBatchSize,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/sync_stream.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/exif.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/partner.entity.drift.dart';
|
||||||
@@ -9,12 +10,14 @@ import 'package:logging/logging.dart';
|
|||||||
import 'package:openapi/api.dart' as api show AssetVisibility;
|
import 'package:openapi/api.dart' as api show AssetVisibility;
|
||||||
import 'package:openapi/api.dart' hide AssetVisibility;
|
import 'package:openapi/api.dart' hide AssetVisibility;
|
||||||
|
|
||||||
class SyncStreamRepository extends DriftDatabaseRepository {
|
class DriftSyncStreamRepository extends DriftDatabaseRepository
|
||||||
|
implements ISyncStreamRepository {
|
||||||
final Logger _logger = Logger('DriftSyncStreamRepository');
|
final Logger _logger = Logger('DriftSyncStreamRepository');
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
|
|
||||||
SyncStreamRepository(super.db) : _db = db;
|
DriftSyncStreamRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async {
|
Future<void> deleteUsersV1(Iterable<SyncUserDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -31,6 +34,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateUsersV1(Iterable<SyncUserV1> data) async {
|
Future<void> updateUsersV1(Iterable<SyncUserV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -53,6 +57,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data) async {
|
Future<void> deletePartnerV1(Iterable<SyncPartnerDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -72,6 +77,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data) async {
|
Future<void> updatePartnerV1(Iterable<SyncPartnerV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _db.batch((batch) {
|
await _db.batch((batch) {
|
||||||
@@ -95,6 +101,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
Future<void> deleteAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _deleteAssetsV1(data);
|
await _deleteAssetsV1(data);
|
||||||
@@ -104,6 +111,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async {
|
Future<void> updateAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetsV1(data);
|
await _updateAssetsV1(data);
|
||||||
@@ -113,6 +121,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
Future<void> deletePartnerAssetsV1(Iterable<SyncAssetDeleteV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _deleteAssetsV1(data);
|
await _deleteAssetsV1(data);
|
||||||
@@ -122,6 +131,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async {
|
Future<void> updatePartnerAssetsV1(Iterable<SyncAssetV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetsV1(data);
|
await _updateAssetsV1(data);
|
||||||
@@ -131,6 +141,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
Future<void> updateAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetExifV1(data);
|
await _updateAssetExifV1(data);
|
||||||
@@ -140,6 +151,7 @@ class SyncStreamRepository extends DriftDatabaseRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
Future<void> updatePartnerAssetsExifV1(Iterable<SyncAssetExifV1> data) async {
|
||||||
try {
|
try {
|
||||||
await _updateAssetExifV1(data);
|
await _updateAssetExifV1(data);
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ import 'dart:async';
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/timeline.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
import 'package:immich_mobile/domain/models/timeline.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:stream_transform/stream_transform.dart';
|
import 'package:stream_transform/stream_transform.dart';
|
||||||
|
|
||||||
class DriftTimelineRepository extends DriftDatabaseRepository {
|
class DriftTimelineRepository extends DriftDatabaseRepository
|
||||||
|
implements ITimelineRepository {
|
||||||
final Drift _db;
|
final Drift _db;
|
||||||
|
|
||||||
const DriftTimelineRepository(super._db) : _db = _db;
|
const DriftTimelineRepository(super._db) : _db = _db;
|
||||||
@@ -26,6 +28,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
return buckets;
|
return buckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<List<Bucket>> watchMainBucket(
|
Stream<List<Bucket>> watchMainBucket(
|
||||||
List<String> userIds, {
|
List<String> userIds, {
|
||||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
@@ -46,6 +49,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
.throttle(const Duration(seconds: 3), trailing: true);
|
.throttle(const Duration(seconds: 3), trailing: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<BaseAsset>> getMainBucketAssets(
|
Future<List<BaseAsset>> getMainBucketAssets(
|
||||||
List<String> userIds, {
|
List<String> userIds, {
|
||||||
required int offset,
|
required int offset,
|
||||||
@@ -86,6 +90,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Stream<List<Bucket>> watchLocalBucket(
|
Stream<List<Bucket>> watchLocalBucket(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
GroupAssetsBy groupBy = GroupAssetsBy.day,
|
||||||
@@ -119,6 +124,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
|
|||||||
}).watch();
|
}).watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<BaseAsset>> getLocalBucketAssets(
|
Future<List<BaseAsset>> getLocalBucketAssets(
|
||||||
String albumId, {
|
String albumId, {
|
||||||
required int offset,
|
required int offset,
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'
|
import 'package:immich_mobile/infrastructure/entities/user.entity.dart'
|
||||||
as entity;
|
as entity;
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class IsarUserRepository extends IsarDatabaseRepository {
|
class IsarUserRepository extends IsarDatabaseRepository
|
||||||
|
implements IUserRepository {
|
||||||
final Isar _db;
|
final Isar _db;
|
||||||
const IsarUserRepository(super.db) : _db = db;
|
const IsarUserRepository(super.db) : _db = db;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> delete(List<String> ids) async {
|
Future<void> delete(List<String> ids) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.deleteAllById(ids);
|
await _db.users.deleteAllById(ids);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> deleteAll() async {
|
Future<void> deleteAll() async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.clear();
|
await _db.users.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<UserDto>> getAll({SortUserBy? sortBy}) async {
|
Future<List<UserDto>> getAll({SortUserBy? sortBy}) async {
|
||||||
return (await _db.users
|
return (await _db.users
|
||||||
.where()
|
.where()
|
||||||
@@ -35,14 +39,17 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<UserDto?> getByUserId(String id) async {
|
Future<UserDto?> getByUserId(String id) async {
|
||||||
return (await _db.users.getById(id))?.toDto();
|
return (await _db.users.getById(id))?.toDto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<UserDto?>> getByUserIds(List<String> ids) async {
|
Future<List<UserDto?>> getByUserIds(List<String> ids) async {
|
||||||
return (await _db.users.getAllById(ids)).map((u) => u?.toDto()).toList();
|
return (await _db.users.getAllById(ids)).map((u) => u?.toDto()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> insert(UserDto user) async {
|
Future<bool> insert(UserDto user) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.put(entity.User.fromDto(user));
|
await _db.users.put(entity.User.fromDto(user));
|
||||||
@@ -50,6 +57,7 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<UserDto> update(UserDto user) async {
|
Future<UserDto> update(UserDto user) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.put(entity.User.fromDto(user));
|
await _db.users.put(entity.User.fromDto(user));
|
||||||
@@ -57,6 +65,7 @@ class IsarUserRepository extends IsarDatabaseRepository {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> updateAll(List<UserDto> users) async {
|
Future<bool> updateAll(List<UserDto> users) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
await _db.users.putAll(users.map(entity.User.fromDto).toList());
|
await _db.users.putAll(users.map(entity.User.fromDto).toList());
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/user.model.dart';
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/api.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/api.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
import 'package:immich_mobile/infrastructure/utils/user.converter.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class UserApiRepository extends ApiRepository {
|
class UserApiRepository extends ApiRepository implements IUserApiRepository {
|
||||||
final UsersApi _api;
|
final UsersApi _api;
|
||||||
const UserApiRepository(this._api);
|
const UserApiRepository(this._api);
|
||||||
|
|
||||||
|
@override
|
||||||
Future<UserDto?> getMyUser() async {
|
Future<UserDto?> getMyUser() async {
|
||||||
final (adminDto, preferenceDto) =
|
final (adminDto, preferenceDto) =
|
||||||
await (_api.getMyUser(), _api.getMyPreferences()).wait;
|
await (_api.getMyUser(), _api.getMyPreferences()).wait;
|
||||||
@@ -18,6 +20,7 @@ class UserApiRepository extends ApiRepository {
|
|||||||
return UserConverter.fromAdminDto(adminDto, preferenceDto);
|
return UserConverter.fromAdminDto(adminDto, preferenceDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> createProfileImage({
|
Future<String> createProfileImage({
|
||||||
required String name,
|
required String name,
|
||||||
required Uint8List data,
|
required Uint8List data,
|
||||||
@@ -30,6 +33,7 @@ class UserApiRepository extends ApiRepository {
|
|||||||
return res.profileImagePath;
|
return res.profileImagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<UserDto>> getAll() async {
|
Future<List<UserDto>> getAll() async {
|
||||||
final dto = await checkNull(_api.searchUsers());
|
final dto = await checkNull(_api.searchUsers());
|
||||||
return dto.map(UserConverter.fromSimpleUserDto).toList();
|
return dto.map(UserConverter.fromSimpleUserDto).toList();
|
||||||
|
|||||||
16
mobile/lib/interfaces/activity_api.interface.dart
Normal file
16
mobile/lib/interfaces/activity_api.interface.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:immich_mobile/models/activities/activity.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IActivityApiRepository {
|
||||||
|
Future<List<Activity>> getAll(
|
||||||
|
String albumId, {
|
||||||
|
String? assetId,
|
||||||
|
});
|
||||||
|
Future<Activity> create(
|
||||||
|
String albumId,
|
||||||
|
ActivityType type, {
|
||||||
|
String? assetId,
|
||||||
|
String? comment,
|
||||||
|
});
|
||||||
|
Future<void> delete(String id);
|
||||||
|
Future<ActivityStats> getStats(String albumId, {String? assetId});
|
||||||
|
}
|
||||||
55
mobile/lib/interfaces/album.interface.dart
Normal file
55
mobile/lib/interfaces/album.interface.dart
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
import 'package:immich_mobile/models/albums/album_search.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IAlbumRepository implements IDatabaseRepository {
|
||||||
|
Future<Album> create(Album album);
|
||||||
|
|
||||||
|
Future<Album?> get(int id);
|
||||||
|
|
||||||
|
Future<Album?> getByName(
|
||||||
|
String name, {
|
||||||
|
bool? shared,
|
||||||
|
bool? remote,
|
||||||
|
bool? owner,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<Album>> getAll({
|
||||||
|
bool? shared,
|
||||||
|
bool? remote,
|
||||||
|
int? ownerId,
|
||||||
|
AlbumSort? sortBy,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Album> update(Album album);
|
||||||
|
|
||||||
|
Future<void> delete(int albumId);
|
||||||
|
|
||||||
|
Future<void> deleteAllLocal();
|
||||||
|
|
||||||
|
Future<int> count({bool? local});
|
||||||
|
|
||||||
|
Future<void> addUsers(Album album, List<UserDto> users);
|
||||||
|
|
||||||
|
Future<void> removeUsers(Album album, List<UserDto> users);
|
||||||
|
|
||||||
|
Future<void> addAssets(Album album, List<Asset> assets);
|
||||||
|
|
||||||
|
Future<void> removeAssets(Album album, List<Asset> assets);
|
||||||
|
|
||||||
|
Future<Album> recalculateMetadata(Album album);
|
||||||
|
|
||||||
|
Future<List<Album>> search(String searchTerm, QuickFilterMode filterMode);
|
||||||
|
|
||||||
|
Stream<List<Album>> watchRemoteAlbums();
|
||||||
|
|
||||||
|
Stream<List<Album>> watchLocalAlbums();
|
||||||
|
|
||||||
|
Stream<Album?> watchAlbum(int id);
|
||||||
|
|
||||||
|
Future<void> clearTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AlbumSort { remoteId, localId }
|
||||||
42
mobile/lib/interfaces/album_api.interface.dart
Normal file
42
mobile/lib/interfaces/album_api.interface.dart
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAlbumApiRepository {
|
||||||
|
Future<Album> get(String id);
|
||||||
|
|
||||||
|
Future<List<Album>> getAll({bool? shared});
|
||||||
|
|
||||||
|
Future<Album> create(
|
||||||
|
String name, {
|
||||||
|
required Iterable<String> assetIds,
|
||||||
|
Iterable<String> sharedUserIds = const [],
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Album> update(
|
||||||
|
String albumId, {
|
||||||
|
String? name,
|
||||||
|
String? thumbnailAssetId,
|
||||||
|
String? description,
|
||||||
|
bool? activityEnabled,
|
||||||
|
SortOrder? sortOrder,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> delete(String albumId);
|
||||||
|
|
||||||
|
Future<({List<String> added, List<String> duplicates})> addAssets(
|
||||||
|
String albumId,
|
||||||
|
Iterable<String> assetIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<({List<String> removed, List<String> failed})> removeAssets(
|
||||||
|
String albumId,
|
||||||
|
Iterable<String> assetIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<Album> addUsers(
|
||||||
|
String albumId,
|
||||||
|
Iterable<String> userIds,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> removeUser(String albumId, {required String userId});
|
||||||
|
}
|
||||||
21
mobile/lib/interfaces/album_media.interface.dart
Normal file
21
mobile/lib/interfaces/album_media.interface.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAlbumMediaRepository {
|
||||||
|
Future<List<Album>> getAll();
|
||||||
|
|
||||||
|
Future<List<String>> getAssetIds(String albumId);
|
||||||
|
|
||||||
|
Future<int> getAssetCount(String albumId);
|
||||||
|
|
||||||
|
Future<List<Asset>> getAssets(
|
||||||
|
String albumId, {
|
||||||
|
int start = 0,
|
||||||
|
int end = 0x7fffffffffffffff,
|
||||||
|
DateTime? modifiedFrom,
|
||||||
|
DateTime? modifiedUntil,
|
||||||
|
bool orderByModificationDate = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Album> get(String id);
|
||||||
|
}
|
||||||
68
mobile/lib/interfaces/asset.interface.dart
Normal file
68
mobile/lib/interfaces/asset.interface.dart
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
|
||||||
|
abstract interface class IAssetRepository implements IDatabaseRepository {
|
||||||
|
Future<Asset?> getByRemoteId(String id);
|
||||||
|
|
||||||
|
Future<Asset?> getByOwnerIdChecksum(int ownerId, String checksum);
|
||||||
|
|
||||||
|
Future<List<Asset>> getAllByRemoteId(
|
||||||
|
Iterable<String> ids, {
|
||||||
|
AssetState? state,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<Asset?>> getAllByOwnerIdChecksum(
|
||||||
|
List<int> ids,
|
||||||
|
List<String> checksums,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<List<Asset>> getAll({
|
||||||
|
required String ownerId,
|
||||||
|
AssetState? state,
|
||||||
|
AssetSort? sortBy,
|
||||||
|
int? limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<List<Asset>> getAllLocal();
|
||||||
|
|
||||||
|
Future<List<Asset>> getByAlbum(
|
||||||
|
Album album, {
|
||||||
|
Iterable<String> notOwnedBy = const [],
|
||||||
|
String? ownerId,
|
||||||
|
AssetState? state,
|
||||||
|
AssetSort? sortBy,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset> update(Asset asset);
|
||||||
|
|
||||||
|
Future<List<Asset>> updateAll(List<Asset> assets);
|
||||||
|
|
||||||
|
Future<void> deleteAllByRemoteId(List<String> ids, {AssetState? state});
|
||||||
|
|
||||||
|
Future<void> deleteByIds(List<int> ids);
|
||||||
|
|
||||||
|
Future<List<Asset>> getMatches({
|
||||||
|
required List<Asset> assets,
|
||||||
|
required String ownerId,
|
||||||
|
AssetState? state,
|
||||||
|
int limit = 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> upsertDuplicatedAssets(Iterable<String> duplicatedAssets);
|
||||||
|
|
||||||
|
Future<List<String>> getAllDuplicatedAssetIds();
|
||||||
|
|
||||||
|
Future<List<Asset>> getStackAssets(String stackId);
|
||||||
|
|
||||||
|
Future<void> clearTable();
|
||||||
|
|
||||||
|
Stream<Asset?> watchAsset(int id, {bool fireImmediately = false});
|
||||||
|
|
||||||
|
Future<List<Asset>> getTrashAssets(String userId);
|
||||||
|
|
||||||
|
Future<List<Asset>> getRecentlyTakenAssets(String userId);
|
||||||
|
Future<List<Asset>> getMotionAssets(String userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AssetSort { checksum, ownerIdChecksum }
|
||||||
26
mobile/lib/interfaces/asset_api.interface.dart
Normal file
26
mobile/lib/interfaces/asset_api.interface.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAssetApiRepository {
|
||||||
|
// Future<Asset> get(String id);
|
||||||
|
|
||||||
|
// Future<List<Asset>> getAll();
|
||||||
|
|
||||||
|
// Future<Asset> create(Asset asset);
|
||||||
|
|
||||||
|
Future<Asset> update(
|
||||||
|
String id, {
|
||||||
|
String? description,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Future<void> delete(String id);
|
||||||
|
|
||||||
|
Future<List<Asset>> search({List<String> personIds = const []});
|
||||||
|
|
||||||
|
Future<void> updateVisibility(
|
||||||
|
List<String> list,
|
||||||
|
AssetVisibilityEnum visibility,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<String?> getAssetMIMEType(String id);
|
||||||
|
}
|
||||||
10
mobile/lib/interfaces/asset_media.interface.dart
Normal file
10
mobile/lib/interfaces/asset_media.interface.dart
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IAssetMediaRepository {
|
||||||
|
Future<List<String>> deleteAll(List<String> ids);
|
||||||
|
|
||||||
|
Future<Asset?> get(String id);
|
||||||
|
|
||||||
|
/// Obtaining the correct original filename of the asset
|
||||||
|
Future<String?> getOriginalFilename(String id);
|
||||||
|
}
|
||||||
11
mobile/lib/interfaces/auth.interface.dart
Normal file
11
mobile/lib/interfaces/auth.interface.dart
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
import 'package:immich_mobile/models/auth/auxilary_endpoint.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IAuthRepository implements IDatabaseRepository {
|
||||||
|
Future<void> clearLocalData();
|
||||||
|
String getAccessToken();
|
||||||
|
bool getEndpointSwitchingFeature();
|
||||||
|
String? getPreferredWifiName();
|
||||||
|
String? getLocalEndpoint();
|
||||||
|
List<AuxilaryEndpoint> getExternalEndpointList();
|
||||||
|
}
|
||||||
14
mobile/lib/interfaces/auth_api.interface.dart
Normal file
14
mobile/lib/interfaces/auth_api.interface.dart
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IAuthApiRepository {
|
||||||
|
Future<LoginResponse> login(String email, String password);
|
||||||
|
|
||||||
|
Future<void> logout();
|
||||||
|
|
||||||
|
Future<void> changePassword(String newPassword);
|
||||||
|
|
||||||
|
Future<bool> unlockPinCode(String pinCode);
|
||||||
|
Future<void> lockPinCode();
|
||||||
|
|
||||||
|
Future<void> setupPinCode(String pinCode);
|
||||||
|
}
|
||||||
16
mobile/lib/interfaces/backup_album.interface.dart
Normal file
16
mobile/lib/interfaces/backup_album.interface.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
|
||||||
|
abstract interface class IBackupAlbumRepository implements IDatabaseRepository {
|
||||||
|
Future<List<BackupAlbum>> getAll({BackupAlbumSort? sort});
|
||||||
|
|
||||||
|
Future<List<String>> getIdsBySelection(BackupSelection backup);
|
||||||
|
|
||||||
|
Future<List<BackupAlbum>> getAllBySelection(BackupSelection backup);
|
||||||
|
|
||||||
|
Future<void> updateAll(List<BackupAlbum> backupAlbums);
|
||||||
|
|
||||||
|
Future<void> deleteAll(List<int> ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BackupAlbumSort { id }
|
||||||
6
mobile/lib/interfaces/biometric.interface.dart
Normal file
6
mobile/lib/interfaces/biometric.interface.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:immich_mobile/models/auth/biometric_status.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IBiometricRepository {
|
||||||
|
Future<BiometricStatus> getStatus();
|
||||||
|
Future<bool> authenticate(String? message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/models/cast/cast_manager_state.dart';
|
||||||
|
|
||||||
|
abstract interface class ICastDestinationService {
|
||||||
|
Future<bool> initialize();
|
||||||
|
CastDestinationType getType();
|
||||||
|
|
||||||
|
void Function(bool)? onConnectionState;
|
||||||
|
|
||||||
|
void Function(Duration)? onCurrentTime;
|
||||||
|
void Function(Duration)? onDuration;
|
||||||
|
|
||||||
|
void Function(String)? onReceiverName;
|
||||||
|
void Function(CastState)? onCastState;
|
||||||
|
|
||||||
|
Future<void> connect(dynamic device);
|
||||||
|
|
||||||
|
void loadMedia(Asset asset, bool reload);
|
||||||
|
|
||||||
|
void play();
|
||||||
|
void pause();
|
||||||
|
void seekTo(Duration position);
|
||||||
|
void stop();
|
||||||
|
Future<void> disconnect();
|
||||||
|
|
||||||
|
Future<List<(String, CastDestinationType, dynamic)>> getDevices();
|
||||||
|
}
|
||||||
15
mobile/lib/interfaces/download.interface.dart
Normal file
15
mobile/lib/interfaces/download.interface.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
|
||||||
|
abstract interface class IDownloadRepository {
|
||||||
|
void Function(TaskStatusUpdate)? onImageDownloadStatus;
|
||||||
|
void Function(TaskStatusUpdate)? onVideoDownloadStatus;
|
||||||
|
void Function(TaskStatusUpdate)? onLivePhotoDownloadStatus;
|
||||||
|
void Function(TaskProgressUpdate)? onTaskProgress;
|
||||||
|
|
||||||
|
Future<List<TaskRecord>> getLiveVideoTasks();
|
||||||
|
Future<List<bool>> downloadAll(List<DownloadTask> tasks);
|
||||||
|
|
||||||
|
Future<bool> cancel(String id);
|
||||||
|
Future<void> deleteAllTrackingRecords();
|
||||||
|
Future<void> deleteRecordsWithIds(List<String> id);
|
||||||
|
}
|
||||||
16
mobile/lib/interfaces/etag.interface.dart
Normal file
16
mobile/lib/interfaces/etag.interface.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:immich_mobile/entities/etag.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/database.interface.dart';
|
||||||
|
|
||||||
|
abstract interface class IETagRepository implements IDatabaseRepository {
|
||||||
|
Future<ETag?> get(String id);
|
||||||
|
|
||||||
|
Future<ETag?> getById(String id);
|
||||||
|
|
||||||
|
Future<List<String>> getAllIds();
|
||||||
|
|
||||||
|
Future<void> upsertAll(List<ETag> etags);
|
||||||
|
|
||||||
|
Future<void> deleteByIds(List<String> ids);
|
||||||
|
|
||||||
|
Future<void> clearTable();
|
||||||
|
}
|
||||||
36
mobile/lib/interfaces/file_media.interface.dart
Normal file
36
mobile/lib/interfaces/file_media.interface.dart
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IFileMediaRepository {
|
||||||
|
Future<Asset?> saveImage(
|
||||||
|
Uint8List data, {
|
||||||
|
required String title,
|
||||||
|
String? relativePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset?> saveImageWithFile(
|
||||||
|
String filePath, {
|
||||||
|
String? title,
|
||||||
|
String? relativePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset?> saveVideo(
|
||||||
|
File file, {
|
||||||
|
required String title,
|
||||||
|
String? relativePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Asset?> saveLivePhoto({
|
||||||
|
required File image,
|
||||||
|
required File video,
|
||||||
|
required String title,
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> clearFileCache();
|
||||||
|
|
||||||
|
Future<void> enableBackgroundAccess();
|
||||||
|
|
||||||
|
Future<void> requestExtendedPermissions();
|
||||||
|
}
|
||||||
6
mobile/lib/interfaces/folder_api.interface.dart
Normal file
6
mobile/lib/interfaces/folder_api.interface.dart
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
|
||||||
|
abstract interface class IFolderApiRepository {
|
||||||
|
Future<List<String>> getAllUniquePaths();
|
||||||
|
Future<List<Asset>> getAssetsForPath(String? path);
|
||||||
|
}
|
||||||
5
mobile/lib/interfaces/local_files_manager.interface.dart
Normal file
5
mobile/lib/interfaces/local_files_manager.interface.dart
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
abstract interface class ILocalFilesManager {
|
||||||
|
Future<bool> moveToTrash(List<String> mediaUrls);
|
||||||
|
Future<bool> restoreFromTrash(String fileName, int type);
|
||||||
|
Future<bool> requestManageMediaPermission();
|
||||||
|
}
|
||||||
4
mobile/lib/interfaces/network.interface.dart
Normal file
4
mobile/lib/interfaces/network.interface.dart
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
abstract interface class INetworkRepository {
|
||||||
|
Future<String?> getWifiName();
|
||||||
|
Future<String?> getWifiIp();
|
||||||
|
}
|
||||||
8
mobile/lib/interfaces/partner.interface.dart
Normal file
8
mobile/lib/interfaces/partner.interface.dart
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
|
||||||
|
abstract class IPartnerRepository {
|
||||||
|
Future<List<UserDto>> getSharedWith();
|
||||||
|
Future<List<UserDto>> getSharedBy();
|
||||||
|
Stream<List<UserDto>> watchSharedWith();
|
||||||
|
Stream<List<UserDto>> watchSharedBy();
|
||||||
|
}
|
||||||
13
mobile/lib/interfaces/partner_api.interface.dart
Normal file
13
mobile/lib/interfaces/partner_api.interface.dart
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/user.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IPartnerApiRepository {
|
||||||
|
Future<List<UserDto>> getAll(Direction direction);
|
||||||
|
Future<UserDto> create(String id);
|
||||||
|
Future<UserDto> update(String id, {required bool inTimeline});
|
||||||
|
Future<void> delete(String id);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Direction {
|
||||||
|
sharedWithMe,
|
||||||
|
sharedByMe,
|
||||||
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
|
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
abstract interface class IPersonApiRepository {
|
||||||
|
Future<List<Person>> getAll();
|
||||||
|
Future<Person> update(String id, {String? name});
|
||||||
|
}
|
||||||
|
|
||||||
class Person {
|
class Person {
|
||||||
Person({
|
Person({
|
||||||
required this.id,
|
required this.id,
|
||||||
5
mobile/lib/interfaces/secure_storage.interface.dart
Normal file
5
mobile/lib/interfaces/secure_storage.interface.dart
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
abstract interface class ISecureStorageRepository {
|
||||||
|
Future<String?> read(String key);
|
||||||
|
Future<void> write(String key, String value);
|
||||||
|
Future<void> delete(String key);
|
||||||
|
}
|
||||||
9
mobile/lib/interfaces/sessions_api.interface.dart
Normal file
9
mobile/lib/interfaces/sessions_api.interface.dart
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import 'package:immich_mobile/models/sessions/session_create_response.model.dart';
|
||||||
|
|
||||||
|
abstract interface class ISessionAPIRepository {
|
||||||
|
Future<SessionCreateResponse> createSession(
|
||||||
|
String deviceName,
|
||||||
|
String deviceOS, {
|
||||||
|
int? duration,
|
||||||
|
});
|
||||||
|
}
|
||||||
7
mobile/lib/interfaces/share_handler.interface.dart
Normal file
7
mobile/lib/interfaces/share_handler.interface.dart
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
||||||
|
|
||||||
|
abstract interface class IShareHandlerRepository {
|
||||||
|
void Function(List<ShareIntentAttachment>)? onSharedMedia;
|
||||||
|
|
||||||
|
Future<void> init();
|
||||||
|
}
|
||||||
39
mobile/lib/interfaces/timeline.interface.dart
Normal file
39
mobile/lib/interfaces/timeline.interface.dart
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
|
||||||
|
|
||||||
|
abstract class ITimelineRepository {
|
||||||
|
Future<List<String>> getTimelineUserIds(String id);
|
||||||
|
|
||||||
|
Stream<List<String>> watchTimelineUsers(String id);
|
||||||
|
|
||||||
|
Stream<RenderList> watchArchiveTimeline(String userId);
|
||||||
|
Stream<RenderList> watchFavoriteTimeline(String userId);
|
||||||
|
Stream<RenderList> watchTrashTimeline(String userId);
|
||||||
|
Stream<RenderList> watchAlbumTimeline(
|
||||||
|
Album album,
|
||||||
|
GroupAssetsBy groupAssetsBy,
|
||||||
|
);
|
||||||
|
Stream<RenderList> watchAllVideosTimeline(String userId);
|
||||||
|
|
||||||
|
Stream<RenderList> watchHomeTimeline(
|
||||||
|
String userId,
|
||||||
|
GroupAssetsBy groupAssetsBy,
|
||||||
|
);
|
||||||
|
Stream<RenderList> watchMultiUsersTimeline(
|
||||||
|
List<String> userIds,
|
||||||
|
GroupAssetsBy groupAssetsBy,
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<RenderList> getTimelineFromAssets(
|
||||||
|
List<Asset> assets,
|
||||||
|
GroupAssetsBy getGroupByOption,
|
||||||
|
);
|
||||||
|
|
||||||
|
Stream<RenderList> watchAssetSelectionTimeline(String userId);
|
||||||
|
|
||||||
|
Stream<RenderList> watchLockedTimeline(
|
||||||
|
String userId,
|
||||||
|
GroupAssetsBy groupAssetsBy,
|
||||||
|
);
|
||||||
|
}
|
||||||
11
mobile/lib/interfaces/upload.interface.dart
Normal file
11
mobile/lib/interfaces/upload.interface.dart
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
|
||||||
|
abstract interface class IUploadRepository {
|
||||||
|
void Function(TaskStatusUpdate)? onUploadStatus;
|
||||||
|
void Function(TaskProgressUpdate)? onTaskProgress;
|
||||||
|
|
||||||
|
Future<bool> upload(UploadTask task);
|
||||||
|
Future<bool> cancel(String id);
|
||||||
|
Future<void> deleteAllTrackingRecords();
|
||||||
|
Future<void> deleteRecordsWithIds(List<String> id);
|
||||||
|
}
|
||||||
5
mobile/lib/interfaces/widget.interface.dart
Normal file
5
mobile/lib/interfaces/widget.interface.dart
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
abstract interface class IWidgetRepository {
|
||||||
|
Future<void> saveData(String key, String value);
|
||||||
|
Future<void> refresh(String name);
|
||||||
|
Future<void> setAppGroupId(String appGroupId);
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:immich_mobile/domain/models/person.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/person_api.interface.dart';
|
||||||
|
|
||||||
class SearchLocationFilter {
|
class SearchLocationFilter {
|
||||||
String? country;
|
String? country;
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/person.model.dart';
|
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/person_api.interface.dart';
|
||||||
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
import 'package:immich_mobile/models/search/search_filter.model.dart';
|
||||||
import 'package:immich_mobile/providers/search/paginated_search.provider.dart';
|
import 'package:immich_mobile/providers/search/paginated_search.provider.dart';
|
||||||
import 'package:immich_mobile/providers/search/search_input_focus.provider.dart';
|
import 'package:immich_mobile/providers/search/search_input_focus.provider.dart';
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import 'dart:ui';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/asset_media.interface.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/asset_media.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/asset_media.repository.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
|
import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
|
||||||
import 'package:immich_mobile/providers/image/cache/thumbnail_image_cache_manager.dart';
|
import 'package:immich_mobile/providers/image/cache/thumbnail_image_cache_manager.dart';
|
||||||
|
|
||||||
class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
|
class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
|
||||||
final AssetMediaRepository _assetMediaRepository =
|
final IAssetMediaRepository _assetMediaRepository =
|
||||||
const AssetMediaRepository();
|
const AssetMediaRepository();
|
||||||
final CacheManager? cacheManager;
|
final CacheManager? cacheManager;
|
||||||
|
|
||||||
|
|||||||
@@ -118,8 +118,10 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
}) async {
|
}) async {
|
||||||
await _apiService.setAccessToken(accessToken);
|
await _apiService.setAccessToken(accessToken);
|
||||||
|
|
||||||
await _widgetService.writeSessionKey(accessToken);
|
await _widgetService.writeCredentials(
|
||||||
await _widgetService.writeServerList();
|
Store.get(StoreKey.serverEndpoint),
|
||||||
|
accessToken,
|
||||||
|
);
|
||||||
|
|
||||||
// Get the deviceid from the store if it exists, otherwise generate a new one
|
// Get the deviceid from the store if it exists, otherwise generate a new one
|
||||||
String deviceId =
|
String deviceId =
|
||||||
@@ -188,7 +190,6 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
|
|
||||||
Future<void> saveLocalEndpoint(String url) async {
|
Future<void> saveLocalEndpoint(String url) async {
|
||||||
await Store.put(StoreKey.localEndpoint, url);
|
await Store.put(StoreKey.localEndpoint, url);
|
||||||
await _widgetService.writeServerList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String? getSavedWifiName() {
|
String? getSavedWifiName() {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import 'package:immich_mobile/domain/models/store.model.dart';
|
|||||||
import 'package:immich_mobile/entities/album.entity.dart';
|
import 'package:immich_mobile/entities/album.entity.dart';
|
||||||
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
import 'package:immich_mobile/entities/backup_album.entity.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/album_media.interface.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/backup_album.interface.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/file_media.interface.dart';
|
||||||
import 'package:immich_mobile/models/auth/auth_state.model.dart';
|
import 'package:immich_mobile/models/auth/auth_state.model.dart';
|
||||||
import 'package:immich_mobile/models/backup/available_album.model.dart';
|
import 'package:immich_mobile/models/backup/available_album.model.dart';
|
||||||
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
import 'package:immich_mobile/models/backup/backup_candidate.model.dart';
|
||||||
@@ -22,7 +25,6 @@ import 'package:immich_mobile/providers/auth.provider.dart';
|
|||||||
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
|
import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart';
|
||||||
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
||||||
import 'package:immich_mobile/repositories/album_media.repository.dart';
|
import 'package:immich_mobile/repositories/album_media.repository.dart';
|
||||||
import 'package:immich_mobile/repositories/backup.repository.dart';
|
|
||||||
import 'package:immich_mobile/repositories/file_media.repository.dart';
|
import 'package:immich_mobile/repositories/file_media.repository.dart';
|
||||||
import 'package:immich_mobile/services/background.service.dart';
|
import 'package:immich_mobile/services/background.service.dart';
|
||||||
import 'package:immich_mobile/services/backup.service.dart';
|
import 'package:immich_mobile/services/backup.service.dart';
|
||||||
@@ -106,8 +108,8 @@ class BackupNotifier extends StateNotifier<BackUpState> {
|
|||||||
final AuthState _authState;
|
final AuthState _authState;
|
||||||
final BackgroundService _backgroundService;
|
final BackgroundService _backgroundService;
|
||||||
final GalleryPermissionNotifier _galleryPermissionNotifier;
|
final GalleryPermissionNotifier _galleryPermissionNotifier;
|
||||||
final AlbumMediaRepository _albumMediaRepository;
|
final IAlbumMediaRepository _albumMediaRepository;
|
||||||
final FileMediaRepository _fileMediaRepository;
|
final IFileMediaRepository _fileMediaRepository;
|
||||||
final BackupAlbumService _backupAlbumService;
|
final BackupAlbumService _backupAlbumService;
|
||||||
final Ref ref;
|
final Ref ref;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
|
import 'package:immich_mobile/interfaces/cast_destination_service.interface.dart';
|
||||||
import 'package:immich_mobile/models/cast/cast_manager_state.dart';
|
import 'package:immich_mobile/models/cast/cast_manager_state.dart';
|
||||||
import 'package:immich_mobile/services/gcast.service.dart';
|
import 'package:immich_mobile/services/gcast.service.dart';
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ final castProvider = StateNotifierProvider<CastNotifier, CastManagerState>(
|
|||||||
|
|
||||||
class CastNotifier extends StateNotifier<CastManagerState> {
|
class CastNotifier extends StateNotifier<CastManagerState> {
|
||||||
// more cast providers can be added here (ie Fcast)
|
// more cast providers can be added here (ie Fcast)
|
||||||
final GCastService _gCastService;
|
final ICastDestinationService _gCastService;
|
||||||
|
|
||||||
List<(String, CastDestinationType, dynamic)> discovered = List.empty();
|
List<(String, CastDestinationType, dynamic)> discovered = List.empty();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_album.interface.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_album.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
|
|
||||||
final localAlbumRepository = Provider<DriftLocalAlbumRepository>(
|
final localAlbumRepository = Provider<ILocalAlbumRepository>(
|
||||||
(ref) => DriftLocalAlbumRepository(ref.watch(driftProvider)),
|
(ref) => DriftLocalAlbumRepository(ref.watch(driftProvider)),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/local_asset.interface.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
|
|
||||||
final localAssetRepository = Provider<DriftLocalAssetRepository>(
|
final localAssetRepository = Provider<ILocalAssetRepository>(
|
||||||
(ref) => DriftLocalAssetRepository(ref.watch(driftProvider)),
|
(ref) => DriftLocalAssetRepository(ref.watch(driftProvider)),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/device_asset.interface.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/device_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/device_asset.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
|
|
||||||
final deviceAssetRepositoryProvider = Provider<IsarDeviceAssetRepository>(
|
final deviceAssetRepositoryProvider = Provider<IDeviceAssetRepository>(
|
||||||
(ref) => IsarDeviceAssetRepository(ref.watch(isarProvider)),
|
(ref) => IsarDeviceAssetRepository(ref.watch(isarProvider)),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/exif.interface.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/exif.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/exif.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
@@ -6,5 +7,5 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||||||
part 'exif.provider.g.dart';
|
part 'exif.provider.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
IsarExifRepository exifRepository(Ref ref) =>
|
IExifInfoRepository exifRepository(Ref ref) =>
|
||||||
IsarExifRepository(ref.watch(isarProvider));
|
IsarExifRepository(ref.watch(isarProvider));
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ part of 'exif.provider.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$exifRepositoryHash() => r'bf4a3f6a50d954a23d317659b4f3e2f381066463';
|
String _$exifRepositoryHash() => r'f0abe778ed61fbb257001fdf2ac6e17814011fee';
|
||||||
|
|
||||||
/// See also [exifRepository].
|
/// See also [exifRepository].
|
||||||
@ProviderFor(exifRepository)
|
@ProviderFor(exifRepository)
|
||||||
final exifRepositoryProvider = Provider<IsarExifRepository>.internal(
|
final exifRepositoryProvider = Provider<IExifInfoRepository>.internal(
|
||||||
exifRepository,
|
exifRepository,
|
||||||
name: r'exifRepositoryProvider',
|
name: r'exifRepositoryProvider',
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
@@ -22,6 +22,6 @@ final exifRepositoryProvider = Provider<IsarExifRepository>.internal(
|
|||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef ExifRepositoryRef = ProviderRef<IsarExifRepository>;
|
typedef ExifRepositoryRef = ProviderRef<IExifInfoRepository>;
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/storage.interface.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
||||||
|
|
||||||
final storageRepositoryProvider = Provider<StorageRepository>(
|
final storageRepositoryProvider = Provider<IStorageRepository>(
|
||||||
(ref) => StorageRepository(),
|
(ref) => StorageRepository(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/store.interface.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/store.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
@@ -7,7 +8,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||||||
part 'store.provider.g.dart';
|
part 'store.provider.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
IsarStoreRepository storeRepository(Ref ref) =>
|
IStoreRepository storeRepository(Ref ref) =>
|
||||||
IsarStoreRepository(ref.watch(isarProvider));
|
IsarStoreRepository(ref.watch(isarProvider));
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ part of 'store.provider.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$storeRepositoryHash() => r'659cb134466e4b0d5f04e2fc93e426350d99545f';
|
String _$storeRepositoryHash() => r'99d24875d30c5e86b1c6caa352a0026167114e62';
|
||||||
|
|
||||||
/// See also [storeRepository].
|
/// See also [storeRepository].
|
||||||
@ProviderFor(storeRepository)
|
@ProviderFor(storeRepository)
|
||||||
final storeRepositoryProvider = Provider<IsarStoreRepository>.internal(
|
final storeRepositoryProvider = Provider<IStoreRepository>.internal(
|
||||||
storeRepository,
|
storeRepository,
|
||||||
name: r'storeRepositoryProvider',
|
name: r'storeRepositoryProvider',
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
@@ -22,7 +22,7 @@ final storeRepositoryProvider = Provider<IsarStoreRepository>.internal(
|
|||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef StoreRepositoryRef = ProviderRef<IsarStoreRepository>;
|
typedef StoreRepositoryRef = ProviderRef<IStoreRepository>;
|
||||||
String _$storeServiceHash() => r'250e10497c42df360e9e1f9a618d0b19c1b5b0a0';
|
String _$storeServiceHash() => r'250e10497c42df360e9e1f9a618d0b19c1b5b0a0';
|
||||||
|
|
||||||
/// See also [storeService].
|
/// See also [storeService].
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ final syncApiRepositoryProvider = Provider(
|
|||||||
);
|
);
|
||||||
|
|
||||||
final syncStreamRepositoryProvider = Provider(
|
final syncStreamRepositoryProvider = Provider(
|
||||||
(ref) => SyncStreamRepository(ref.watch(driftProvider)),
|
(ref) => DriftSyncStreamRepository(ref.watch(driftProvider)),
|
||||||
);
|
);
|
||||||
|
|
||||||
final localSyncServiceProvider = Provider(
|
final localSyncServiceProvider = Provider(
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/timeline.interface.dart';
|
||||||
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart';
|
import 'package:immich_mobile/presentation/widgets/timeline/timeline.state.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
||||||
|
|
||||||
final timelineRepositoryProvider = Provider<DriftTimelineRepository>(
|
final timelineRepositoryProvider = Provider<ITimelineRepository>(
|
||||||
(ref) => DriftTimelineRepository(ref.watch(driftProvider)),
|
(ref) => DriftTimelineRepository(ref.watch(driftProvider)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user.interface.dart';
|
||||||
|
import 'package:immich_mobile/domain/interfaces/user_api.interface.dart';
|
||||||
import 'package:immich_mobile/domain/services/user.service.dart';
|
import 'package:immich_mobile/domain/services/user.service.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/user.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/user_api.repository.dart';
|
||||||
@@ -10,16 +12,16 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||||||
part 'user.provider.g.dart';
|
part 'user.provider.g.dart';
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
IsarUserRepository userRepository(Ref ref) =>
|
IUserRepository userRepository(Ref ref) =>
|
||||||
IsarUserRepository(ref.watch(isarProvider));
|
IsarUserRepository(ref.watch(isarProvider));
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
UserApiRepository userApiRepository(Ref ref) =>
|
IUserApiRepository userApiRepository(Ref ref) =>
|
||||||
UserApiRepository(ref.watch(apiServiceProvider).usersApi);
|
UserApiRepository(ref.watch(apiServiceProvider).usersApi);
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
UserService userService(Ref ref) => UserService(
|
UserService userService(Ref ref) => UserService(
|
||||||
isarUserRepository: ref.watch(userRepositoryProvider),
|
userRepository: ref.watch(userRepositoryProvider),
|
||||||
userApiRepository: ref.watch(userApiRepositoryProvider),
|
userApiRepository: ref.watch(userApiRepositoryProvider),
|
||||||
storeService: ref.watch(storeServiceProvider),
|
storeService: ref.watch(storeServiceProvider),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ part of 'user.provider.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$userRepositoryHash() => r'538791a4ad126ed086c9db682c67fc5c654d54f3';
|
String _$userRepositoryHash() => r'1a2ac726bcc44397dcaecf449084fefd336696d4';
|
||||||
|
|
||||||
/// See also [userRepository].
|
/// See also [userRepository].
|
||||||
@ProviderFor(userRepository)
|
@ProviderFor(userRepository)
|
||||||
final userRepositoryProvider = Provider<IsarUserRepository>.internal(
|
final userRepositoryProvider = Provider<IUserRepository>.internal(
|
||||||
userRepository,
|
userRepository,
|
||||||
name: r'userRepositoryProvider',
|
name: r'userRepositoryProvider',
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
@@ -22,12 +22,12 @@ final userRepositoryProvider = Provider<IsarUserRepository>.internal(
|
|||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef UserRepositoryRef = ProviderRef<IsarUserRepository>;
|
typedef UserRepositoryRef = ProviderRef<IUserRepository>;
|
||||||
String _$userApiRepositoryHash() => r'8a7340ca4544c8c6b20225c65bff2abb9e96baa2';
|
String _$userApiRepositoryHash() => r'6b19f2c99fb83162a5ceb91adb8589eaae01bc92';
|
||||||
|
|
||||||
/// See also [userApiRepository].
|
/// See also [userApiRepository].
|
||||||
@ProviderFor(userApiRepository)
|
@ProviderFor(userApiRepository)
|
||||||
final userApiRepositoryProvider = Provider<UserApiRepository>.internal(
|
final userApiRepositoryProvider = Provider<IUserApiRepository>.internal(
|
||||||
userApiRepository,
|
userApiRepository,
|
||||||
name: r'userApiRepositoryProvider',
|
name: r'userApiRepositoryProvider',
|
||||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
@@ -39,8 +39,8 @@ final userApiRepositoryProvider = Provider<UserApiRepository>.internal(
|
|||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef UserApiRepositoryRef = ProviderRef<UserApiRepository>;
|
typedef UserApiRepositoryRef = ProviderRef<IUserApiRepository>;
|
||||||
String _$userServiceHash() => r'181414dddc7891be6237e13d568c287a804228d1';
|
String _$userServiceHash() => r'4a0873357b7115b4d6bfa8e89b847c0b74ce0d93';
|
||||||
|
|
||||||
/// See also [userService].
|
/// See also [userService].
|
||||||
@ProviderFor(userService)
|
@ProviderFor(userService)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user