Compare commits

...

29 Commits

Author SHA1 Message Date
Alex The Bot
37ab37bffc Version v1.85.0 2023-11-08 03:20:59 +00:00
shenlong
664b7106ca feat(mobile): shared album activity disable handling (#4890)
* feat(mobile): shared album activity disable handling

* not show comment/like option on non-shared album, alternative text when activity is disabled

---------

Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2023-11-08 03:07:43 +00:00
Alex
bb28cae671 docs: update (#4893)
* docs: update

* chore:format
2023-11-07 15:52:44 -06:00
shenlong
c2c26c471a fix(mobile): do not show trashed assets in album viewer page (#4894)
Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2023-11-07 13:19:45 -06:00
Strubbl
2dca2850dc Update README.md (#4892)
fix alt parameter spelling of the Discord image tag
2023-11-07 18:57:30 +00:00
dependabot[bot]
7fc8f6433b chore(deps): bump stumpylog/image-cleaner-action from 0.3.0 to 0.4.0 (#4886)
Bumps [stumpylog/image-cleaner-action](https://github.com/stumpylog/image-cleaner-action) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/stumpylog/image-cleaner-action/releases)
- [Changelog](https://github.com/stumpylog/image-cleaner-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stumpylog/image-cleaner-action/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: stumpylog/image-cleaner-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 13:54:18 -05:00
Jason Rasmussen
f6180fccdc chore(server): compose updates (#4878)
* chore: compose updates

* chore: docs for troubleshooting

* chore: add reference in docker compose to docs
2023-11-07 11:34:03 -05:00
martin
9d01885b58 feat(server, web): Album's options (#4870)
* feat: disable activity

* fix: disable reactions

* fix: tests

* fix: tests

* fix: tests

* pr feedback

* pr feedback

* chore: styling & wording

* refactor component

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2023-11-07 04:37:21 +00:00
Jason Rasmussen
ace0a5911c fix(web): optimize deps (#4877) 2023-11-06 22:02:46 -06:00
Fynn Petersen-Frey
21f2d3058a feat(mobile)!: batched full/initial sync (#4840)
* feat(mobile): batched full/initial sync

* use OptionalBetween

* skip/take as integer

---------

Co-authored-by: Fynn Petersen-Frey <zoodyy@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2023-11-06 11:40:43 -06:00
shenlong
26fd9d7e5f feat(mobile): shared album activities (#4833)
* fix(server): global activity like duplicate search

* mobile: user_circle_avatar - fallback to text icon if no profile pic available

* mobile: use favourite icon in search "your activity"

* feat(mobile): shared album activities

* mobile: align hearts with user profile icon

* styling

* replace bottom sheet with dismissible

* add auto focus to the input

---------

Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2023-11-06 09:46:26 -06:00
Jason Rasmussen
c74ea7282a docs: python upload guide (#4867) 2023-11-06 09:08:36 -05:00
Jason Rasmussen
279481ad54 feat(server): make is favorite optional on asset upload (#4865)
* feat(server): make isFavorite optional

* chore: open api

* chore: e2e
2023-11-06 09:04:39 -05:00
Mert
9e7a32804b chore(server): set relations for getByIds (#4855) 2023-11-05 20:15:12 -06:00
martin
a0743d8b7d feat(web): global activity (#4796)
* feat: global activity

* fix: tests

* pr feedback

* use flexbox

* fix: deleted control actions

* fix: flex box

* fix: do not show activity tab by default

* feat: better grouping

* fix: set isShared default value to false

* fix: prevent re-rendering the asset grid

* fix: activity status above the scrollbar

* fix: prevent re-rendering the asset grid

* fix: prevent re-rendering the asset grid

* pr feedback

* pr feedback

* pr feedback

* styling and better thumbnail

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2023-11-05 11:24:43 -06:00
Fynn Petersen-Frey
68000c21a8 fix(mobile): backup indicator wrong when only background backup is enabled (#4842)
Co-authored-by: Fynn Petersen-Frey <zoodyy@users.noreply.github.com>
2023-11-05 10:07:57 -06:00
Jason Rasmussen
e671b30aaf fix(server): duplicate faces bug (#4844) 2023-11-05 10:07:29 -06:00
Sergey Kondrikov
cf1dfdc776 fix(web): unstack after stack child selection (#4834) 2023-11-04 07:59:21 -05:00
doggo
de29480dda fix(mobile): first stack list asset is now highlighted on view (#4802) 2023-11-03 20:43:43 -05:00
Jason Rasmussen
2e424fe249 feat(server): better api error messages (for unhandled exceptions) (#4817)
* feat(server): better error messages

* chore: open api

* chore: remove debug log

* fix: syntax error

* fix: e2e test
2023-11-03 20:33:15 -05:00
Wingy
d4ef6f52bb chore(mobile): change version mismatch text (#4831)
* change version mismatch text

* change text
2023-11-03 20:20:42 -05:00
martin
e1e45f3f32 fix(web): show one face for the same person in the detail panel (#4822) 2023-11-03 16:02:05 -05:00
Jesbin
330f4cadda docs: changes to docker compose command. (#4828) 2023-11-03 16:01:17 -05:00
waclaw66
621eef0edc feat(mobile): share assets from album (#4821)
* share from album

* fix case

* enhance conditional array items
2023-11-03 16:00:55 -05:00
waclaw66
33ce2b7bba fix(mobile): shows asset datetime with original timezone (#4774) 2023-11-03 09:04:41 -05:00
shenlong
81792a5342 fix(mobile): immich app bar tap radius (#4816)
* mobile: tool-tip for server url in app bar dialog

* fix: Add Inkwell around the entire profile image

* mobile: open documentation and github in browser

---------

Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2023-11-03 09:04:06 -05:00
shenlong
5f43971ccf mobile: allow upload if local asset in selection (#4815)
Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2023-11-03 09:03:01 -05:00
Sergey Kondrikov
38443a6068 fix(web): unstacking issues (#4792)
* Fix typo

* Restore asset store consistency after unstacking

* Fix aspect ratio after unstacking
2023-11-03 09:01:48 -05:00
waclaw66
92bb42950e fix(web): scrollbar year label visibility (#4820)
* fixes year label visibility

* format fix
2023-11-03 08:54:02 -05:00
185 changed files with 4868 additions and 2648 deletions

View File

@@ -38,7 +38,7 @@ jobs:
- -
name: Clean temporary images name: Clean temporary images
if: "${{ env.TOKEN != '' }}" if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/ephemeral@v0.3.0 uses: stumpylog/image-cleaner-action/ephemeral@v0.4.0
with: with:
token: "${{ env.TOKEN }}" token: "${{ env.TOKEN }}"
owner: "immich-app" owner: "immich-app"
@@ -70,7 +70,7 @@ jobs:
- -
name: Clean untagged images name: Clean untagged images
if: "${{ env.TOKEN != '' }}" if: "${{ env.TOKEN != '' }}"
uses: stumpylog/image-cleaner-action/untagged@v0.3.0 uses: stumpylog/image-cleaner-action/untagged@v0.4.0
with: with:
token: "${{ env.TOKEN }}" token: "${{ env.TOKEN }}"
owner: "immich-app" owner: "immich-app"

View File

@@ -2,7 +2,7 @@
<br/> <br/>
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-green.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: MIT"></a> <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-green.svg?color=3F51B5&style=for-the-badge&label=License&logoColor=000000&labelColor=ececec" alt="License: MIT"></a>
<a href="https://discord.gg/D8JsnBEuKb"> <a href="https://discord.gg/D8JsnBEuKb">
<img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" atl="Discord"/> <img src="https://img.shields.io/discord/979116623879368755.svg?label=Discord&logo=Discord&style=for-the-badge&logoColor=000000&labelColor=ececec" alt="Discord"/>
</a> </a>
<br/> <br/>
<br/> <br/>

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.84.0 * The version of the OpenAPI document: 1.85.0
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.84.0 * The version of the OpenAPI document: 1.85.0
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.84.0 * The version of the OpenAPI document: 1.85.0
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -4,7 +4,7 @@
* Immich * Immich
* Immich API * Immich API
* *
* The version of the OpenAPI document: 1.84.0 * The version of the OpenAPI document: 1.85.0
* *
* *
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@@ -1,3 +1,7 @@
# See:
# - https://immich.app/docs/developer/setup
# - https://immich.app/docs/developer/troubleshooting
version: "3.8" version: "3.8"
services: services:
@@ -71,10 +75,6 @@ services:
command: npm run dev --host command: npm run dev --host
env_file: env_file:
- .env - .env
environment:
# Rename these values for svelte public interface
- PUBLIC_IMMICH_SERVER_URL=${IMMICH_SERVER_URL}
- PUBLIC_IMMICH_API_URL_EXTERNAL=${IMMICH_API_URL_EXTERNAL}
ports: ports:
- 3000:3000 - 3000:3000
- 24678:24678 - 24678:24678

View File

@@ -7,9 +7,9 @@ services:
build: build:
context: ../server context: ../server
dockerfile: Dockerfile dockerfile: Dockerfile
command: ["./start-server.sh"] command: [ "./start-server.sh" ]
volumes: volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
env_file: env_file:
- .env - .env
@@ -18,19 +18,6 @@ services:
- database - database
- typesense - typesense
immich-machine-learning:
container_name: immich_machine_learning
image: immich-machine-learning:latest
build:
context: ../machine-learning
dockerfile: Dockerfile
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- model-cache:/cache
env_file:
- .env
restart: always
immich-microservices: immich-microservices:
container_name: immich_microservices container_name: immich_microservices
image: immich-microservices:latest image: immich-microservices:latest
@@ -40,9 +27,9 @@ services:
build: build:
context: ../server context: ../server
dockerfile: Dockerfile dockerfile: Dockerfile
command: ["./start-microservices.sh"] command: [ "./start-microservices.sh" ]
volumes: volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
env_file: env_file:
- .env - .env
@@ -64,6 +51,18 @@ services:
depends_on: depends_on:
- immich-server - immich-server
immich-machine-learning:
container_name: immich_machine_learning
image: immich-machine-learning:latest
build:
context: ../machine-learning
dockerfile: Dockerfile
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
typesense: typesense:
container_name: immich_typesense container_name: immich_typesense
image: typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd image: typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd
@@ -73,7 +72,7 @@ services:
# remove this to get debug messages # remove this to get debug messages
- GLOG_minloglevel=1 - GLOG_minloglevel=1
volumes: volumes:
- tsdata:/data - ${UPLOAD_LOCATION}/typesense:/data
restart: always restart: always
redis: redis:
@@ -91,7 +90,7 @@ services:
POSTGRES_USER: ${DB_USERNAME} POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME} POSTGRES_DB: ${DB_DATABASE_NAME}
volumes: volumes:
- pgdata:/var/lib/postgresql/data - ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
restart: always restart: always
immich-proxy: immich-proxy:
@@ -113,6 +112,4 @@ services:
restart: always restart: always
volumes: volumes:
pgdata:
model-cache: model-cache:
tsdata:

View File

@@ -17,13 +17,13 @@ docker exec -t immich_postgres pg_dumpall -c -U postgres | gzip > "/path/to/back
``` ```
```bash title='Restore' ```bash title='Restore'
docker-compose down -v # CAUTION! Deletes all Immich data to start from scratch. docker compose down -v # CAUTION! Deletes all Immich data to start from scratch.
docker-compose pull # Update to latest version of Immich (if desired) docker compose pull # Update to latest version of Immich (if desired)
docker-compose create # Create Docker containers for Immich apps without running them. docker compose create # Create Docker containers for Immich apps without running them.
docker start immich_postgres # Start Postgres server docker start immich_postgres # Start Postgres server
sleep 10 # Wait for Postgres server to start up sleep 10 # Wait for Postgres server to start up
gunzip < "/path/to/backup/dump.sql.gz" | docker exec -i immich_postgres psql -U postgres -d immich # Restore Backup gunzip < "/path/to/backup/dump.sql.gz" | docker exec -i immich_postgres psql -U postgres -d immich # Restore Backup
docker-compose up -d # Start remainder of Immich apps docker compose up -d # Start remainder of Immich apps
``` ```
Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.). Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.).

View File

@@ -0,0 +1,19 @@
# Troubleshooting
:::tip
A great option to get assistance with troubleshooting is to join our [Discord](https://discord.gg/D8JsnBEuKb) server, where we have a dedicated channel for `#contributing`.
:::
## Known Issues
### Running on Windows
Running Immich on Windows can be frustrating and there are lots of ways it can go wrong. Where possible we recommend using Docker on Linux. However, several people have had success running Immich on Windows using Docker via WSL2.
### NTFS Mounted Volumes
The docker-compose.dev.yml and docker-compose.prod.yml use volume mounts for the postgres database. On start-up, postgres will try to `chown` the data directory, but fail. See [this post](https://forums.docker.com/t/data-directory-var-lib-postgresql-data-pgdata-has-wrong-ownership/17963/24) for more information about this issue and possible solutions.
### `Cannot read properties of null (reading 'split')`
This error occurs when trying to access the app via port `3000` instead of `2283`. During development `immich-proxy` runs on port 2283, while `immich-web` runs on `3000`.

View File

@@ -4,6 +4,10 @@ You can use the CLI to upload an existing gallery to the Immich server
[Immich CLI Repository](https://github.com/immich-app/CLI) [Immich CLI Repository](https://github.com/immich-app/CLI)
:::tip Google Photos Takeout
If you are looking to import your Google Photos takeout, we recommed this community maintained tool [immich-go](https://github.com/simulot/immich-go)
:::
## Requirements ## Requirements
- Node.js 16 or above - Node.js 16 or above

View File

@@ -1,5 +1,7 @@
# Facial Recognition # Facial Recognition
## Overview
Immich recognizes faces in your photos and videos and groups them together. You can then assign names to the faces and search for them. Immich recognizes faces in your photos and videos and groups them together. You can then assign names to the faces and search for them.
The list of people is shown in the Explore page. The list of people is shown in the Explore page.
@@ -13,3 +15,16 @@ Upon clicking on a person, a list of assets that contain their face will be show
The asset detail view will also show the faces that are recognized in the asset. The asset detail view will also show the faces that are recognized in the asset.
<img src={require('./img/facial-recognition-3.png').default} title='Facial Recognition 3' /> <img src={require('./img/facial-recognition-3.png').default} title='Facial Recognition 3' />
## Actions
Additional actions you can do with a detected person are:
- Change the feature face photo of the person
- Set date of birth
- Merge two or more detected faces into one person
- Hide face
It can be found from the app bar when you access the detial view of a person
<img src={require('./img/facial-recognition-4.png').default} title='Facial Recognition 4' width="70%"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

View File

@@ -1,6 +1,6 @@
import MobileAppDownload from '../partials/_mobile-app-download.md'; import MobileAppDownload from '../partials/_mobile-app-download.md';
import MobileAppLogin from '../partials/_mobile-app-login.md'; import MobileAppLogin from '../partials/_mobile-app-login.md';
import MobileAppBackup from '../partials/_mobile-app-login.md'; import MobileAppBackup from '../partials/_mobile-app-backup.md';
# Mobile App # Mobile App

View File

@@ -0,0 +1,42 @@
# Python File Upload
```python
#!/usr/bin/python3
import requests
import os
from datetime import datetime
API_KEY = 'YOUR_API_KEY' # replace with a valid api key
BASE_URL = 'http://127.0.0.1:2283/api' # replace as needed
def upload(file):
stats = os.stat(file)
headers = {
'Accept': 'application/json',
'x-api-key': API_KEY
}
data = {
'deviceAssetId': f'{file}-{stats.st_mtime}',
'deviceId': 'python',
'fileCreatedAt': datetime.fromtimestamp(stats.st_mtime),
'fileModifiedAt': datetime.fromtimestamp(stats.st_mtime),
'isFavorite': 'false',
}
files = {
'assetData': open(file, 'rb')
}
response = requests.post(
f'{BASE_URL}/asset/upload', headers=headers, data=data, files=files)
print(response.json())
# {'id': 'ef96f635-61c7-4639-9e60-61a11c4bbfba', 'duplicate': False}
upload('./test.jpg')
```

View File

@@ -17,6 +17,12 @@ The default configuration looks like this:
"targetAudioCodec": "aac", "targetAudioCodec": "aac",
"targetResolution": "720", "targetResolution": "720",
"maxBitrate": "0", "maxBitrate": "0",
"bframes": -1,
"refs": 0,
"gopSize": 0,
"npl": 0,
"temporalAQ": false,
"cqMode": "auto",
"twoPass": false, "twoPass": false,
"transcode": "required", "transcode": "required",
"tonemap": "hable", "tonemap": "hable",
@@ -44,9 +50,15 @@ The default configuration looks like this:
"sidecar": { "sidecar": {
"concurrency": 5 "concurrency": 5
}, },
"library": {
"concurrency": 5
},
"storageTemplateMigration": { "storageTemplateMigration": {
"concurrency": 5 "concurrency": 5
}, },
"migration": {
"concurrency": 5
},
"thumbnailGeneration": { "thumbnailGeneration": {
"concurrency": 5 "concurrency": 5
}, },
@@ -55,16 +67,16 @@ The default configuration looks like this:
} }
}, },
"machineLearning": { "machineLearning": {
"classification": {
"minScore": 0.7,
"enabled": true,
"modelName": "microsoft/resnet-50"
},
"enabled": true, "enabled": true,
"url": "http://immich-machine-learning:3003", "url": "http://immich-machine-learning:3003",
"classification": {
"enabled": true,
"modelName": "microsoft/resnet-50",
"minScore": 0.9
},
"clip": { "clip": {
"enabled": true, "enabled": true,
"modelName": "ViT-B-32::openai" "modelName": "ViT-B-32__openai"
}, },
"facialRecognition": { "facialRecognition": {
"enabled": true, "enabled": true,
@@ -74,6 +86,14 @@ The default configuration looks like this:
"minFaces": 1 "minFaces": 1
} }
}, },
"map": {
"enabled": true,
"tileUrl": "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
},
"reverseGeocoding": {
"enabled": true,
"citiesFileOverride": "cities500"
},
"oauth": { "oauth": {
"enabled": false, "enabled": false,
"issuerUrl": "", "issuerUrl": "",
@@ -96,8 +116,27 @@ The default configuration looks like this:
"thumbnail": { "thumbnail": {
"webpSize": 250, "webpSize": 250,
"jpegSize": 1440, "jpegSize": 1440,
"quality": 90, "quality": 80,
"colorspace": "p3" "colorspace": "p3"
},
"newVersionCheck": {
"enabled": true
},
"trash": {
"enabled": true,
"days": 30
},
"theme": {
"customCss": ""
},
"library": {
"scan": {
"enabled": true,
"cronExpression": "0 0 * * *"
}
},
"stylesheets": {
"css": ""
} }
} }
``` ```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 KiB

After

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

After

Width:  |  Height:  |  Size: 334 KiB

View File

@@ -34,7 +34,7 @@ function HomepageHeader() {
</Link> </Link>
</div> </div>
<img src="/img/immich-screenshots.png" alt="logo" /> <img src="/img/immich-screenshots.png" alt="screenshots" width={'85%'} />
<div className="flex flex-col sm:flex-row place-items-center place-content-center mt-4 gap-1"> <div className="flex flex-col sm:flex-row place-items-center place-content-center mt-4 gap-1">
<div className="h-24"> <div className="h-24">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "machine-learning" name = "machine-learning"
version = "1.84.0" version = "1.85.0"
description = "" description = ""
authors = ["Hau Tran <alex.tran1502@gmail.com>"] authors = ["Hau Tran <alex.tran1502@gmail.com>"]
readme = "README.md" readme = "README.md"

View File

@@ -35,8 +35,8 @@ platform :android do
task: 'bundle', task: 'bundle',
build_type: 'Release', build_type: 'Release',
properties: { properties: {
"android.injected.version.code" => 108, "android.injected.version.code" => 109,
"android.injected.version.name" => "1.84.0", "android.injected.version.name" => "1.85.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')

View File

@@ -23,6 +23,7 @@
"album_viewer_appbar_share_err_title": "Failed to change album title", "album_viewer_appbar_share_err_title": "Failed to change album title",
"album_viewer_appbar_share_leave": "Leave album", "album_viewer_appbar_share_leave": "Leave album",
"album_viewer_appbar_share_remove": "Remove from album", "album_viewer_appbar_share_remove": "Remove from album",
"album_viewer_appbar_share_to": "Share To",
"album_viewer_page_share_add_users": "Add users", "album_viewer_page_share_add_users": "Add users",
"all_people_page_title": "People", "all_people_page_title": "People",
"all_videos_page_title": "Videos", "all_videos_page_title": "Videos",
@@ -372,5 +373,11 @@
"viewer_stack_use_as_main_asset": "Use as Main Asset", "viewer_stack_use_as_main_asset": "Use as Main Asset",
"app_bar_signout_dialog_title": "Sign out", "app_bar_signout_dialog_title": "Sign out",
"app_bar_signout_dialog_content": "Are you sure you wanna sign out?", "app_bar_signout_dialog_content": "Are you sure you wanna sign out?",
"app_bar_signout_dialog_ok": "Yes" "app_bar_signout_dialog_ok": "Yes",
"shared_album_activities_input_hint": "Say something",
"shared_album_activity_remove_title": "Delete Activity",
"shared_album_activity_remove_content": "Do you want to delete this activity?",
"shared_album_activity_setting_title": "Comments & likes",
"shared_album_activity_setting_subtitle": "Let others respond",
"shared_album_activities_input_disable": "Comment is disabled"
} }

View File

@@ -169,4 +169,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382 PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
COCOAPODS: 1.12.1 COCOAPODS: 1.11.3

View File

@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta" desc "iOS Beta"
lane :beta do lane :beta do
increment_version_number( increment_version_number(
version_number: "1.84.0" version_number: "1.85.0"
) )
increment_build_number( increment_build_number(
build_number: latest_testflight_build_number + 1, build_number: latest_testflight_build_number + 1,

View File

@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:timezone/data/latest.dart';
import 'package:immich_mobile/constants/locales.dart'; import 'package:immich_mobile/constants/locales.dart';
import 'package:immich_mobile/modules/backup/background_service/background.service.dart'; import 'package:immich_mobile/modules/backup/background_service/background.service.dart';
import 'package:immich_mobile/modules/backup/models/backup_album.model.dart'; import 'package:immich_mobile/modules/backup/models/backup_album.model.dart';
@@ -77,6 +78,8 @@ Future<void> initApp() async {
log.severe('Catch all error: ${error.toString()} - $error', error, stack); log.severe('Catch all error: ${error.toString()} - $error', error, stack);
return true; return true;
}; };
initializeTimeZones();
} }
Future<Isar> loadDb() async { Future<Isar> loadDb() async {

View File

@@ -0,0 +1,90 @@
import 'package:immich_mobile/shared/models/user.dart';
import 'package:openapi/api.dart';
enum ActivityType { comment, like }
class Activity {
final String id;
final String? assetId;
final String? comment;
final DateTime createdAt;
final ActivityType type;
final User user;
const Activity({
required this.id,
this.assetId,
this.comment,
required this.createdAt,
required this.type,
required this.user,
});
Activity copyWith({
String? id,
String? assetId,
String? comment,
DateTime? createdAt,
ActivityType? type,
User? user,
}) {
return Activity(
id: id ?? this.id,
assetId: assetId ?? this.assetId,
comment: comment ?? this.comment,
createdAt: createdAt ?? this.createdAt,
type: type ?? this.type,
user: user ?? this.user,
);
}
Activity.fromDto(ActivityResponseDto dto)
: id = dto.id,
assetId = dto.assetId,
comment = dto.comment,
createdAt = dto.createdAt,
type = dto.type == ActivityResponseDtoTypeEnum.comment
? ActivityType.comment
: ActivityType.like,
user = User(
email: dto.user.email,
firstName: dto.user.firstName,
lastName: dto.user.lastName,
profileImagePath: dto.user.profileImagePath,
id: dto.user.id,
// Placeholder values
isAdmin: false,
updatedAt: DateTime.now(),
isPartnerSharedBy: false,
isPartnerSharedWith: false,
memoryEnabled: false,
);
@override
String toString() {
return 'Activity(id: $id, assetId: $assetId, comment: $comment, createdAt: $createdAt, type: $type, user: $user)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Activity &&
other.id == id &&
other.assetId == assetId &&
other.comment == comment &&
other.createdAt == createdAt &&
other.type == type &&
other.user == user;
}
@override
int get hashCode {
return id.hashCode ^
assetId.hashCode ^
comment.hashCode ^
createdAt.hashCode ^
type.hashCode ^
user.hashCode;
}
}

View File

@@ -0,0 +1,130 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/activities/models/activity.model.dart';
import 'package:immich_mobile/modules/activities/services/activity.service.dart';
class ActivityNotifier extends StateNotifier<AsyncValue<List<Activity>>> {
final Ref _ref;
final ActivityService _activityService;
final String albumId;
final String? assetId;
ActivityNotifier(
this._ref,
this._activityService,
this.albumId,
this.assetId,
) : super(
const AsyncData([]),
) {
fetchActivity();
}
Future<void> fetchActivity() async {
state = const AsyncLoading();
state = await AsyncValue.guard(
() => _activityService.getAllActivities(albumId, assetId),
);
}
Future<void> removeActivity(String id) async {
final activities = state.asData?.value ?? [];
if (await _activityService.removeActivity(id)) {
final removedActivity = activities.firstWhere((a) => a.id == id);
activities.remove(removedActivity);
state = AsyncData(activities);
if (removedActivity.type == ActivityType.comment) {
_ref
.read(
activityStatisticsStateProvider(
(albumId: albumId, assetId: assetId),
).notifier,
)
.removeActivity();
}
}
}
Future<void> addComment(String comment) async {
final activity = await _activityService.addActivity(
albumId,
ActivityType.comment,
assetId: assetId,
comment: comment,
);
if (activity != null) {
final activities = state.asData?.value ?? [];
state = AsyncData([...activities, activity]);
_ref
.read(
activityStatisticsStateProvider(
(albumId: albumId, assetId: assetId),
).notifier,
)
.addActivity();
if (assetId != null) {
// Add a count to the current album's provider as well
_ref
.read(
activityStatisticsStateProvider(
(albumId: albumId, assetId: null),
).notifier,
)
.addActivity();
}
}
}
Future<void> addLike() async {
final activity = await _activityService
.addActivity(albumId, ActivityType.like, assetId: assetId);
if (activity != null) {
final activities = state.asData?.value ?? [];
state = AsyncData([...activities, activity]);
}
}
}
class ActivityStatisticsNotifier extends StateNotifier<int> {
final String albumId;
final String? assetId;
final ActivityService _activityService;
ActivityStatisticsNotifier(this._activityService, this.albumId, this.assetId)
: super(0) {
fetchStatistics();
}
Future<void> fetchStatistics() async {
state = await _activityService.getStatistics(albumId, assetId: assetId);
}
Future<void> addActivity() async {
state = state + 1;
}
Future<void> removeActivity() async {
state = state - 1;
}
}
typedef ActivityParams = ({String albumId, String? assetId});
final activityStateProvider = StateNotifierProvider.autoDispose
.family<ActivityNotifier, AsyncValue<List<Activity>>, ActivityParams>(
(ref, args) {
return ActivityNotifier(
ref,
ref.watch(activityServiceProvider),
args.albumId,
args.assetId,
);
});
final activityStatisticsStateProvider = StateNotifierProvider.autoDispose
.family<ActivityStatisticsNotifier, int, ActivityParams>((ref, args) {
return ActivityStatisticsNotifier(
ref.watch(activityServiceProvider),
args.albumId,
args.assetId,
);
});

View File

@@ -0,0 +1,85 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/activities/models/activity.model.dart';
import 'package:immich_mobile/shared/providers/api.provider.dart';
import 'package:immich_mobile/shared/services/api.service.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
final activityServiceProvider =
Provider((ref) => ActivityService(ref.watch(apiServiceProvider)));
class ActivityService {
final ApiService _apiService;
final Logger _log = Logger("ActivityService");
ActivityService(this._apiService);
Future<List<Activity>> getAllActivities(
String albumId,
String? assetId,
) async {
try {
final list = await _apiService.activityApi
.getActivities(albumId, assetId: assetId);
return list != null ? list.map(Activity.fromDto).toList() : [];
} catch (e) {
_log.severe(
"failed to fetch activities for albumId - $albumId; assetId - $assetId -> $e",
);
rethrow;
}
}
Future<int> getStatistics(String albumId, {String? assetId}) async {
try {
final dto = await _apiService.activityApi
.getActivityStatistics(albumId, assetId: assetId);
return dto?.comments ?? 0;
} catch (e) {
_log.severe(
"failed to fetch activity statistics for albumId - $albumId; assetId - $assetId -> $e",
);
}
return 0;
}
Future<bool> removeActivity(String id) async {
try {
await _apiService.activityApi.deleteActivity(id);
return true;
} catch (e) {
_log.severe(
"failed to remove activity id - $id -> $e",
);
}
return false;
}
Future<Activity?> addActivity(
String albumId,
ActivityType type, {
String? assetId,
String? comment,
}) async {
try {
final dto = await _apiService.activityApi.createActivity(
ActivityCreateDto(
albumId: albumId,
type: type == ActivityType.comment
? ReactionType.comment
: ReactionType.like,
assetId: assetId,
comment: comment,
),
);
if (dto != null) {
return Activity.fromDto(dto);
}
} catch (e) {
_log.severe(
"failed to add activity for albumId - $albumId; assetId - $assetId -> $e",
);
}
return null;
}
}

View File

@@ -0,0 +1,320 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/activities/models/activity.model.dart';
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
import 'package:immich_mobile/shared/models/store.dart';
import 'package:immich_mobile/shared/ui/confirm_dialog.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
import 'package:immich_mobile/utils/datetime_extensions.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
class ActivitiesPage extends HookConsumerWidget {
final String albumId;
final String? assetId;
final bool withAssetThumbs;
final String appBarTitle;
final bool isOwner;
final bool isReadOnly;
const ActivitiesPage(
this.albumId, {
this.appBarTitle = "",
this.assetId,
this.withAssetThumbs = true,
this.isOwner = false,
this.isReadOnly = false,
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final provider =
activityStateProvider((albumId: albumId, assetId: assetId));
final activities = ref.watch(provider);
final inputController = useTextEditingController();
final inputFocusNode = useFocusNode();
final listViewScrollController = useScrollController();
final currentUser = Store.tryGet(StoreKey.currentUser);
useEffect(
() {
inputFocusNode.requestFocus();
return null;
},
[],
);
buildTitleWithTimestamp(Activity activity, {bool leftAlign = true}) {
final textColor = Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black;
final textStyle = Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: textColor.withOpacity(0.6));
return Row(
mainAxisAlignment: leftAlign
? MainAxisAlignment.start
: MainAxisAlignment.spaceBetween,
mainAxisSize: leftAlign ? MainAxisSize.min : MainAxisSize.max,
children: [
Text(
"${activity.user.firstName} ${activity.user.lastName}",
style: textStyle,
overflow: TextOverflow.ellipsis,
),
if (leftAlign)
Text(
"",
style: textStyle,
),
Expanded(
child: Text(
activity.createdAt.copyWith().timeAgo(),
style: textStyle,
overflow: TextOverflow.ellipsis,
textAlign: leftAlign ? TextAlign.left : TextAlign.right,
),
),
],
);
}
buildAssetThumbnail(Activity activity) {
return withAssetThumbs && activity.assetId != null
? Container(
width: 40,
height: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
image: DecorationImage(
image: CachedNetworkImageProvider(
getThumbnailUrlForRemoteId(
activity.assetId!,
),
cacheKey: getThumbnailCacheKeyForRemoteId(
activity.assetId!,
),
headers: {
"Authorization":
'Bearer ${Store.get(StoreKey.accessToken)}',
},
),
fit: BoxFit.cover,
),
),
child: const SizedBox.shrink(),
)
: null;
}
buildTextField(String? likedId) {
final liked = likedId != null;
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: TextField(
controller: inputController,
enabled: !isReadOnly,
focusNode: inputFocusNode,
textInputAction: TextInputAction.send,
autofocus: false,
decoration: InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
prefixIcon: currentUser != null
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: UserCircleAvatar(
user: currentUser,
size: 30,
radius: 15,
),
)
: null,
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 10),
child: IconButton(
icon: Icon(
liked
? Icons.favorite_rounded
: Icons.favorite_border_rounded,
),
onPressed: () async {
liked
? await ref
.read(provider.notifier)
.removeActivity(likedId)
: await ref.read(provider.notifier).addLike();
},
),
),
suffixIconColor: liked ? Colors.red[700] : null,
hintText: isReadOnly
? 'shared_album_activities_input_disable'.tr()
: 'shared_album_activities_input_hint'.tr(),
hintStyle: TextStyle(
fontWeight: FontWeight.normal,
fontSize: 14,
color: Colors.grey[600],
),
),
onEditingComplete: () async {
await ref.read(provider.notifier).addComment(inputController.text);
inputController.clear();
inputFocusNode.unfocus();
listViewScrollController.animateTo(
listViewScrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 800),
curve: Curves.fastOutSlowIn,
);
},
onTapOutside: (_) => inputFocusNode.unfocus(),
),
);
}
getDismissibleWidget(
Widget widget,
Activity activity,
bool canDelete,
) {
return Dismissible(
key: Key(activity.id),
dismissThresholds: const {
DismissDirection.horizontal: 0.7,
},
direction: DismissDirection.horizontal,
confirmDismiss: (direction) => canDelete
? showDialog(
context: context,
builder: (context) => ConfirmDialog(
onOk: () {},
title: "shared_album_activity_remove_title",
content: "shared_album_activity_remove_content",
ok: "delete_dialog_ok",
),
)
: Future.value(false),
onDismissed: (direction) async =>
await ref.read(provider.notifier).removeActivity(activity.id),
background: Container(
color: canDelete ? Colors.red[400] : Colors.grey[600],
alignment: AlignmentDirectional.centerStart,
child: canDelete
? const Padding(
padding: EdgeInsets.all(15),
child: Icon(
Icons.delete_sweep_rounded,
color: Colors.black,
),
)
: null,
),
secondaryBackground: Container(
color: canDelete ? Colors.red[400] : Colors.grey[600],
alignment: AlignmentDirectional.centerEnd,
child: canDelete
? const Padding(
padding: EdgeInsets.all(15),
child: Icon(
Icons.delete_sweep_rounded,
color: Colors.black,
),
)
: null,
),
child: widget,
);
}
return Scaffold(
appBar: AppBar(title: Text(appBarTitle)),
body: activities.maybeWhen(
orElse: () {
return const Center(child: ImmichLoadingIndicator());
},
data: (data) {
final liked = data.firstWhereOrNull(
(a) =>
a.type == ActivityType.like &&
a.user.id == currentUser?.id &&
a.assetId == assetId,
);
return SafeArea(
child: Stack(
children: [
ListView.builder(
controller: listViewScrollController,
itemCount: data.length + 1,
itemBuilder: (context, index) {
// Vertical gap after the last element
if (index == data.length) {
return const SizedBox(
height: 80,
);
}
final activity = data[index];
final canDelete =
activity.user.id == currentUser?.id || isOwner;
return Padding(
padding: const EdgeInsets.all(5),
child: activity.type == ActivityType.comment
? getDismissibleWidget(
ListTile(
minVerticalPadding: 15,
leading: UserCircleAvatar(user: activity.user),
title: buildTitleWithTimestamp(
activity,
leftAlign: withAssetThumbs &&
activity.assetId != null,
),
titleAlignment: ListTileTitleAlignment.top,
trailing: buildAssetThumbnail(activity),
subtitle: Text(activity.comment!),
),
activity,
canDelete,
)
: getDismissibleWidget(
ListTile(
minVerticalPadding: 15,
leading: Container(
width: 44,
alignment: Alignment.center,
child: Icon(
Icons.favorite_rounded,
color: Colors.red[700],
),
),
title: buildTitleWithTimestamp(activity),
trailing: buildAssetThumbnail(activity),
),
activity,
canDelete,
),
);
},
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Theme.of(context).scaffoldBackgroundColor,
child: buildTextField(liked?.id),
),
),
],
),
);
},
),
);
}
}

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
import 'package:immich_mobile/modules/album/services/album.service.dart'; import 'package:immich_mobile/modules/album/services/album.service.dart';
import 'package:immich_mobile/shared/models/album.dart'; import 'package:immich_mobile/shared/models/album.dart';
import 'package:immich_mobile/shared/models/asset.dart'; import 'package:immich_mobile/shared/models/asset.dart';
@@ -10,7 +11,7 @@ import 'package:immich_mobile/shared/providers/db.provider.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
class SharedAlbumNotifier extends StateNotifier<List<Album>> { class SharedAlbumNotifier extends StateNotifier<List<Album>> {
SharedAlbumNotifier(this._albumService, Isar db) : super([]) { SharedAlbumNotifier(this._albumService, Isar db, this._ref) : super([]) {
final query = db.albums.filter().sharedEqualTo(true).sortByCreatedAtDesc(); final query = db.albums.filter().sharedEqualTo(true).sortByCreatedAtDesc();
query.findAll().then((value) => state = value); query.findAll().then((value) => state = value);
_streamSub = query.watch().listen((data) => state = data); _streamSub = query.watch().listen((data) => state = data);
@@ -18,6 +19,7 @@ class SharedAlbumNotifier extends StateNotifier<List<Album>> {
final AlbumService _albumService; final AlbumService _albumService;
late final StreamSubscription<List<Album>> _streamSub; late final StreamSubscription<List<Album>> _streamSub;
final Ref _ref;
Future<Album?> createSharedAlbum( Future<Album?> createSharedAlbum(
String albumName, String albumName,
@@ -66,6 +68,17 @@ class SharedAlbumNotifier extends StateNotifier<List<Album>> {
return result; return result;
} }
Future<bool> setActivityEnabled(Album album, bool activityEnabled) async {
final result =
await _albumService.setActivityEnabled(album, activityEnabled);
if (result) {
_ref.invalidate(albumDetailProvider(album.id));
}
return result;
}
@override @override
void dispose() { void dispose() {
_streamSub.cancel(); _streamSub.cancel();
@@ -78,5 +91,6 @@ final sharedAlbumProvider =
return SharedAlbumNotifier( return SharedAlbumNotifier(
ref.watch(albumServiceProvider), ref.watch(albumServiceProvider),
ref.watch(dbProvider), ref.watch(dbProvider),
ref,
); );
}); });

View File

@@ -284,6 +284,23 @@ class AlbumService {
return false; return false;
} }
Future<bool> setActivityEnabled(Album album, bool enabled) async {
try {
final result = await _apiService.albumApi.updateAlbumInfo(
album.remoteId!,
UpdateAlbumDto(isActivityEnabled: enabled),
);
if (result != null) {
album.activityEnabled = enabled;
await _db.writeTxn(() => _db.albums.put(album));
return true;
}
} catch (e) {
debugPrint("Error setActivityEnabled ${e.toString()}");
}
return false;
}
Future<bool> deleteAlbum(Album album) async { Future<bool> deleteAlbum(Album album) async {
try { try {
final userId = Store.get(StoreKey.currentUser).isarId; final userId = Store.get(StoreKey.currentUser).isarId;

View File

@@ -3,10 +3,13 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
import 'package:immich_mobile/modules/album/providers/album.provider.dart'; import 'package:immich_mobile/modules/album/providers/album.provider.dart';
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart'; import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
import 'package:immich_mobile/modules/album/providers/album_viewer.provider.dart'; import 'package:immich_mobile/modules/album/providers/album_viewer.provider.dart';
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
import 'package:immich_mobile/shared/ui/share_dialog.dart';
import 'package:immich_mobile/shared/services/share.service.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/models/album.dart'; import 'package:immich_mobile/shared/models/album.dart';
import 'package:immich_mobile/shared/models/asset.dart'; import 'package:immich_mobile/shared/models/asset.dart';
@@ -24,6 +27,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
required this.titleFocusNode, required this.titleFocusNode,
this.onAddPhotos, this.onAddPhotos,
this.onAddUsers, this.onAddUsers,
required this.onActivities,
}) : super(key: key); }) : super(key: key);
final Album album; final Album album;
@@ -33,11 +37,19 @@ class AlbumViewerAppbar extends HookConsumerWidget
final FocusNode titleFocusNode; final FocusNode titleFocusNode;
final Function(Album album)? onAddPhotos; final Function(Album album)? onAddPhotos;
final Function(Album album)? onAddUsers; final Function(Album album)? onAddUsers;
final Function(Album album) onActivities;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final newAlbumTitle = ref.watch(albumViewerProvider).editTitleText; final newAlbumTitle = ref.watch(albumViewerProvider).editTitleText;
final isEditAlbum = ref.watch(albumViewerProvider).isEditAlbum; final isEditAlbum = ref.watch(albumViewerProvider).isEditAlbum;
final comments = album.shared
? ref.watch(
activityStatisticsStateProvider(
(albumId: album.remoteId!, assetId: null),
),
)
: 0;
deleteAlbum() async { deleteAlbum() async {
ImmichLoadingOverlayController.appLoader.show(); ImmichLoadingOverlayController.appLoader.show();
@@ -160,40 +172,81 @@ class AlbumViewerAppbar extends HookConsumerWidget
ImmichLoadingOverlayController.appLoader.hide(); ImmichLoadingOverlayController.appLoader.hide();
} }
buildBottomSheetActionButton() { void handleShareAssets(
WidgetRef ref,
BuildContext context,
Set<Asset> selection,
) {
showDialog(
context: context,
builder: (BuildContext buildContext) {
ref.watch(shareServiceProvider).shareAssets(selection.toList()).then(
(bool status) {
if (!status) {
ImmichToast.show(
context: context,
msg: 'image_viewer_page_state_provider_share_error'.tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
}
Navigator.of(buildContext).pop();
},
);
return const ShareDialog();
},
barrierDismissible: false,
);
}
void onShareAssetsTo() async {
ImmichLoadingOverlayController.appLoader.show();
handleShareAssets(ref, context, selected);
ImmichLoadingOverlayController.appLoader.hide();
}
buildBottomSheetActions() {
if (selected.isNotEmpty) { if (selected.isNotEmpty) {
if (album.ownerId == userId) { return [
return ListTile( ListTile(
leading: const Icon(Icons.delete_sweep_rounded), leading: const Icon(Icons.ios_share_rounded),
title: const Text( title: const Text(
'album_viewer_appbar_share_remove', 'album_viewer_appbar_share_to',
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
).tr(), ).tr(),
onTap: () => onRemoveFromAlbumPressed(), onTap: () => onShareAssetsTo(),
); ),
} else { album.ownerId == userId
return const SizedBox(); ? ListTile(
} leading: const Icon(Icons.delete_sweep_rounded),
title: const Text(
'album_viewer_appbar_share_remove',
style: TextStyle(fontWeight: FontWeight.bold),
).tr(),
onTap: () => onRemoveFromAlbumPressed(),
)
: const SizedBox(),
];
} else { } else {
if (album.ownerId == userId) { return [
return ListTile( album.ownerId == userId
leading: const Icon(Icons.delete_forever_rounded), ? ListTile(
title: const Text( leading: const Icon(Icons.delete_forever_rounded),
'album_viewer_appbar_share_delete', title: const Text(
style: TextStyle(fontWeight: FontWeight.bold), 'album_viewer_appbar_share_delete',
).tr(), style: TextStyle(fontWeight: FontWeight.bold),
onTap: () => onDeleteAlbumPressed(), ).tr(),
); onTap: () => onDeleteAlbumPressed(),
} else { )
return ListTile( : ListTile(
leading: const Icon(Icons.person_remove_rounded), leading: const Icon(Icons.person_remove_rounded),
title: const Text( title: const Text(
'album_viewer_appbar_share_leave', 'album_viewer_appbar_share_leave',
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
).tr(), ).tr(),
onTap: () => onLeaveAlbumPressed(), onTap: () => onLeaveAlbumPressed(),
); ),
} ];
} }
} }
@@ -257,7 +310,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
buildBottomSheetActionButton(), ...buildBottomSheetActions(),
if (selected.isEmpty && onAddPhotos != null) ...commonActions, if (selected.isEmpty && onAddPhotos != null) ...commonActions,
if (selected.isEmpty && if (selected.isEmpty &&
onAddPhotos != null && onAddPhotos != null &&
@@ -271,6 +324,33 @@ class AlbumViewerAppbar extends HookConsumerWidget
); );
} }
Widget buildActivitiesButton() {
return IconButton(
onPressed: () {
onActivities(album);
},
icon: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
Icons.mode_comment_outlined,
),
if (comments != 0)
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
comments.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
),
),
),
],
),
);
}
buildLeadingButton() { buildLeadingButton() {
if (selected.isNotEmpty) { if (selected.isNotEmpty) {
return IconButton( return IconButton(
@@ -314,6 +394,8 @@ class AlbumViewerAppbar extends HookConsumerWidget
title: selected.isNotEmpty ? Text('${selected.length}') : null, title: selected.isNotEmpty ? Text('${selected.length}') : null,
centerTitle: false, centerTitle: false,
actions: [ actions: [
if (album.shared && (album.activityEnabled || comments != 0))
buildActivitiesButton(),
if (album.isRemote) if (album.isRemote)
IconButton( IconButton(
splashRadius: 25, splashRadius: 25,

View File

@@ -23,6 +23,7 @@ class AlbumOptionsPage extends HookConsumerWidget {
final sharedUsers = useState(album.sharedUsers.toList()); final sharedUsers = useState(album.sharedUsers.toList());
final owner = album.owner.value; final owner = album.owner.value;
final userId = ref.watch(authenticationProvider).userId; final userId = ref.watch(authenticationProvider).userId;
final activityEnabled = useState(album.activityEnabled);
final isOwner = owner?.id == userId; final isOwner = owner?.id == userId;
void showErrorMessage() { void showErrorMessage() {
@@ -195,6 +196,31 @@ class AlbumOptionsPage extends HookConsumerWidget {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (isOwner && album.shared)
SwitchListTile.adaptive(
value: activityEnabled.value,
onChanged: (bool value) async {
activityEnabled.value = value;
if (await ref
.read(sharedAlbumProvider.notifier)
.setActivityEnabled(album, value)) {
album.activityEnabled = value;
}
},
activeColor: activityEnabled.value
? Theme.of(context).primaryColor
: Theme.of(context).disabledColor,
dense: true,
title: Text(
"shared_album_activity_setting_title",
style: Theme.of(context)
.textTheme
.labelLarge
?.copyWith(fontWeight: FontWeight.bold),
).tr(),
subtitle:
const Text("shared_album_activity_setting_subtitle").tr(),
),
buildSectionTitle("PEOPLE"), buildSectionTitle("PEOPLE"),
buildOwnerInfo(), buildOwnerInfo(),
buildSharedUsersList(), buildSharedUsersList(),

View File

@@ -232,6 +232,19 @@ class AlbumViewerPage extends HookConsumerWidget {
); );
} }
onActivitiesPressed(Album album) {
if (album.remoteId != null) {
AutoRouter.of(context).push(
ActivitiesRoute(
albumId: album.remoteId!,
appBarTitle: album.name,
isOwner: userId == album.ownerId,
isReadOnly: !album.activityEnabled,
),
);
}
}
return Scaffold( return Scaffold(
appBar: album.when( appBar: album.when(
data: (data) => AlbumViewerAppbar( data: (data) => AlbumViewerAppbar(
@@ -242,6 +255,7 @@ class AlbumViewerPage extends HookConsumerWidget {
selectionDisabled: disableSelection, selectionDisabled: disableSelection,
onAddPhotos: onAddPhotosPressed, onAddPhotos: onAddPhotosPressed,
onAddUsers: onAddUsersPressed, onAddUsers: onAddUsersPressed,
onActivities: onActivitiesPressed,
), ),
error: (error, stackTrace) => AppBar(title: const Text("Error")), error: (error, stackTrace) => AppBar(title: const Text("Error")),
loading: () => AppBar(), loading: () => AppBar(),
@@ -266,6 +280,8 @@ class AlbumViewerPage extends HookConsumerWidget {
], ],
), ),
isOwner: userId == data.ownerId, isOwner: userId == data.ownerId,
sharedAlbumId:
data.shared && data.activityEnabled ? data.remoteId : null,
), ),
), ),
), ),

View File

@@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:timezone/timezone.dart';
import 'package:immich_mobile/modules/asset_viewer/ui/description_input.dart'; import 'package:immich_mobile/modules/asset_viewer/ui/description_input.dart';
import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart'; import 'package:immich_mobile/modules/map/ui/map_thumbnail.dart';
import 'package:immich_mobile/shared/models/asset.dart'; import 'package:immich_mobile/shared/models/asset.dart';
@@ -26,12 +27,36 @@ class ExifBottomSheet extends HookConsumerWidget {
exifInfo.latitude != 0 && exifInfo.latitude != 0 &&
exifInfo.longitude != 0; exifInfo.longitude != 0;
String get formattedDateTime { String formatTimeZone(Duration d) =>
final fileCreatedAt = asset.fileCreatedAt.toLocal(); "GMT${d.isNegative ? '-': '+'}${d.inHours.abs().toString().padLeft(2, '0')}:${d.inMinutes.abs().remainder(60).toString().padLeft(2, '0')}";
final date = DateFormat.yMMMEd().format(fileCreatedAt);
final time = DateFormat.jm().format(fileCreatedAt);
return '$date$time'; String get formattedDateTime {
DateTime dt = asset.fileCreatedAt.toLocal();
String? timeZone;
if (asset.exifInfo?.dateTimeOriginal != null) {
dt = asset.exifInfo!.dateTimeOriginal!;
if (asset.exifInfo?.timeZone != null) {
dt = dt.toUtc();
try {
final location = getLocation(asset.exifInfo!.timeZone!);
dt = TZDateTime.from(dt, location);
} on LocationNotFoundException {
RegExp re = RegExp(r'^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$', caseSensitive: false);
final m = re.firstMatch(asset.exifInfo!.timeZone!);
if (m != null) {
final duration = Duration(hours: int.parse(m.group(1) ?? '0'), minutes: int.parse(m.group(2) ?? '0'));
dt = dt.add(duration);
timeZone = formatTimeZone(duration);
}
}
}
}
final date = DateFormat.yMMMEd().format(dt);
final time = DateFormat.jm().format(dt);
timeZone ??= formatTimeZone(dt.timeZoneOffset);
return '$date$time $timeZone';
} }
Future<Uri?> _createCoordinatesUri(ExifInfo? exifInfo) async { Future<Uri?> _createCoordinatesUri(ExifInfo? exifInfo) async {

View File

@@ -1,6 +1,7 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
import 'package:immich_mobile/shared/models/asset.dart'; import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/providers/asset.provider.dart'; import 'package:immich_mobile/shared/providers/asset.provider.dart';
@@ -16,6 +17,8 @@ class TopControlAppBar extends HookConsumerWidget {
required this.onFavorite, required this.onFavorite,
required this.onUploadPressed, required this.onUploadPressed,
required this.isOwner, required this.isOwner,
required this.shareAlbumId,
required this.onActivitiesPressed,
}) : super(key: key); }) : super(key: key);
final Asset asset; final Asset asset;
@@ -24,14 +27,23 @@ class TopControlAppBar extends HookConsumerWidget {
final VoidCallback? onDownloadPressed; final VoidCallback? onDownloadPressed;
final VoidCallback onToggleMotionVideo; final VoidCallback onToggleMotionVideo;
final VoidCallback onAddToAlbumPressed; final VoidCallback onAddToAlbumPressed;
final VoidCallback onActivitiesPressed;
final Function(Asset) onFavorite; final Function(Asset) onFavorite;
final bool isPlayingMotionVideo; final bool isPlayingMotionVideo;
final bool isOwner; final bool isOwner;
final String? shareAlbumId;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
const double iconSize = 22.0; const double iconSize = 22.0;
final a = ref.watch(assetWatcher(asset)).value ?? asset; final a = ref.watch(assetWatcher(asset)).value ?? asset;
final comments = shareAlbumId != null
? ref.watch(
activityStatisticsStateProvider(
(albumId: shareAlbumId!, assetId: asset.remoteId),
),
)
: 0;
Widget buildFavoriteButton(a) { Widget buildFavoriteButton(a) {
return IconButton( return IconButton(
@@ -94,6 +106,34 @@ class TopControlAppBar extends HookConsumerWidget {
); );
} }
Widget buildActivitiesButton() {
return IconButton(
onPressed: () {
onActivitiesPressed();
},
icon: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.mode_comment_outlined,
color: Colors.grey[200],
),
if (comments != 0)
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
comments.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey[200],
),
),
),
],
),
);
}
Widget buildUploadButton() { Widget buildUploadButton() {
return IconButton( return IconButton(
onPressed: onUploadPressed, onPressed: onUploadPressed,
@@ -130,6 +170,7 @@ class TopControlAppBar extends HookConsumerWidget {
if (asset.isLocal && !asset.isRemote) buildUploadButton(), if (asset.isLocal && !asset.isRemote) buildUploadButton(),
if (asset.isRemote && !asset.isLocal && isOwner) buildDownloadButton(), if (asset.isRemote && !asset.isLocal && isOwner) buildDownloadButton(),
if (asset.isRemote && isOwner) buildAddToAlbumButtom(), if (asset.isRemote && isOwner) buildAddToAlbumButtom(),
if (shareAlbumId != null) buildActivitiesButton(),
buildMoreInfoButton(), buildMoreInfoButton(),
], ],
); );

View File

@@ -49,6 +49,7 @@ class GalleryViewerPage extends HookConsumerWidget {
final int heroOffset; final int heroOffset;
final bool showStack; final bool showStack;
final bool isOwner; final bool isOwner;
final String? sharedAlbumId;
GalleryViewerPage({ GalleryViewerPage({
super.key, super.key,
@@ -58,6 +59,7 @@ class GalleryViewerPage extends HookConsumerWidget {
this.heroOffset = 0, this.heroOffset = 0,
this.showStack = false, this.showStack = false,
this.isOwner = true, this.isOwner = true,
this.sharedAlbumId,
}) : controller = PageController(initialPage: initialIndex); }) : controller = PageController(initialPage: initialIndex);
final PageController controller; final PageController controller;
@@ -327,6 +329,19 @@ class GalleryViewerPage extends HookConsumerWidget {
); );
} }
handleActivities() {
if (sharedAlbumId != null) {
AutoRouter.of(context).push(
ActivitiesRoute(
albumId: sharedAlbumId!,
assetId: asset().remoteId,
withAssetThumbs: false,
isOwner: isOwner,
),
);
}
}
buildAppBar() { buildAppBar() {
return IgnorePointer( return IgnorePointer(
ignoring: !ref.watch(showControlsProvider), ignoring: !ref.watch(showControlsProvider),
@@ -355,6 +370,8 @@ class GalleryViewerPage extends HookConsumerWidget {
isPlayingMotionVideo.value = !isPlayingMotionVideo.value; isPlayingMotionVideo.value = !isPlayingMotionVideo.value;
}), }),
onAddToAlbumPressed: () => addToAlbum(asset()), onAddToAlbumPressed: () => addToAlbum(asset()),
shareAlbumId: sharedAlbumId,
onActivitiesPressed: handleActivities,
), ),
), ),
), ),
@@ -443,7 +460,8 @@ class GalleryViewerPage extends HookConsumerWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
border: index == stackIndex.value border: (stackIndex.value == -1 && index == 0) ||
index == stackIndex.value
? Border.all( ? Border.all(
color: Colors.white, color: Colors.white,
width: 2, width: 2,

View File

@@ -40,7 +40,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
progressInPercentage: 0, progressInPercentage: 0,
cancelToken: CancellationToken(), cancelToken: CancellationToken(),
autoBackup: Store.get(StoreKey.autoBackup, false), autoBackup: Store.get(StoreKey.autoBackup, false),
backgroundBackup: false, backgroundBackup: Store.get(StoreKey.backgroundBackup, false),
backupRequireWifi: Store.get(StoreKey.backupRequireWifi, true), backupRequireWifi: Store.get(StoreKey.backupRequireWifi, true),
backupRequireCharging: backupRequireCharging:
Store.get(StoreKey.backupRequireCharging, false), Store.get(StoreKey.backupRequireCharging, false),
@@ -171,6 +171,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
state.backupRequireCharging, state.backupRequireCharging,
); );
await Store.put(StoreKey.backupTriggerDelay, state.backupTriggerDelay); await Store.put(StoreKey.backupTriggerDelay, state.backupTriggerDelay);
await Store.put(StoreKey.backgroundBackup, state.backgroundBackup);
} else { } else {
state = state.copyWith( state = state.copyWith(
backgroundBackup: wasEnabled, backgroundBackup: wasEnabled,
@@ -383,6 +384,9 @@ class BackupNotifier extends StateNotifier<BackUpState> {
final isEnabled = await _backgroundService.isBackgroundBackupEnabled(); final isEnabled = await _backgroundService.isBackgroundBackupEnabled();
state = state.copyWith(backgroundBackup: isEnabled); state = state.copyWith(backgroundBackup: isEnabled);
if (isEnabled != Store.get(StoreKey.backgroundBackup, !isEnabled)) {
Store.put(StoreKey.backgroundBackup, isEnabled);
}
if (state.backupProgress != BackUpProgressEnum.inBackground) { if (state.backupProgress != BackUpProgressEnum.inBackground) {
await _getBackupAlbumsInfo(); await _getBackupAlbumsInfo();

View File

@@ -34,6 +34,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
final bool showDragScroll; final bool showDragScroll;
final bool showStack; final bool showStack;
final bool isOwner; final bool isOwner;
final String? sharedAlbumId;
const ImmichAssetGrid({ const ImmichAssetGrid({
super.key, super.key,
@@ -55,6 +56,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
this.showDragScroll = true, this.showDragScroll = true,
this.showStack = false, this.showStack = false,
this.isOwner = true, this.isOwner = true,
this.sharedAlbumId,
}); });
@override @override
@@ -120,6 +122,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
showDragScroll: showDragScroll, showDragScroll: showDragScroll,
showStack: showStack, showStack: showStack,
isOwner: isOwner, isOwner: isOwner,
sharedAlbumId: sharedAlbumId,
), ),
); );
} }

View File

@@ -39,6 +39,7 @@ class ImmichAssetGridView extends StatefulWidget {
final bool showDragScroll; final bool showDragScroll;
final bool showStack; final bool showStack;
final bool isOwner; final bool isOwner;
final String? sharedAlbumId;
const ImmichAssetGridView({ const ImmichAssetGridView({
super.key, super.key,
@@ -60,6 +61,7 @@ class ImmichAssetGridView extends StatefulWidget {
this.showDragScroll = true, this.showDragScroll = true,
this.showStack = false, this.showStack = false,
this.isOwner = true, this.isOwner = true,
this.sharedAlbumId,
}); });
@override @override
@@ -141,6 +143,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
heroOffset: widget.heroOffset, heroOffset: widget.heroOffset,
showStack: widget.showStack, showStack: widget.showStack,
isOwner: widget.isOwner, isOwner: widget.isOwner,
sharedAlbumId: widget.sharedAlbumId,
); );
} }

View File

@@ -21,6 +21,7 @@ class ThumbnailImage extends StatelessWidget {
final Function? onSelect; final Function? onSelect;
final Function? onDeselect; final Function? onDeselect;
final int heroOffset; final int heroOffset;
final String? sharedAlbumId;
const ThumbnailImage({ const ThumbnailImage({
Key? key, Key? key,
@@ -31,6 +32,7 @@ class ThumbnailImage extends StatelessWidget {
this.showStorageIndicator = true, this.showStorageIndicator = true,
this.showStack = false, this.showStack = false,
this.isOwner = true, this.isOwner = true,
this.sharedAlbumId,
this.useGrayBoxPlaceholder = false, this.useGrayBoxPlaceholder = false,
this.isSelected = false, this.isSelected = false,
this.multiselectEnabled = false, this.multiselectEnabled = false,
@@ -184,6 +186,7 @@ class ThumbnailImage extends StatelessWidget {
heroOffset: heroOffset, heroOffset: heroOffset,
showStack: showStack, showStack: showStack,
isOwner: isOwner, isOwner: isOwner,
sharedAlbumId: sharedAlbumId,
), ),
); );
} }

View File

@@ -100,7 +100,7 @@ class ControlBottomAppBar extends ConsumerWidget {
label: "control_bottom_app_bar_stack".tr(), label: "control_bottom_app_bar_stack".tr(),
onPressed: enabled ? onStack : null, onPressed: enabled ? onStack : null,
), ),
if (!hasRemote) if (hasLocal)
ControlBoxButton( ControlBoxButton(
iconData: Icons.backup_outlined, iconData: Icons.backup_outlined,
label: "Upload", label: "Upload",

View File

@@ -169,9 +169,10 @@ class HomePage extends HookConsumerWidget {
processing.value = true; processing.value = true;
selectionEnabledHook.value = false; selectionEnabledHook.value = false;
try { try {
ref ref.read(manualUploadProvider.notifier).uploadAssets(
.read(manualUploadProvider.notifier) context,
.uploadAssets(context, selection.value); selection.value.where((a) => a.storage == AssetState.local),
);
} finally { } finally {
processing.value = false; processing.value = false;
} }

View File

@@ -17,7 +17,7 @@ class OAuthService {
// Resolve API server endpoint from user provided serverUrl // Resolve API server endpoint from user provided serverUrl
await _apiService.resolveAndSetEndpoint(serverUrl); await _apiService.resolveAndSetEndpoint(serverUrl);
return await _apiService.oAuthApi.generateConfig( return await _apiService.oAuthApi.generateOAuthConfig(
OAuthConfigDto(redirectUri: '$callbackUrlScheme:/'), OAuthConfigDto(redirectUri: '$callbackUrlScheme:/'),
); );
} }
@@ -29,7 +29,7 @@ class OAuthService {
callbackUrlScheme: callbackUrlScheme, callbackUrlScheme: callbackUrlScheme,
); );
return await _apiService.oAuthApi.callback( return await _apiService.oAuthApi.finishOAuth(
OAuthCallbackDto( OAuthCallbackDto(
url: result, url: result,
), ),

View File

@@ -65,7 +65,7 @@ class LoginForm extends HookConsumerWidget {
isLoadingServer.value = true; isLoadingServer.value = true;
final endpoint = await apiService.resolveAndSetEndpoint(serverUrl); final endpoint = await apiService.resolveAndSetEndpoint(serverUrl);
final loginConfig = await apiService.oAuthApi.generateConfig( final loginConfig = await apiService.oAuthApi.generateOAuthConfig(
OAuthConfigDto(redirectUri: serverUrl), OAuthConfigDto(redirectUri: serverUrl),
); );

View File

@@ -172,7 +172,7 @@ class SearchPage extends HookConsumerWidget {
), ),
ListTile( ListTile(
leading: Icon( leading: Icon(
Icons.star_outline, Icons.favorite_border_rounded,
color: categoryIconColor, color: categoryIconColor,
), ),
title: title:

View File

@@ -37,6 +37,7 @@ class TrashNotifier extends StateNotifier<bool> {
.remoteIdProperty() .remoteIdProperty()
.findAll(); .findAll();
// TODO: handle local asset removal on emptyTrash
_ref _ref
.read(syncServiceProvider) .read(syncServiceProvider)
.handleRemoteAssetRemoval(idsToRemove.cast<String>().toList()); .handleRemoteAssetRemoval(idsToRemove.cast<String>().toList());

View File

@@ -1,6 +1,7 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/activities/views/activities_page.dart';
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart'; import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
import 'package:immich_mobile/modules/album/views/album_options_part.dart'; import 'package:immich_mobile/modules/album/views/album_options_part.dart';
import 'package:immich_mobile/modules/album/views/album_viewer_page.dart'; import 'package:immich_mobile/modules/album/views/album_viewer_page.dart';
@@ -160,6 +161,12 @@ part 'router.gr.dart';
AutoRoute(page: TrashPage, guards: [AuthGuard, DuplicateGuard]), AutoRoute(page: TrashPage, guards: [AuthGuard, DuplicateGuard]),
AutoRoute(page: SharedLinkPage, guards: [AuthGuard, DuplicateGuard]), AutoRoute(page: SharedLinkPage, guards: [AuthGuard, DuplicateGuard]),
AutoRoute(page: SharedLinkEditPage, guards: [AuthGuard, DuplicateGuard]), AutoRoute(page: SharedLinkEditPage, guards: [AuthGuard, DuplicateGuard]),
CustomRoute(
page: ActivitiesPage,
guards: [AuthGuard, DuplicateGuard],
transitionsBuilder: TransitionsBuilders.slideLeft,
durationInMilliseconds: 200,
),
], ],
) )
class AppRouter extends _$AppRouter { class AppRouter extends _$AppRouter {

View File

@@ -73,6 +73,7 @@ class _$AppRouter extends RootStackRouter {
heroOffset: args.heroOffset, heroOffset: args.heroOffset,
showStack: args.showStack, showStack: args.showStack,
isOwner: args.isOwner, isOwner: args.isOwner,
sharedAlbumId: args.sharedAlbumId,
), ),
); );
}, },
@@ -337,6 +338,25 @@ class _$AppRouter extends RootStackRouter {
), ),
); );
}, },
ActivitiesRoute.name: (routeData) {
final args = routeData.argsAs<ActivitiesRouteArgs>();
return CustomPage<dynamic>(
routeData: routeData,
child: ActivitiesPage(
args.albumId,
appBarTitle: args.appBarTitle,
assetId: args.assetId,
withAssetThumbs: args.withAssetThumbs,
isOwner: args.isOwner,
isReadOnly: args.isReadOnly,
key: args.key,
),
transitionsBuilder: TransitionsBuilders.slideLeft,
durationInMilliseconds: 200,
opaque: true,
barrierDismissible: false,
);
},
HomeRoute.name: (routeData) { HomeRoute.name: (routeData) {
return MaterialPageX<dynamic>( return MaterialPageX<dynamic>(
routeData: routeData, routeData: routeData,
@@ -674,6 +694,14 @@ class _$AppRouter extends RootStackRouter {
duplicateGuard, duplicateGuard,
], ],
), ),
RouteConfig(
ActivitiesRoute.name,
path: '/activities-page',
guards: [
authGuard,
duplicateGuard,
],
),
]; ];
} }
@@ -749,6 +777,7 @@ class GalleryViewerRoute extends PageRouteInfo<GalleryViewerRouteArgs> {
int heroOffset = 0, int heroOffset = 0,
bool showStack = false, bool showStack = false,
bool isOwner = true, bool isOwner = true,
String? sharedAlbumId,
}) : super( }) : super(
GalleryViewerRoute.name, GalleryViewerRoute.name,
path: '/gallery-viewer-page', path: '/gallery-viewer-page',
@@ -760,6 +789,7 @@ class GalleryViewerRoute extends PageRouteInfo<GalleryViewerRouteArgs> {
heroOffset: heroOffset, heroOffset: heroOffset,
showStack: showStack, showStack: showStack,
isOwner: isOwner, isOwner: isOwner,
sharedAlbumId: sharedAlbumId,
), ),
); );
@@ -775,6 +805,7 @@ class GalleryViewerRouteArgs {
this.heroOffset = 0, this.heroOffset = 0,
this.showStack = false, this.showStack = false,
this.isOwner = true, this.isOwner = true,
this.sharedAlbumId,
}); });
final Key? key; final Key? key;
@@ -791,9 +822,11 @@ class GalleryViewerRouteArgs {
final bool isOwner; final bool isOwner;
final String? sharedAlbumId;
@override @override
String toString() { String toString() {
return 'GalleryViewerRouteArgs{key: $key, initialIndex: $initialIndex, loadAsset: $loadAsset, totalAssets: $totalAssets, heroOffset: $heroOffset, showStack: $showStack, isOwner: $isOwner}'; return 'GalleryViewerRouteArgs{key: $key, initialIndex: $initialIndex, loadAsset: $loadAsset, totalAssets: $totalAssets, heroOffset: $heroOffset, showStack: $showStack, isOwner: $isOwner, sharedAlbumId: $sharedAlbumId}';
} }
} }
@@ -1527,6 +1560,65 @@ class SharedLinkEditRouteArgs {
} }
} }
/// generated route for
/// [ActivitiesPage]
class ActivitiesRoute extends PageRouteInfo<ActivitiesRouteArgs> {
ActivitiesRoute({
required String albumId,
String appBarTitle = "",
String? assetId,
bool withAssetThumbs = true,
bool isOwner = false,
bool isReadOnly = false,
Key? key,
}) : super(
ActivitiesRoute.name,
path: '/activities-page',
args: ActivitiesRouteArgs(
albumId: albumId,
appBarTitle: appBarTitle,
assetId: assetId,
withAssetThumbs: withAssetThumbs,
isOwner: isOwner,
isReadOnly: isReadOnly,
key: key,
),
);
static const String name = 'ActivitiesRoute';
}
class ActivitiesRouteArgs {
const ActivitiesRouteArgs({
required this.albumId,
this.appBarTitle = "",
this.assetId,
this.withAssetThumbs = true,
this.isOwner = false,
this.isReadOnly = false,
this.key,
});
final String albumId;
final String appBarTitle;
final String? assetId;
final bool withAssetThumbs;
final bool isOwner;
final bool isReadOnly;
final Key? key;
@override
String toString() {
return 'ActivitiesRouteArgs{albumId: $albumId, appBarTitle: $appBarTitle, assetId: $assetId, withAssetThumbs: $withAssetThumbs, isOwner: $isOwner, isReadOnly: $isReadOnly, key: $key}';
}
}
/// generated route for /// generated route for
/// [HomePage] /// [HomePage]
class HomeRoute extends PageRouteInfo<void> { class HomeRoute extends PageRouteInfo<void> {

View File

@@ -22,6 +22,7 @@ class Album {
this.endDate, this.endDate,
this.lastModifiedAssetTimestamp, this.lastModifiedAssetTimestamp,
required this.shared, required this.shared,
required this.activityEnabled,
}); });
Id id = Isar.autoIncrement; Id id = Isar.autoIncrement;
@@ -36,6 +37,7 @@ class Album {
DateTime? endDate; DateTime? endDate;
DateTime? lastModifiedAssetTimestamp; DateTime? lastModifiedAssetTimestamp;
bool shared; bool shared;
bool activityEnabled;
final IsarLink<User> owner = IsarLink<User>(); final IsarLink<User> owner = IsarLink<User>();
final IsarLink<Asset> thumbnail = IsarLink<Asset>(); final IsarLink<Asset> thumbnail = IsarLink<Asset>();
final IsarLinks<User> sharedUsers = IsarLinks<User>(); final IsarLinks<User> sharedUsers = IsarLinks<User>();
@@ -77,7 +79,8 @@ class Album {
} }
Stream<void> watchRenderList(GroupAssetsBy groupAssetsBy) async* { Stream<void> watchRenderList(GroupAssetsBy groupAssetsBy) async* {
final query = assets.filter().sortByFileCreatedAtDesc(); final query =
assets.filter().isTrashedEqualTo(false).sortByFileCreatedAtDesc();
_renderList = await RenderList.fromQuery(query, groupAssetsBy); _renderList = await RenderList.fromQuery(query, groupAssetsBy);
yield _renderList; yield _renderList;
await for (final _ in query.watchLazy()) { await for (final _ in query.watchLazy()) {
@@ -105,6 +108,7 @@ class Album {
modifiedAt.isAtSameMomentAs(other.modifiedAt) && modifiedAt.isAtSameMomentAs(other.modifiedAt) &&
lastModifiedAssetTimestampIsSetAndEqual && lastModifiedAssetTimestampIsSetAndEqual &&
shared == other.shared && shared == other.shared &&
activityEnabled == other.activityEnabled &&
owner.value == other.owner.value && owner.value == other.owner.value &&
thumbnail.value == other.thumbnail.value && thumbnail.value == other.thumbnail.value &&
sharedUsers.length == other.sharedUsers.length && sharedUsers.length == other.sharedUsers.length &&
@@ -122,6 +126,7 @@ class Album {
modifiedAt.hashCode ^ modifiedAt.hashCode ^
lastModifiedAssetTimestamp.hashCode ^ lastModifiedAssetTimestamp.hashCode ^
shared.hashCode ^ shared.hashCode ^
activityEnabled.hashCode ^
owner.value.hashCode ^ owner.value.hashCode ^
thumbnail.value.hashCode ^ thumbnail.value.hashCode ^
sharedUsers.length.hashCode ^ sharedUsers.length.hashCode ^
@@ -133,6 +138,7 @@ class Album {
createdAt: ape.lastModified?.toUtc() ?? DateTime.now().toUtc(), createdAt: ape.lastModified?.toUtc() ?? DateTime.now().toUtc(),
modifiedAt: ape.lastModified?.toUtc() ?? DateTime.now().toUtc(), modifiedAt: ape.lastModified?.toUtc() ?? DateTime.now().toUtc(),
shared: false, shared: false,
activityEnabled: false,
); );
a.owner.value = Store.get(StoreKey.currentUser); a.owner.value = Store.get(StoreKey.currentUser);
a.localId = ape.id; a.localId = ape.id;
@@ -150,6 +156,7 @@ class Album {
shared: dto.shared, shared: dto.shared,
startDate: dto.startDate, startDate: dto.startDate,
endDate: dto.endDate, endDate: dto.endDate,
activityEnabled: dto.isActivityEnabled,
); );
a.owner.value = await db.users.getById(dto.ownerId); a.owner.value = await db.users.getById(dto.ownerId);
if (dto.albumThumbnailAssetId != null) { if (dto.albumThumbnailAssetId != null) {

View File

@@ -17,48 +17,53 @@ const AlbumSchema = CollectionSchema(
name: r'Album', name: r'Album',
id: -1355968412107120937, id: -1355968412107120937,
properties: { properties: {
r'createdAt': PropertySchema( r'activityEnabled': PropertySchema(
id: 0, id: 0,
name: r'activityEnabled',
type: IsarType.bool,
),
r'createdAt': PropertySchema(
id: 1,
name: r'createdAt', name: r'createdAt',
type: IsarType.dateTime, type: IsarType.dateTime,
), ),
r'endDate': PropertySchema( r'endDate': PropertySchema(
id: 1, id: 2,
name: r'endDate', name: r'endDate',
type: IsarType.dateTime, type: IsarType.dateTime,
), ),
r'lastModifiedAssetTimestamp': PropertySchema( r'lastModifiedAssetTimestamp': PropertySchema(
id: 2, id: 3,
name: r'lastModifiedAssetTimestamp', name: r'lastModifiedAssetTimestamp',
type: IsarType.dateTime, type: IsarType.dateTime,
), ),
r'localId': PropertySchema( r'localId': PropertySchema(
id: 3, id: 4,
name: r'localId', name: r'localId',
type: IsarType.string, type: IsarType.string,
), ),
r'modifiedAt': PropertySchema( r'modifiedAt': PropertySchema(
id: 4, id: 5,
name: r'modifiedAt', name: r'modifiedAt',
type: IsarType.dateTime, type: IsarType.dateTime,
), ),
r'name': PropertySchema( r'name': PropertySchema(
id: 5, id: 6,
name: r'name', name: r'name',
type: IsarType.string, type: IsarType.string,
), ),
r'remoteId': PropertySchema( r'remoteId': PropertySchema(
id: 6, id: 7,
name: r'remoteId', name: r'remoteId',
type: IsarType.string, type: IsarType.string,
), ),
r'shared': PropertySchema( r'shared': PropertySchema(
id: 7, id: 8,
name: r'shared', name: r'shared',
type: IsarType.bool, type: IsarType.bool,
), ),
r'startDate': PropertySchema( r'startDate': PropertySchema(
id: 8, id: 9,
name: r'startDate', name: r'startDate',
type: IsarType.dateTime, type: IsarType.dateTime,
) )
@@ -157,15 +162,16 @@ void _albumSerialize(
List<int> offsets, List<int> offsets,
Map<Type, List<int>> allOffsets, Map<Type, List<int>> allOffsets,
) { ) {
writer.writeDateTime(offsets[0], object.createdAt); writer.writeBool(offsets[0], object.activityEnabled);
writer.writeDateTime(offsets[1], object.endDate); writer.writeDateTime(offsets[1], object.createdAt);
writer.writeDateTime(offsets[2], object.lastModifiedAssetTimestamp); writer.writeDateTime(offsets[2], object.endDate);
writer.writeString(offsets[3], object.localId); writer.writeDateTime(offsets[3], object.lastModifiedAssetTimestamp);
writer.writeDateTime(offsets[4], object.modifiedAt); writer.writeString(offsets[4], object.localId);
writer.writeString(offsets[5], object.name); writer.writeDateTime(offsets[5], object.modifiedAt);
writer.writeString(offsets[6], object.remoteId); writer.writeString(offsets[6], object.name);
writer.writeBool(offsets[7], object.shared); writer.writeString(offsets[7], object.remoteId);
writer.writeDateTime(offsets[8], object.startDate); writer.writeBool(offsets[8], object.shared);
writer.writeDateTime(offsets[9], object.startDate);
} }
Album _albumDeserialize( Album _albumDeserialize(
@@ -175,15 +181,16 @@ Album _albumDeserialize(
Map<Type, List<int>> allOffsets, Map<Type, List<int>> allOffsets,
) { ) {
final object = Album( final object = Album(
createdAt: reader.readDateTime(offsets[0]), activityEnabled: reader.readBool(offsets[0]),
endDate: reader.readDateTimeOrNull(offsets[1]), createdAt: reader.readDateTime(offsets[1]),
lastModifiedAssetTimestamp: reader.readDateTimeOrNull(offsets[2]), endDate: reader.readDateTimeOrNull(offsets[2]),
localId: reader.readStringOrNull(offsets[3]), lastModifiedAssetTimestamp: reader.readDateTimeOrNull(offsets[3]),
modifiedAt: reader.readDateTime(offsets[4]), localId: reader.readStringOrNull(offsets[4]),
name: reader.readString(offsets[5]), modifiedAt: reader.readDateTime(offsets[5]),
remoteId: reader.readStringOrNull(offsets[6]), name: reader.readString(offsets[6]),
shared: reader.readBool(offsets[7]), remoteId: reader.readStringOrNull(offsets[7]),
startDate: reader.readDateTimeOrNull(offsets[8]), shared: reader.readBool(offsets[8]),
startDate: reader.readDateTimeOrNull(offsets[9]),
); );
object.id = id; object.id = id;
return object; return object;
@@ -197,22 +204,24 @@ P _albumDeserializeProp<P>(
) { ) {
switch (propertyId) { switch (propertyId) {
case 0: case 0:
return (reader.readDateTime(offset)) as P; return (reader.readBool(offset)) as P;
case 1: case 1:
return (reader.readDateTimeOrNull(offset)) as P; return (reader.readDateTime(offset)) as P;
case 2: case 2:
return (reader.readDateTimeOrNull(offset)) as P; return (reader.readDateTimeOrNull(offset)) as P;
case 3: case 3:
return (reader.readStringOrNull(offset)) as P; return (reader.readDateTimeOrNull(offset)) as P;
case 4: case 4:
return (reader.readDateTime(offset)) as P;
case 5:
return (reader.readString(offset)) as P;
case 6:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 5:
return (reader.readDateTime(offset)) as P;
case 6:
return (reader.readString(offset)) as P;
case 7: case 7:
return (reader.readBool(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 8: case 8:
return (reader.readBool(offset)) as P;
case 9:
return (reader.readDateTimeOrNull(offset)) as P; return (reader.readDateTimeOrNull(offset)) as P;
default: default:
throw IsarError('Unknown property with id $propertyId'); throw IsarError('Unknown property with id $propertyId');
@@ -442,6 +451,16 @@ extension AlbumQueryWhere on QueryBuilder<Album, Album, QWhereClause> {
} }
extension AlbumQueryFilter on QueryBuilder<Album, Album, QFilterCondition> { extension AlbumQueryFilter on QueryBuilder<Album, Album, QFilterCondition> {
QueryBuilder<Album, Album, QAfterFilterCondition> activityEnabledEqualTo(
bool value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'activityEnabled',
value: value,
));
});
}
QueryBuilder<Album, Album, QAfterFilterCondition> createdAtEqualTo( QueryBuilder<Album, Album, QAfterFilterCondition> createdAtEqualTo(
DateTime value) { DateTime value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@@ -1385,6 +1404,18 @@ extension AlbumQueryLinks on QueryBuilder<Album, Album, QFilterCondition> {
} }
extension AlbumQuerySortBy on QueryBuilder<Album, Album, QSortBy> { extension AlbumQuerySortBy on QueryBuilder<Album, Album, QSortBy> {
QueryBuilder<Album, Album, QAfterSortBy> sortByActivityEnabled() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'activityEnabled', Sort.asc);
});
}
QueryBuilder<Album, Album, QAfterSortBy> sortByActivityEnabledDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'activityEnabled', Sort.desc);
});
}
QueryBuilder<Album, Album, QAfterSortBy> sortByCreatedAt() { QueryBuilder<Album, Album, QAfterSortBy> sortByCreatedAt() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'createdAt', Sort.asc); return query.addSortBy(r'createdAt', Sort.asc);
@@ -1496,6 +1527,18 @@ extension AlbumQuerySortBy on QueryBuilder<Album, Album, QSortBy> {
} }
extension AlbumQuerySortThenBy on QueryBuilder<Album, Album, QSortThenBy> { extension AlbumQuerySortThenBy on QueryBuilder<Album, Album, QSortThenBy> {
QueryBuilder<Album, Album, QAfterSortBy> thenByActivityEnabled() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'activityEnabled', Sort.asc);
});
}
QueryBuilder<Album, Album, QAfterSortBy> thenByActivityEnabledDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'activityEnabled', Sort.desc);
});
}
QueryBuilder<Album, Album, QAfterSortBy> thenByCreatedAt() { QueryBuilder<Album, Album, QAfterSortBy> thenByCreatedAt() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'createdAt', Sort.asc); return query.addSortBy(r'createdAt', Sort.asc);
@@ -1619,6 +1662,12 @@ extension AlbumQuerySortThenBy on QueryBuilder<Album, Album, QSortThenBy> {
} }
extension AlbumQueryWhereDistinct on QueryBuilder<Album, Album, QDistinct> { extension AlbumQueryWhereDistinct on QueryBuilder<Album, Album, QDistinct> {
QueryBuilder<Album, Album, QDistinct> distinctByActivityEnabled() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'activityEnabled');
});
}
QueryBuilder<Album, Album, QDistinct> distinctByCreatedAt() { QueryBuilder<Album, Album, QDistinct> distinctByCreatedAt() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'createdAt'); return query.addDistinctBy(r'createdAt');
@@ -1684,6 +1733,12 @@ extension AlbumQueryProperty on QueryBuilder<Album, Album, QQueryProperty> {
}); });
} }
QueryBuilder<Album, bool, QQueryOperations> activityEnabledProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'activityEnabled');
});
}
QueryBuilder<Album, DateTime, QQueryOperations> createdAtProperty() { QueryBuilder<Album, DateTime, QQueryOperations> createdAtProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'createdAt'); return query.addPropertyName(r'createdAt');

View File

@@ -8,6 +8,8 @@ part 'exif_info.g.dart';
class ExifInfo { class ExifInfo {
Id? id; Id? id;
int? fileSize; int? fileSize;
DateTime? dateTimeOriginal;
String? timeZone;
String? make; String? make;
String? model; String? model;
String? lens; String? lens;
@@ -47,6 +49,8 @@ class ExifInfo {
ExifInfo.fromDto(ExifResponseDto dto) ExifInfo.fromDto(ExifResponseDto dto)
: fileSize = dto.fileSizeInByte, : fileSize = dto.fileSizeInByte,
dateTimeOriginal = dto.dateTimeOriginal,
timeZone = dto.timeZone,
make = dto.make, make = dto.make,
model = dto.model, model = dto.model,
lens = dto.lensModel, lens = dto.lensModel,
@@ -64,6 +68,8 @@ class ExifInfo {
ExifInfo({ ExifInfo({
this.id, this.id,
this.fileSize, this.fileSize,
this.dateTimeOriginal,
this.timeZone,
this.make, this.make,
this.model, this.model,
this.lens, this.lens,
@@ -82,6 +88,8 @@ class ExifInfo {
ExifInfo copyWith({ ExifInfo copyWith({
Id? id, Id? id,
int? fileSize, int? fileSize,
DateTime? dateTimeOriginal,
String? timeZone,
String? make, String? make,
String? model, String? model,
String? lens, String? lens,
@@ -99,6 +107,8 @@ class ExifInfo {
ExifInfo( ExifInfo(
id: id ?? this.id, id: id ?? this.id,
fileSize: fileSize ?? this.fileSize, fileSize: fileSize ?? this.fileSize,
dateTimeOriginal: dateTimeOriginal ?? this.dateTimeOriginal,
timeZone: timeZone ?? this.timeZone,
make: make ?? this.make, make: make ?? this.make,
model: model ?? this.model, model: model ?? this.model,
lens: lens ?? this.lens, lens: lens ?? this.lens,
@@ -119,6 +129,8 @@ class ExifInfo {
if (other is! ExifInfo) return false; if (other is! ExifInfo) return false;
return id == other.id && return id == other.id &&
fileSize == other.fileSize && fileSize == other.fileSize &&
dateTimeOriginal == other.dateTimeOriginal &&
timeZone == other.timeZone &&
make == other.make && make == other.make &&
model == other.model && model == other.model &&
lens == other.lens && lens == other.lens &&
@@ -139,6 +151,8 @@ class ExifInfo {
int get hashCode => int get hashCode =>
id.hashCode ^ id.hashCode ^
fileSize.hashCode ^ fileSize.hashCode ^
dateTimeOriginal.hashCode ^
timeZone.hashCode ^
make.hashCode ^ make.hashCode ^
model.hashCode ^ model.hashCode ^
lens.hashCode ^ lens.hashCode ^

View File

@@ -27,65 +27,75 @@ const ExifInfoSchema = CollectionSchema(
name: r'country', name: r'country',
type: IsarType.string, type: IsarType.string,
), ),
r'description': PropertySchema( r'dateTimeOriginal': PropertySchema(
id: 2, id: 2,
name: r'dateTimeOriginal',
type: IsarType.dateTime,
),
r'description': PropertySchema(
id: 3,
name: r'description', name: r'description',
type: IsarType.string, type: IsarType.string,
), ),
r'exposureSeconds': PropertySchema( r'exposureSeconds': PropertySchema(
id: 3, id: 4,
name: r'exposureSeconds', name: r'exposureSeconds',
type: IsarType.float, type: IsarType.float,
), ),
r'f': PropertySchema( r'f': PropertySchema(
id: 4, id: 5,
name: r'f', name: r'f',
type: IsarType.float, type: IsarType.float,
), ),
r'fileSize': PropertySchema( r'fileSize': PropertySchema(
id: 5, id: 6,
name: r'fileSize', name: r'fileSize',
type: IsarType.long, type: IsarType.long,
), ),
r'iso': PropertySchema( r'iso': PropertySchema(
id: 6, id: 7,
name: r'iso', name: r'iso',
type: IsarType.int, type: IsarType.int,
), ),
r'lat': PropertySchema( r'lat': PropertySchema(
id: 7, id: 8,
name: r'lat', name: r'lat',
type: IsarType.float, type: IsarType.float,
), ),
r'lens': PropertySchema( r'lens': PropertySchema(
id: 8, id: 9,
name: r'lens', name: r'lens',
type: IsarType.string, type: IsarType.string,
), ),
r'long': PropertySchema( r'long': PropertySchema(
id: 9, id: 10,
name: r'long', name: r'long',
type: IsarType.float, type: IsarType.float,
), ),
r'make': PropertySchema( r'make': PropertySchema(
id: 10, id: 11,
name: r'make', name: r'make',
type: IsarType.string, type: IsarType.string,
), ),
r'mm': PropertySchema( r'mm': PropertySchema(
id: 11, id: 12,
name: r'mm', name: r'mm',
type: IsarType.float, type: IsarType.float,
), ),
r'model': PropertySchema( r'model': PropertySchema(
id: 12, id: 13,
name: r'model', name: r'model',
type: IsarType.string, type: IsarType.string,
), ),
r'state': PropertySchema( r'state': PropertySchema(
id: 13, id: 14,
name: r'state', name: r'state',
type: IsarType.string, type: IsarType.string,
),
r'timeZone': PropertySchema(
id: 15,
name: r'timeZone',
type: IsarType.string,
) )
}, },
estimateSize: _exifInfoEstimateSize, estimateSize: _exifInfoEstimateSize,
@@ -150,6 +160,12 @@ int _exifInfoEstimateSize(
bytesCount += 3 + value.length * 3; bytesCount += 3 + value.length * 3;
} }
} }
{
final value = object.timeZone;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
return bytesCount; return bytesCount;
} }
@@ -161,18 +177,20 @@ void _exifInfoSerialize(
) { ) {
writer.writeString(offsets[0], object.city); writer.writeString(offsets[0], object.city);
writer.writeString(offsets[1], object.country); writer.writeString(offsets[1], object.country);
writer.writeString(offsets[2], object.description); writer.writeDateTime(offsets[2], object.dateTimeOriginal);
writer.writeFloat(offsets[3], object.exposureSeconds); writer.writeString(offsets[3], object.description);
writer.writeFloat(offsets[4], object.f); writer.writeFloat(offsets[4], object.exposureSeconds);
writer.writeLong(offsets[5], object.fileSize); writer.writeFloat(offsets[5], object.f);
writer.writeInt(offsets[6], object.iso); writer.writeLong(offsets[6], object.fileSize);
writer.writeFloat(offsets[7], object.lat); writer.writeInt(offsets[7], object.iso);
writer.writeString(offsets[8], object.lens); writer.writeFloat(offsets[8], object.lat);
writer.writeFloat(offsets[9], object.long); writer.writeString(offsets[9], object.lens);
writer.writeString(offsets[10], object.make); writer.writeFloat(offsets[10], object.long);
writer.writeFloat(offsets[11], object.mm); writer.writeString(offsets[11], object.make);
writer.writeString(offsets[12], object.model); writer.writeFloat(offsets[12], object.mm);
writer.writeString(offsets[13], object.state); writer.writeString(offsets[13], object.model);
writer.writeString(offsets[14], object.state);
writer.writeString(offsets[15], object.timeZone);
} }
ExifInfo _exifInfoDeserialize( ExifInfo _exifInfoDeserialize(
@@ -184,19 +202,21 @@ ExifInfo _exifInfoDeserialize(
final object = ExifInfo( final object = ExifInfo(
city: reader.readStringOrNull(offsets[0]), city: reader.readStringOrNull(offsets[0]),
country: reader.readStringOrNull(offsets[1]), country: reader.readStringOrNull(offsets[1]),
description: reader.readStringOrNull(offsets[2]), dateTimeOriginal: reader.readDateTimeOrNull(offsets[2]),
exposureSeconds: reader.readFloatOrNull(offsets[3]), description: reader.readStringOrNull(offsets[3]),
f: reader.readFloatOrNull(offsets[4]), exposureSeconds: reader.readFloatOrNull(offsets[4]),
fileSize: reader.readLongOrNull(offsets[5]), f: reader.readFloatOrNull(offsets[5]),
fileSize: reader.readLongOrNull(offsets[6]),
id: id, id: id,
iso: reader.readIntOrNull(offsets[6]), iso: reader.readIntOrNull(offsets[7]),
lat: reader.readFloatOrNull(offsets[7]), lat: reader.readFloatOrNull(offsets[8]),
lens: reader.readStringOrNull(offsets[8]), lens: reader.readStringOrNull(offsets[9]),
long: reader.readFloatOrNull(offsets[9]), long: reader.readFloatOrNull(offsets[10]),
make: reader.readStringOrNull(offsets[10]), make: reader.readStringOrNull(offsets[11]),
mm: reader.readFloatOrNull(offsets[11]), mm: reader.readFloatOrNull(offsets[12]),
model: reader.readStringOrNull(offsets[12]), model: reader.readStringOrNull(offsets[13]),
state: reader.readStringOrNull(offsets[13]), state: reader.readStringOrNull(offsets[14]),
timeZone: reader.readStringOrNull(offsets[15]),
); );
return object; return object;
} }
@@ -213,29 +233,33 @@ P _exifInfoDeserializeProp<P>(
case 1: case 1:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 2: case 2:
return (reader.readStringOrNull(offset)) as P; return (reader.readDateTimeOrNull(offset)) as P;
case 3: case 3:
return (reader.readFloatOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 4: case 4:
return (reader.readFloatOrNull(offset)) as P; return (reader.readFloatOrNull(offset)) as P;
case 5: case 5:
return (reader.readLongOrNull(offset)) as P; return (reader.readFloatOrNull(offset)) as P;
case 6: case 6:
return (reader.readIntOrNull(offset)) as P; return (reader.readLongOrNull(offset)) as P;
case 7: case 7:
return (reader.readFloatOrNull(offset)) as P; return (reader.readIntOrNull(offset)) as P;
case 8: case 8:
return (reader.readStringOrNull(offset)) as P; return (reader.readFloatOrNull(offset)) as P;
case 9: case 9:
return (reader.readFloatOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 10: case 10:
return (reader.readStringOrNull(offset)) as P;
case 11:
return (reader.readFloatOrNull(offset)) as P; return (reader.readFloatOrNull(offset)) as P;
case 12: case 11:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 12:
return (reader.readFloatOrNull(offset)) as P;
case 13: case 13:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 14:
return (reader.readStringOrNull(offset)) as P;
case 15:
return (reader.readStringOrNull(offset)) as P;
default: default:
throw IsarError('Unknown property with id $propertyId'); throw IsarError('Unknown property with id $propertyId');
} }
@@ -622,6 +646,80 @@ extension ExifInfoQueryFilter
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
dateTimeOriginalIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'dateTimeOriginal',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
dateTimeOriginalIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'dateTimeOriginal',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
dateTimeOriginalEqualTo(DateTime? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'dateTimeOriginal',
value: value,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
dateTimeOriginalGreaterThan(
DateTime? value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'dateTimeOriginal',
value: value,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
dateTimeOriginalLessThan(
DateTime? value, {
bool include = false,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'dateTimeOriginal',
value: value,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition>
dateTimeOriginalBetween(
DateTime? lower,
DateTime? upper, {
bool includeLower = true,
bool includeUpper = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'dateTimeOriginal',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> descriptionIsNull() { QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> descriptionIsNull() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull( return query.addFilterCondition(const FilterCondition.isNull(
@@ -1956,6 +2054,152 @@ extension ExifInfoQueryFilter
)); ));
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'timeZone',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'timeZone',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'timeZone',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'timeZone',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'timeZone',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneBetween(
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'timeZone',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'timeZone',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'timeZone',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'timeZone',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'timeZone',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'timeZone',
value: '',
));
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterFilterCondition> timeZoneIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'timeZone',
value: '',
));
});
}
} }
extension ExifInfoQueryObject extension ExifInfoQueryObject
@@ -1989,6 +2233,18 @@ extension ExifInfoQuerySortBy on QueryBuilder<ExifInfo, ExifInfo, QSortBy> {
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByDateTimeOriginal() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'dateTimeOriginal', Sort.asc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByDateTimeOriginalDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'dateTimeOriginal', Sort.desc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByDescription() { QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByDescription() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'description', Sort.asc); return query.addSortBy(r'description', Sort.asc);
@@ -2132,6 +2388,18 @@ extension ExifInfoQuerySortBy on QueryBuilder<ExifInfo, ExifInfo, QSortBy> {
return query.addSortBy(r'state', Sort.desc); return query.addSortBy(r'state', Sort.desc);
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByTimeZone() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'timeZone', Sort.asc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> sortByTimeZoneDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'timeZone', Sort.desc);
});
}
} }
extension ExifInfoQuerySortThenBy extension ExifInfoQuerySortThenBy
@@ -2160,6 +2428,18 @@ extension ExifInfoQuerySortThenBy
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByDateTimeOriginal() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'dateTimeOriginal', Sort.asc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByDateTimeOriginalDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'dateTimeOriginal', Sort.desc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByDescription() { QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByDescription() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'description', Sort.asc); return query.addSortBy(r'description', Sort.asc);
@@ -2315,6 +2595,18 @@ extension ExifInfoQuerySortThenBy
return query.addSortBy(r'state', Sort.desc); return query.addSortBy(r'state', Sort.desc);
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByTimeZone() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'timeZone', Sort.asc);
});
}
QueryBuilder<ExifInfo, ExifInfo, QAfterSortBy> thenByTimeZoneDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'timeZone', Sort.desc);
});
}
} }
extension ExifInfoQueryWhereDistinct extension ExifInfoQueryWhereDistinct
@@ -2333,6 +2625,12 @@ extension ExifInfoQueryWhereDistinct
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QDistinct> distinctByDateTimeOriginal() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'dateTimeOriginal');
});
}
QueryBuilder<ExifInfo, ExifInfo, QDistinct> distinctByDescription( QueryBuilder<ExifInfo, ExifInfo, QDistinct> distinctByDescription(
{bool caseSensitive = true}) { {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@@ -2409,6 +2707,13 @@ extension ExifInfoQueryWhereDistinct
return query.addDistinctBy(r'state', caseSensitive: caseSensitive); return query.addDistinctBy(r'state', caseSensitive: caseSensitive);
}); });
} }
QueryBuilder<ExifInfo, ExifInfo, QDistinct> distinctByTimeZone(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'timeZone', caseSensitive: caseSensitive);
});
}
} }
extension ExifInfoQueryProperty extension ExifInfoQueryProperty
@@ -2431,6 +2736,13 @@ extension ExifInfoQueryProperty
}); });
} }
QueryBuilder<ExifInfo, DateTime?, QQueryOperations>
dateTimeOriginalProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'dateTimeOriginal');
});
}
QueryBuilder<ExifInfo, String?, QQueryOperations> descriptionProperty() { QueryBuilder<ExifInfo, String?, QQueryOperations> descriptionProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'description'); return query.addPropertyName(r'description');
@@ -2502,4 +2814,10 @@ extension ExifInfoQueryProperty
return query.addPropertyName(r'state'); return query.addPropertyName(r'state');
}); });
} }
QueryBuilder<ExifInfo, String?, QQueryOperations> timeZoneProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'timeZone');
});
}
} }

View File

@@ -156,6 +156,7 @@ enum StoreKey<T> {
accessToken<String>(11, type: String), accessToken<String>(11, type: String),
serverEndpoint<String>(12, type: String), serverEndpoint<String>(12, type: String),
autoBackup<bool>(13, type: bool), autoBackup<bool>(13, type: bool),
backgroundBackup<bool>(14, type: bool),
// user settings from [AppSettingsEnum] below: // user settings from [AppSettingsEnum] below:
loadPreview<bool>(100, type: bool), loadPreview<bool>(100, type: bool),
loadOriginal<bool>(101, type: bool), loadOriginal<bool>(101, type: bool),

View File

@@ -66,7 +66,7 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
state = state.copyWith( state = state.copyWith(
isVersionMismatch: true, isVersionMismatch: true,
versionMismatchErrorMessage: versionMismatchErrorMessage:
"Server is out of date in major version. Some functionalities might not work correctly. Download and rebuild server", "Server is out of date. Please update to the latest major version.",
); );
return; return;
@@ -76,7 +76,7 @@ class ServerInfoNotifier extends StateNotifier<ServerInfo> {
state = state.copyWith( state = state.copyWith(
isVersionMismatch: true, isVersionMismatch: true,
versionMismatchErrorMessage: versionMismatchErrorMessage:
"Server is out of date in minor version. Some functionalities might not work correctly. Consider download and rebuild server", "Server is out of date. Consider updating to the latest minor version.",
); );
return; return;

View File

@@ -22,6 +22,7 @@ class ApiService {
late PersonApi personApi; late PersonApi personApi;
late AuditApi auditApi; late AuditApi auditApi;
late SharedLinkApi sharedLinkApi; late SharedLinkApi sharedLinkApi;
late ActivityApi activityApi;
ApiService() { ApiService() {
final endpoint = Store.tryGet(StoreKey.serverEndpoint); final endpoint = Store.tryGet(StoreKey.serverEndpoint);
@@ -47,6 +48,7 @@ class ApiService {
personApi = PersonApi(_apiClient); personApi = PersonApi(_apiClient);
auditApi = AuditApi(_apiClient); auditApi = AuditApi(_apiClient);
sharedLinkApi = SharedLinkApi(_apiClient); sharedLinkApi = SharedLinkApi(_apiClient);
activityApi = ActivityApi(_apiClient);
} }
Future<String> resolveAndSetEndpoint(String serverUrl) async { Future<String> resolveAndSetEndpoint(String serverUrl) async {

View File

@@ -62,20 +62,31 @@ class AssetService {
/// Returns `null` if the server state did not change, else list of assets /// Returns `null` if the server state did not change, else list of assets
Future<List<Asset>?> _getRemoteAssets(User user) async { Future<List<Asset>?> _getRemoteAssets(User user) async {
const int chunkSize = 5000;
try { try {
final List<AssetResponseDto>? assets = final DateTime now = DateTime.now().toUtc();
await _apiService.assetApi.getAllAssets( final List<Asset> allAssets = [];
userId: user.id, for (int i = 0;; i += chunkSize) {
); final List<AssetResponseDto>? assets =
if (assets == null) { await _apiService.assetApi.getAllAssets(
return null; userId: user.id,
} else if (assets.isNotEmpty && assets.first.ownerId != user.id) { // updatedBefore is important! without it we could
log.warning("Make sure that server and app versions match!" // a) get the same Asset multiple times in different versions (when
" The server returned assets for user ${assets.first.ownerId}" // the asset is modified while the chunks are loaded from the server)
" while requesting assets of user ${user.id}"); // b) miss assets when new assets are inserted in between the calls
return null; updatedBefore: now,
skip: i,
take: chunkSize,
);
if (assets == null) {
return null;
}
allAssets.addAll(assets.map(Asset.remote));
if (assets.length < chunkSize) {
break;
}
} }
return assets.map(Asset.remote).toList(); return allAssets;
} catch (error, stack) { } catch (error, stack) {
log.severe( log.severe(
'Error while getting remote assets: ${error.toString()}', 'Error while getting remote assets: ${error.toString()}',

View File

@@ -197,7 +197,7 @@ class SyncService {
User user, User user,
FutureOr<List<Asset>?> Function(User user) loadAssets, FutureOr<List<Asset>?> Function(User user) loadAssets,
) async { ) async {
final DateTime now = DateTime.now(); final DateTime now = DateTime.now().toUtc();
final List<Asset>? remote = await loadAssets(user); final List<Asset>? remote = await loadAssets(user);
if (remote == null) { if (remote == null) {
return false; return false;
@@ -210,6 +210,10 @@ class SyncService {
assert(inDb.isSorted(Asset.compareByChecksum), "inDb not sorted!"); assert(inDb.isSorted(Asset.compareByChecksum), "inDb not sorted!");
remote.sort(Asset.compareByChecksum); remote.sort(Asset.compareByChecksum);
// filter our duplicates that might be introduced by the chunked retrieval
remote.uniqueConsecutive(compare: Asset.compareByChecksum);
final (toAdd, toUpdate, toRemove) = _diffAssets(remote, inDb, remote: true); final (toAdd, toUpdate, toRemove) = _diffAssets(remote, inDb, remote: true);
if (toAdd.isEmpty && toUpdate.isEmpty && toRemove.isEmpty) { if (toAdd.isEmpty && toUpdate.isEmpty && toRemove.isEmpty) {
await _updateUserAssetsETag(user, now); await _updateUserAssetsETag(user, now);
@@ -759,6 +763,12 @@ class SyncService {
final List<Asset> toAdd = []; final List<Asset> toAdd = [];
final List<Asset> toUpdate = []; final List<Asset> toUpdate = [];
final List<Asset> toRemove = []; final List<Asset> toRemove = [];
if (assets.isEmpty || inDb.isEmpty) {
// fast path for trivial cases: halfes memory usage during initial sync
return assets.isEmpty
? (toAdd, toUpdate, inDb) // remove all from DB
: (assets, toUpdate, toRemove); // add all assets
}
diffSortedListsSync( diffSortedListsSync(
inDb, inDb,
assets, assets,

View File

@@ -194,6 +194,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
Navigator.of(context).pop(); Navigator.of(context).pop();
launchUrl( launchUrl(
Uri.parse('https://immich.app'), Uri.parse('https://immich.app'),
mode: LaunchMode.externalApplication,
); );
}, },
child: Text( child: Text(
@@ -213,6 +214,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
Navigator.of(context).pop(); Navigator.of(context).pop();
launchUrl( launchUrl(
Uri.parse('https://github.com/immich-app/immich'), Uri.parse('https://github.com/immich-app/immich'),
mode: LaunchMode.externalApplication,
); );
}, },
child: Text( child: Text(

View File

@@ -182,19 +182,36 @@ class AppBarServerInfo extends HookConsumerWidget {
child: Container( child: Container(
width: 200, width: 200,
padding: const EdgeInsets.only(right: 10.0), padding: const EdgeInsets.only(right: 10.0),
child: Text( child: Tooltip(
getServerUrl() ?? '--', verticalOffset: 0,
style: TextStyle( decoration: BoxDecoration(
fontSize: 11, color:
color: Theme.of(context) Theme.of(context).primaryColor.withOpacity(0.9),
.textTheme borderRadius: BorderRadius.circular(10),
.labelSmall ),
?.color textStyle: TextStyle(
?.withOpacity(0.5), color: Theme.of(context).brightness == Brightness.dark
fontWeight: FontWeight.bold, ? Colors.black
overflow: TextOverflow.ellipsis, : Colors.white,
fontWeight: FontWeight.bold,
),
message: getServerUrl() ?? '--',
preferBelow: false,
triggerMode: TooltipTriggerMode.tap,
child: Text(
getServerUrl() ?? '--',
style: TextStyle(
fontSize: 11,
color: Theme.of(context)
.textTheme
.labelSmall
?.color
?.withOpacity(0.5),
fontWeight: FontWeight.bold,
overflow: TextOverflow.ellipsis,
),
textAlign: TextAlign.end,
), ),
textAlign: TextAlign.end,
), ),
), ),
), ),

View File

@@ -31,7 +31,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isDarkMode = Theme.of(context).brightness == Brightness.dark;
const widgetSize = 30.0; const widgetSize = 30.0;
buildProfilePhoto() { buildProfileIndicator() {
return InkWell( return InkWell(
onTap: () => showDialog( onTap: () => showDialog(
context: context, context: context,
@@ -39,37 +39,33 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
builder: (ctx) => const ImmichAppBarDialog(), builder: (ctx) => const ImmichAppBarDialog(),
), ),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
child: authState.profileImagePath.isEmpty || user == null child: Badge(
? const Icon( label: Container(
Icons.face_outlined, decoration: BoxDecoration(
size: widgetSize, color: Colors.black,
) borderRadius: BorderRadius.circular(widgetSize / 2),
: UserCircleAvatar( ),
radius: 15, child: const Icon(
size: 27, Icons.info,
user: user, color: Color.fromARGB(255, 243, 188, 106),
), size: widgetSize / 2,
); ),
}
buildProfileIndicator() {
return Badge(
label: Container(
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(widgetSize / 2),
),
child: const Icon(
Icons.info,
color: Color.fromARGB(255, 243, 188, 106),
size: widgetSize / 2,
), ),
backgroundColor: Colors.transparent,
alignment: Alignment.bottomRight,
isLabelVisible: serverInfoState.isVersionMismatch,
offset: const Offset(2, 2),
child: authState.profileImagePath.isEmpty || user == null
? const Icon(
Icons.face_outlined,
size: widgetSize,
)
: UserCircleAvatar(
radius: 15,
size: 27,
user: user,
),
), ),
backgroundColor: Colors.transparent,
alignment: Alignment.bottomRight,
isLabelVisible: serverInfoState.isVersionMismatch,
offset: const Offset(2, 2),
child: buildProfilePhoto(),
); );
} }

View File

@@ -40,19 +40,23 @@ class UserCircleAvatar extends ConsumerWidget {
final profileImageUrl = final profileImageUrl =
'${Store.get(StoreKey.serverEndpoint)}/user/profile-image/${user.id}?d=${Random().nextInt(1024)}'; '${Store.get(StoreKey.serverEndpoint)}/user/profile-image/${user.id}?d=${Random().nextInt(1024)}';
final textIcon = Text(
user.firstName[0].toUpperCase(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).brightness == Brightness.dark
? Colors.black
: Colors.white,
),
);
return CircleAvatar( return CircleAvatar(
backgroundColor: useRandomBackgroundColor backgroundColor: useRandomBackgroundColor
? randomColors[Random().nextInt(randomColors.length)] ? randomColors[Random().nextInt(randomColors.length)]
: Theme.of(context).primaryColor, : Theme.of(context).primaryColor,
radius: radius, radius: radius,
child: user.profileImagePath == "" child: user.profileImagePath == ""
? Text( ? textIcon
user.firstName[0].toUpperCase(),
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
),
)
: ClipRRect( : ClipRRect(
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
child: CachedNetworkImage( child: CachedNetworkImage(
@@ -66,8 +70,7 @@ class UserCircleAvatar extends ConsumerWidget {
"Authorization": "Bearer ${Store.get(StoreKey.accessToken)}", "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
}, },
fadeInDuration: const Duration(milliseconds: 300), fadeInDuration: const Duration(milliseconds: 300),
errorWidget: (context, error, stackTrace) => errorWidget: (context, error, stackTrace) => textIcon,
Image.memory(kTransparentImage),
), ),
), ),
); );

View File

@@ -0,0 +1,36 @@
extension TimeAgoExtension on DateTime {
String timeAgo({bool numericDates = true}) {
DateTime date = toLocal();
final date2 = DateTime.now().toLocal();
final difference = date2.difference(date);
if (difference.inSeconds < 5) {
return 'Just now';
} else if (difference.inSeconds < 60) {
return '${difference.inSeconds} seconds ago';
} else if (difference.inMinutes <= 1) {
return (numericDates) ? '1 minute ago' : 'A minute ago';
} else if (difference.inMinutes < 60) {
return '${difference.inMinutes} minutes ago';
} else if (difference.inHours <= 1) {
return (numericDates) ? '1 hour ago' : 'An hour ago';
} else if (difference.inHours < 60) {
return '${difference.inHours} hours ago';
} else if (difference.inDays <= 1) {
return (numericDates) ? '1 day ago' : 'Yesterday';
} else if (difference.inDays < 6) {
return '${difference.inDays} days ago';
} else if ((difference.inDays / 7).ceil() <= 1) {
return (numericDates) ? '1 week ago' : 'Last week';
} else if ((difference.inDays / 7).ceil() < 4) {
return '${(difference.inDays / 7).ceil()} weeks ago';
} else if ((difference.inDays / 30).ceil() <= 1) {
return (numericDates) ? '1 month ago' : 'Last month';
} else if ((difference.inDays / 30).ceil() < 30) {
return '${(difference.inDays / 30).ceil()} months ago';
} else if ((difference.inDays / 365).ceil() <= 1) {
return (numericDates) ? '1 year ago' : 'Last year';
}
return '${(difference.inDays / 365).floor()} years ago';
}
}

View File

@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 1.84.0 - API version: 1.85.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen - Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements ## Requirements
@@ -58,10 +58,10 @@ final api_instance = APIKeyApi();
final aPIKeyCreateDto = APIKeyCreateDto(); // APIKeyCreateDto | final aPIKeyCreateDto = APIKeyCreateDto(); // APIKeyCreateDto |
try { try {
final result = api_instance.createKey(aPIKeyCreateDto); final result = api_instance.createApiKey(aPIKeyCreateDto);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling APIKeyApi->createKey: $e\n'); print('Exception when calling APIKeyApi->createApiKey: $e\n');
} }
``` ```
@@ -72,11 +72,11 @@ All URIs are relative to */api*
Class | Method | HTTP request | Description Class | Method | HTTP request | Description
------------ | ------------- | ------------- | ------------- ------------ | ------------- | ------------- | -------------
*APIKeyApi* | [**createKey**](doc//APIKeyApi.md#createkey) | **POST** /api-key | *APIKeyApi* | [**createApiKey**](doc//APIKeyApi.md#createapikey) | **POST** /api-key |
*APIKeyApi* | [**deleteKey**](doc//APIKeyApi.md#deletekey) | **DELETE** /api-key/{id} | *APIKeyApi* | [**deleteApiKey**](doc//APIKeyApi.md#deleteapikey) | **DELETE** /api-key/{id} |
*APIKeyApi* | [**getKey**](doc//APIKeyApi.md#getkey) | **GET** /api-key/{id} | *APIKeyApi* | [**getApiKey**](doc//APIKeyApi.md#getapikey) | **GET** /api-key/{id} |
*APIKeyApi* | [**getKeys**](doc//APIKeyApi.md#getkeys) | **GET** /api-key | *APIKeyApi* | [**getApiKeys**](doc//APIKeyApi.md#getapikeys) | **GET** /api-key |
*APIKeyApi* | [**updateKey**](doc//APIKeyApi.md#updatekey) | **PUT** /api-key/{id} | *APIKeyApi* | [**updateApiKey**](doc//APIKeyApi.md#updateapikey) | **PUT** /api-key/{id} |
*ActivityApi* | [**createActivity**](doc//ActivityApi.md#createactivity) | **POST** /activity | *ActivityApi* | [**createActivity**](doc//ActivityApi.md#createactivity) | **POST** /activity |
*ActivityApi* | [**deleteActivity**](doc//ActivityApi.md#deleteactivity) | **DELETE** /activity/{id} | *ActivityApi* | [**deleteActivity**](doc//ActivityApi.md#deleteactivity) | **DELETE** /activity/{id} |
*ActivityApi* | [**getActivities**](doc//ActivityApi.md#getactivities) | **GET** /activity | *ActivityApi* | [**getActivities**](doc//ActivityApi.md#getactivities) | **GET** /activity |
@@ -91,7 +91,7 @@ Class | Method | HTTP request | Description
*AlbumApi* | [**removeAssetFromAlbum**](doc//AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets | *AlbumApi* | [**removeAssetFromAlbum**](doc//AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets |
*AlbumApi* | [**removeUserFromAlbum**](doc//AlbumApi.md#removeuserfromalbum) | **DELETE** /album/{id}/user/{userId} | *AlbumApi* | [**removeUserFromAlbum**](doc//AlbumApi.md#removeuserfromalbum) | **DELETE** /album/{id}/user/{userId} |
*AlbumApi* | [**updateAlbumInfo**](doc//AlbumApi.md#updatealbuminfo) | **PATCH** /album/{id} | *AlbumApi* | [**updateAlbumInfo**](doc//AlbumApi.md#updatealbuminfo) | **PATCH** /album/{id} |
*AssetApi* | [**bulkUploadCheck**](doc//AssetApi.md#bulkuploadcheck) | **POST** /asset/bulk-upload-check | *AssetApi* | [**checkBulkUpload**](doc//AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check |
*AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist | *AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist |
*AssetApi* | [**deleteAssets**](doc//AssetApi.md#deleteassets) | **DELETE** /asset | *AssetApi* | [**deleteAssets**](doc//AssetApi.md#deleteassets) | **DELETE** /asset |
*AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download/archive | *AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download/archive |
@@ -100,15 +100,15 @@ Class | Method | HTTP request | Description
*AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset | *AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset |
*AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | *AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} |
*AssetApi* | [**getAssetSearchTerms**](doc//AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms | *AssetApi* | [**getAssetSearchTerms**](doc//AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms |
*AssetApi* | [**getAssetStats**](doc//AssetApi.md#getassetstats) | **GET** /asset/statistics | *AssetApi* | [**getAssetStatistics**](doc//AssetApi.md#getassetstatistics) | **GET** /asset/statistics |
*AssetApi* | [**getAssetThumbnail**](doc//AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} | *AssetApi* | [**getAssetThumbnail**](doc//AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} |
*AssetApi* | [**getByTimeBucket**](doc//AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket |
*AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | *AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
*AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects | *AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
*AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **POST** /asset/download/info | *AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **POST** /asset/download/info |
*AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker | *AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
*AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | *AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
*AssetApi* | [**getRandom**](doc//AssetApi.md#getrandom) | **GET** /asset/random | *AssetApi* | [**getRandom**](doc//AssetApi.md#getrandom) | **GET** /asset/random |
*AssetApi* | [**getTimeBucket**](doc//AssetApi.md#gettimebucket) | **GET** /asset/time-bucket |
*AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | *AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets |
*AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | *AssetApi* | [**getUserAssetsByDeviceId**](doc//AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
*AssetApi* | [**importFile**](doc//AssetApi.md#importfile) | **POST** /asset/import | *AssetApi* | [**importFile**](doc//AssetApi.md#importfile) | **POST** /asset/import |
@@ -125,30 +125,30 @@ Class | Method | HTTP request | Description
*AuditApi* | [**getAuditDeletes**](doc//AuditApi.md#getauditdeletes) | **GET** /audit/deletes | *AuditApi* | [**getAuditDeletes**](doc//AuditApi.md#getauditdeletes) | **GET** /audit/deletes |
*AuditApi* | [**getAuditFiles**](doc//AuditApi.md#getauditfiles) | **GET** /audit/file-report | *AuditApi* | [**getAuditFiles**](doc//AuditApi.md#getauditfiles) | **GET** /audit/file-report |
*AuditApi* | [**getFileChecksums**](doc//AuditApi.md#getfilechecksums) | **POST** /audit/file-report/checksum | *AuditApi* | [**getFileChecksums**](doc//AuditApi.md#getfilechecksums) | **POST** /audit/file-report/checksum |
*AuthenticationApi* | [**adminSignUp**](doc//AuthenticationApi.md#adminsignup) | **POST** /auth/admin-sign-up |
*AuthenticationApi* | [**changePassword**](doc//AuthenticationApi.md#changepassword) | **POST** /auth/change-password | *AuthenticationApi* | [**changePassword**](doc//AuthenticationApi.md#changepassword) | **POST** /auth/change-password |
*AuthenticationApi* | [**getAuthDevices**](doc//AuthenticationApi.md#getauthdevices) | **GET** /auth/devices | *AuthenticationApi* | [**getAuthDevices**](doc//AuthenticationApi.md#getauthdevices) | **GET** /auth/devices |
*AuthenticationApi* | [**login**](doc//AuthenticationApi.md#login) | **POST** /auth/login | *AuthenticationApi* | [**login**](doc//AuthenticationApi.md#login) | **POST** /auth/login |
*AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout | *AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout |
*AuthenticationApi* | [**logoutAuthDevice**](doc//AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | *AuthenticationApi* | [**logoutAuthDevice**](doc//AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} |
*AuthenticationApi* | [**logoutAuthDevices**](doc//AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices | *AuthenticationApi* | [**logoutAuthDevices**](doc//AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices |
*AuthenticationApi* | [**signUpAdmin**](doc//AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up |
*AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | *AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken |
*JobApi* | [**getAllJobsStatus**](doc//JobApi.md#getalljobsstatus) | **GET** /jobs | *JobApi* | [**getAllJobsStatus**](doc//JobApi.md#getalljobsstatus) | **GET** /jobs |
*JobApi* | [**sendJobCommand**](doc//JobApi.md#sendjobcommand) | **PUT** /jobs/{id} | *JobApi* | [**sendJobCommand**](doc//JobApi.md#sendjobcommand) | **PUT** /jobs/{id} |
*LibraryApi* | [**createLibrary**](doc//LibraryApi.md#createlibrary) | **POST** /library | *LibraryApi* | [**createLibrary**](doc//LibraryApi.md#createlibrary) | **POST** /library |
*LibraryApi* | [**deleteLibrary**](doc//LibraryApi.md#deletelibrary) | **DELETE** /library/{id} | *LibraryApi* | [**deleteLibrary**](doc//LibraryApi.md#deletelibrary) | **DELETE** /library/{id} |
*LibraryApi* | [**getAllForUser**](doc//LibraryApi.md#getallforuser) | **GET** /library | *LibraryApi* | [**getLibraries**](doc//LibraryApi.md#getlibraries) | **GET** /library |
*LibraryApi* | [**getLibraryInfo**](doc//LibraryApi.md#getlibraryinfo) | **GET** /library/{id} | *LibraryApi* | [**getLibraryInfo**](doc//LibraryApi.md#getlibraryinfo) | **GET** /library/{id} |
*LibraryApi* | [**getLibraryStatistics**](doc//LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics | *LibraryApi* | [**getLibraryStatistics**](doc//LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
*LibraryApi* | [**removeOfflineFiles**](doc//LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline | *LibraryApi* | [**removeOfflineFiles**](doc//LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
*LibraryApi* | [**scanLibrary**](doc//LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan | *LibraryApi* | [**scanLibrary**](doc//LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan |
*LibraryApi* | [**updateLibrary**](doc//LibraryApi.md#updatelibrary) | **PUT** /library/{id} | *LibraryApi* | [**updateLibrary**](doc//LibraryApi.md#updatelibrary) | **PUT** /library/{id} |
*OAuthApi* | [**authorizeOAuth**](doc//OAuthApi.md#authorizeoauth) | **POST** /oauth/authorize | *OAuthApi* | [**finishOAuth**](doc//OAuthApi.md#finishoauth) | **POST** /oauth/callback |
*OAuthApi* | [**callback**](doc//OAuthApi.md#callback) | **POST** /oauth/callback | *OAuthApi* | [**generateOAuthConfig**](doc//OAuthApi.md#generateoauthconfig) | **POST** /oauth/config |
*OAuthApi* | [**generateConfig**](doc//OAuthApi.md#generateconfig) | **POST** /oauth/config | *OAuthApi* | [**linkOAuthAccount**](doc//OAuthApi.md#linkoauthaccount) | **POST** /oauth/link |
*OAuthApi* | [**link**](doc//OAuthApi.md#link) | **POST** /oauth/link | *OAuthApi* | [**redirectOAuthToMobile**](doc//OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect |
*OAuthApi* | [**mobileRedirect**](doc//OAuthApi.md#mobileredirect) | **GET** /oauth/mobile-redirect | *OAuthApi* | [**startOAuth**](doc//OAuthApi.md#startoauth) | **POST** /oauth/authorize |
*OAuthApi* | [**unlink**](doc//OAuthApi.md#unlink) | **POST** /oauth/unlink | *OAuthApi* | [**unlinkOAuthAccount**](doc//OAuthApi.md#unlinkoauthaccount) | **POST** /oauth/unlink |
*PartnerApi* | [**createPartner**](doc//PartnerApi.md#createpartner) | **POST** /partner/{id} | *PartnerApi* | [**createPartner**](doc//PartnerApi.md#createpartner) | **POST** /partner/{id} |
*PartnerApi* | [**getPartners**](doc//PartnerApi.md#getpartners) | **GET** /partner | *PartnerApi* | [**getPartners**](doc//PartnerApi.md#getpartners) | **GET** /partner |
*PartnerApi* | [**removePartner**](doc//PartnerApi.md#removepartner) | **DELETE** /partner/{id} | *PartnerApi* | [**removePartner**](doc//PartnerApi.md#removepartner) | **DELETE** /partner/{id} |
@@ -166,8 +166,8 @@ Class | Method | HTTP request | Description
*ServerInfoApi* | [**getServerConfig**](doc//ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | *ServerInfoApi* | [**getServerConfig**](doc//ServerInfoApi.md#getserverconfig) | **GET** /server-info/config |
*ServerInfoApi* | [**getServerFeatures**](doc//ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | *ServerInfoApi* | [**getServerFeatures**](doc//ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features |
*ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info | *ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info |
*ServerInfoApi* | [**getServerStatistics**](doc//ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics |
*ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version | *ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version |
*ServerInfoApi* | [**getStats**](doc//ServerInfoApi.md#getstats) | **GET** /server-info/stats |
*ServerInfoApi* | [**getSupportedMediaTypes**](doc//ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types | *ServerInfoApi* | [**getSupportedMediaTypes**](doc//ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types |
*ServerInfoApi* | [**getTheme**](doc//ServerInfoApi.md#gettheme) | **GET** /server-info/theme | *ServerInfoApi* | [**getTheme**](doc//ServerInfoApi.md#gettheme) | **GET** /server-info/theme |
*ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping | *ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping |
@@ -180,7 +180,7 @@ Class | Method | HTTP request | Description
*SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets | *SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets |
*SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} | *SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} |
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config | *SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |
*SystemConfigApi* | [**getDefaults**](doc//SystemConfigApi.md#getdefaults) | **GET** /system-config/defaults | *SystemConfigApi* | [**getConfigDefaults**](doc//SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
*SystemConfigApi* | [**getStorageTemplateOptions**](doc//SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options | *SystemConfigApi* | [**getStorageTemplateOptions**](doc//SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options |
*SystemConfigApi* | [**updateConfig**](doc//SystemConfigApi.md#updateconfig) | **PUT** /system-config | *SystemConfigApi* | [**updateConfig**](doc//SystemConfigApi.md#updateconfig) | **PUT** /system-config |
*TagApi* | [**createTag**](doc//TagApi.md#createtag) | **POST** /tag | *TagApi* | [**createTag**](doc//TagApi.md#createtag) | **POST** /tag |

View File

@@ -9,15 +9,15 @@ All URIs are relative to */api*
Method | HTTP request | Description Method | HTTP request | Description
------------- | ------------- | ------------- ------------- | ------------- | -------------
[**createKey**](APIKeyApi.md#createkey) | **POST** /api-key | [**createApiKey**](APIKeyApi.md#createapikey) | **POST** /api-key |
[**deleteKey**](APIKeyApi.md#deletekey) | **DELETE** /api-key/{id} | [**deleteApiKey**](APIKeyApi.md#deleteapikey) | **DELETE** /api-key/{id} |
[**getKey**](APIKeyApi.md#getkey) | **GET** /api-key/{id} | [**getApiKey**](APIKeyApi.md#getapikey) | **GET** /api-key/{id} |
[**getKeys**](APIKeyApi.md#getkeys) | **GET** /api-key | [**getApiKeys**](APIKeyApi.md#getapikeys) | **GET** /api-key |
[**updateKey**](APIKeyApi.md#updatekey) | **PUT** /api-key/{id} | [**updateApiKey**](APIKeyApi.md#updateapikey) | **PUT** /api-key/{id} |
# **createKey** # **createApiKey**
> APIKeyCreateResponseDto createKey(aPIKeyCreateDto) > APIKeyCreateResponseDto createApiKey(aPIKeyCreateDto)
@@ -43,10 +43,10 @@ final api_instance = APIKeyApi();
final aPIKeyCreateDto = APIKeyCreateDto(); // APIKeyCreateDto | final aPIKeyCreateDto = APIKeyCreateDto(); // APIKeyCreateDto |
try { try {
final result = api_instance.createKey(aPIKeyCreateDto); final result = api_instance.createApiKey(aPIKeyCreateDto);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling APIKeyApi->createKey: $e\n'); print('Exception when calling APIKeyApi->createApiKey: $e\n');
} }
``` ```
@@ -71,8 +71,8 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **deleteKey** # **deleteApiKey**
> deleteKey(id) > deleteApiKey(id)
@@ -98,9 +98,9 @@ final api_instance = APIKeyApi();
final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
try { try {
api_instance.deleteKey(id); api_instance.deleteApiKey(id);
} catch (e) { } catch (e) {
print('Exception when calling APIKeyApi->deleteKey: $e\n'); print('Exception when calling APIKeyApi->deleteApiKey: $e\n');
} }
``` ```
@@ -125,8 +125,8 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getKey** # **getApiKey**
> APIKeyResponseDto getKey(id) > APIKeyResponseDto getApiKey(id)
@@ -152,10 +152,10 @@ final api_instance = APIKeyApi();
final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
try { try {
final result = api_instance.getKey(id); final result = api_instance.getApiKey(id);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling APIKeyApi->getKey: $e\n'); print('Exception when calling APIKeyApi->getApiKey: $e\n');
} }
``` ```
@@ -180,8 +180,8 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getKeys** # **getApiKeys**
> List<APIKeyResponseDto> getKeys() > List<APIKeyResponseDto> getApiKeys()
@@ -206,10 +206,10 @@ import 'package:openapi/api.dart';
final api_instance = APIKeyApi(); final api_instance = APIKeyApi();
try { try {
final result = api_instance.getKeys(); final result = api_instance.getApiKeys();
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling APIKeyApi->getKeys: $e\n'); print('Exception when calling APIKeyApi->getApiKeys: $e\n');
} }
``` ```
@@ -231,8 +231,8 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **updateKey** # **updateApiKey**
> APIKeyResponseDto updateKey(id, aPIKeyUpdateDto) > APIKeyResponseDto updateApiKey(id, aPIKeyUpdateDto)
@@ -259,10 +259,10 @@ final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final aPIKeyUpdateDto = APIKeyUpdateDto(); // APIKeyUpdateDto | final aPIKeyUpdateDto = APIKeyUpdateDto(); // APIKeyUpdateDto |
try { try {
final result = api_instance.updateKey(id, aPIKeyUpdateDto); final result = api_instance.updateApiKey(id, aPIKeyUpdateDto);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling APIKeyApi->updateKey: $e\n'); print('Exception when calling APIKeyApi->updateApiKey: $e\n');
} }
``` ```

View File

@@ -17,6 +17,7 @@ Name | Type | Description | Notes
**endDate** | [**DateTime**](DateTime.md) | | [optional] **endDate** | [**DateTime**](DateTime.md) | | [optional]
**hasSharedLink** | **bool** | | **hasSharedLink** | **bool** | |
**id** | **String** | | **id** | **String** | |
**isActivityEnabled** | **bool** | |
**lastModifiedAssetTimestamp** | [**DateTime**](DateTime.md) | | [optional] **lastModifiedAssetTimestamp** | [**DateTime**](DateTime.md) | | [optional]
**owner** | [**UserResponseDto**](UserResponseDto.md) | | **owner** | [**UserResponseDto**](UserResponseDto.md) | |
**ownerId** | **String** | | **ownerId** | **String** | |

View File

@@ -9,7 +9,7 @@ All URIs are relative to */api*
Method | HTTP request | Description Method | HTTP request | Description
------------- | ------------- | ------------- ------------- | ------------- | -------------
[**bulkUploadCheck**](AssetApi.md#bulkuploadcheck) | **POST** /asset/bulk-upload-check | [**checkBulkUpload**](AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check |
[**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist | [**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist |
[**deleteAssets**](AssetApi.md#deleteassets) | **DELETE** /asset | [**deleteAssets**](AssetApi.md#deleteassets) | **DELETE** /asset |
[**downloadArchive**](AssetApi.md#downloadarchive) | **POST** /asset/download/archive | [**downloadArchive**](AssetApi.md#downloadarchive) | **POST** /asset/download/archive |
@@ -18,15 +18,15 @@ Method | HTTP request | Description
[**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset | [**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset |
[**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | [**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} |
[**getAssetSearchTerms**](AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms | [**getAssetSearchTerms**](AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms |
[**getAssetStats**](AssetApi.md#getassetstats) | **GET** /asset/statistics | [**getAssetStatistics**](AssetApi.md#getassetstatistics) | **GET** /asset/statistics |
[**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} | [**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} |
[**getByTimeBucket**](AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket |
[**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | [**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
[**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects | [**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
[**getDownloadInfo**](AssetApi.md#getdownloadinfo) | **POST** /asset/download/info | [**getDownloadInfo**](AssetApi.md#getdownloadinfo) | **POST** /asset/download/info |
[**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/map-marker | [**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
[**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | [**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
[**getRandom**](AssetApi.md#getrandom) | **GET** /asset/random | [**getRandom**](AssetApi.md#getrandom) | **GET** /asset/random |
[**getTimeBucket**](AssetApi.md#gettimebucket) | **GET** /asset/time-bucket |
[**getTimeBuckets**](AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | [**getTimeBuckets**](AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets |
[**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} | [**getUserAssetsByDeviceId**](AssetApi.md#getuserassetsbydeviceid) | **GET** /asset/{deviceId} |
[**importFile**](AssetApi.md#importfile) | **POST** /asset/import | [**importFile**](AssetApi.md#importfile) | **POST** /asset/import |
@@ -41,8 +41,8 @@ Method | HTTP request | Description
[**uploadFile**](AssetApi.md#uploadfile) | **POST** /asset/upload | [**uploadFile**](AssetApi.md#uploadfile) | **POST** /asset/upload |
# **bulkUploadCheck** # **checkBulkUpload**
> AssetBulkUploadCheckResponseDto bulkUploadCheck(assetBulkUploadCheckDto) > AssetBulkUploadCheckResponseDto checkBulkUpload(assetBulkUploadCheckDto)
@@ -70,10 +70,10 @@ final api_instance = AssetApi();
final assetBulkUploadCheckDto = AssetBulkUploadCheckDto(); // AssetBulkUploadCheckDto | final assetBulkUploadCheckDto = AssetBulkUploadCheckDto(); // AssetBulkUploadCheckDto |
try { try {
final result = api_instance.bulkUploadCheck(assetBulkUploadCheckDto); final result = api_instance.checkBulkUpload(assetBulkUploadCheckDto);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling AssetApi->bulkUploadCheck: $e\n'); print('Exception when calling AssetApi->checkBulkUpload: $e\n');
} }
``` ```
@@ -374,7 +374,7 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getAllAssets** # **getAllAssets**
> List<AssetResponseDto> getAllAssets(userId, isFavorite, isArchived, skip, updatedAfter, ifNoneMatch) > List<AssetResponseDto> getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch)
@@ -399,15 +399,17 @@ import 'package:openapi/api.dart';
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction); //defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi(); final api_instance = AssetApi();
final skip = 56; // int |
final take = 56; // int |
final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final isFavorite = true; // bool | final isFavorite = true; // bool |
final isArchived = true; // bool | final isArchived = true; // bool |
final skip = 8.14; // num |
final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime | final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime |
final updatedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
final ifNoneMatch = ifNoneMatch_example; // String | ETag of data already cached on the client final ifNoneMatch = ifNoneMatch_example; // String | ETag of data already cached on the client
try { try {
final result = api_instance.getAllAssets(userId, isFavorite, isArchived, skip, updatedAfter, ifNoneMatch); final result = api_instance.getAllAssets(skip, take, userId, isFavorite, isArchived, updatedAfter, updatedBefore, ifNoneMatch);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling AssetApi->getAllAssets: $e\n'); print('Exception when calling AssetApi->getAllAssets: $e\n');
@@ -418,11 +420,13 @@ try {
Name | Type | Description | Notes Name | Type | Description | Notes
------------- | ------------- | ------------- | ------------- ------------- | ------------- | ------------- | -------------
**skip** | **int**| | [optional]
**take** | **int**| | [optional]
**userId** | **String**| | [optional] **userId** | **String**| | [optional]
**isFavorite** | **bool**| | [optional] **isFavorite** | **bool**| | [optional]
**isArchived** | **bool**| | [optional] **isArchived** | **bool**| | [optional]
**skip** | **num**| | [optional]
**updatedAfter** | **DateTime**| | [optional] **updatedAfter** | **DateTime**| | [optional]
**updatedBefore** | **DateTime**| | [optional]
**ifNoneMatch** | **String**| ETag of data already cached on the client | [optional] **ifNoneMatch** | **String**| ETag of data already cached on the client | [optional]
### Return type ### Return type
@@ -550,8 +554,8 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getAssetStats** # **getAssetStatistics**
> AssetStatsResponseDto getAssetStats(isArchived, isFavorite, isTrashed) > AssetStatsResponseDto getAssetStatistics(isArchived, isFavorite, isTrashed)
@@ -579,10 +583,10 @@ final isFavorite = true; // bool |
final isTrashed = true; // bool | final isTrashed = true; // bool |
try { try {
final result = api_instance.getAssetStats(isArchived, isFavorite, isTrashed); final result = api_instance.getAssetStatistics(isArchived, isFavorite, isTrashed);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling AssetApi->getAssetStats: $e\n'); print('Exception when calling AssetApi->getAssetStatistics: $e\n');
} }
``` ```
@@ -668,79 +672,6 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getByTimeBucket**
> List<AssetResponseDto> getByTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key)
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi();
final size = ; // TimeBucketSize |
final timeBucket = timeBucket_example; // String |
final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final personId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final isArchived = true; // bool |
final isFavorite = true; // bool |
final isTrashed = true; // bool |
final withStacked = true; // bool |
final key = key_example; // String |
try {
final result = api_instance.getByTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key);
print(result);
} catch (e) {
print('Exception when calling AssetApi->getByTimeBucket: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**size** | [**TimeBucketSize**](.md)| |
**timeBucket** | **String**| |
**userId** | **String**| | [optional]
**albumId** | **String**| | [optional]
**personId** | **String**| | [optional]
**isArchived** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional]
**isTrashed** | **bool**| | [optional]
**withStacked** | **bool**| | [optional]
**key** | **String**| | [optional]
### Return type
[**List<AssetResponseDto>**](AssetResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getCuratedLocations** # **getCuratedLocations**
> List<CuratedLocationsResponseDto> getCuratedLocations() > List<CuratedLocationsResponseDto> getCuratedLocations()
@@ -1073,6 +1004,79 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getTimeBucket**
> List<AssetResponseDto> getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key)
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi();
final size = ; // TimeBucketSize |
final timeBucket = timeBucket_example; // String |
final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final personId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
final isArchived = true; // bool |
final isFavorite = true; // bool |
final isTrashed = true; // bool |
final withStacked = true; // bool |
final key = key_example; // String |
try {
final result = api_instance.getTimeBucket(size, timeBucket, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key);
print(result);
} catch (e) {
print('Exception when calling AssetApi->getTimeBucket: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**size** | [**TimeBucketSize**](.md)| |
**timeBucket** | **String**| |
**userId** | **String**| | [optional]
**albumId** | **String**| | [optional]
**personId** | **String**| | [optional]
**isArchived** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional]
**isTrashed** | **bool**| | [optional]
**withStacked** | **bool**| | [optional]
**key** | **String**| | [optional]
### Return type
[**List<AssetResponseDto>**](AssetResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getTimeBuckets** # **getTimeBuckets**
> List<TimeBucketResponseDto> getTimeBuckets(size, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key) > List<TimeBucketResponseDto> getTimeBuckets(size, userId, albumId, personId, isArchived, isFavorite, isTrashed, withStacked, key)
@@ -1696,7 +1700,7 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **uploadFile** # **uploadFile**
> AssetFileUploadResponseDto uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, duration, isArchived, isExternal, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData) > AssetFileUploadResponseDto uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isExternal, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData)
@@ -1724,11 +1728,11 @@ final deviceAssetId = deviceAssetId_example; // String |
final deviceId = deviceId_example; // String | final deviceId = deviceId_example; // String |
final fileCreatedAt = 2013-10-20T19:20:30+01:00; // DateTime | final fileCreatedAt = 2013-10-20T19:20:30+01:00; // DateTime |
final fileModifiedAt = 2013-10-20T19:20:30+01:00; // DateTime | final fileModifiedAt = 2013-10-20T19:20:30+01:00; // DateTime |
final isFavorite = true; // bool |
final key = key_example; // String | final key = key_example; // String |
final duration = duration_example; // String | final duration = duration_example; // String |
final isArchived = true; // bool | final isArchived = true; // bool |
final isExternal = true; // bool | final isExternal = true; // bool |
final isFavorite = true; // bool |
final isOffline = true; // bool | final isOffline = true; // bool |
final isReadOnly = true; // bool | final isReadOnly = true; // bool |
final isVisible = true; // bool | final isVisible = true; // bool |
@@ -1737,7 +1741,7 @@ final livePhotoData = BINARY_DATA_HERE; // MultipartFile |
final sidecarData = BINARY_DATA_HERE; // MultipartFile | final sidecarData = BINARY_DATA_HERE; // MultipartFile |
try { try {
final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, duration, isArchived, isExternal, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData); final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, duration, isArchived, isExternal, isFavorite, isOffline, isReadOnly, isVisible, libraryId, livePhotoData, sidecarData);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling AssetApi->uploadFile: $e\n'); print('Exception when calling AssetApi->uploadFile: $e\n');
@@ -1753,11 +1757,11 @@ Name | Type | Description | Notes
**deviceId** | **String**| | **deviceId** | **String**| |
**fileCreatedAt** | **DateTime**| | **fileCreatedAt** | **DateTime**| |
**fileModifiedAt** | **DateTime**| | **fileModifiedAt** | **DateTime**| |
**isFavorite** | **bool**| |
**key** | **String**| | [optional] **key** | **String**| | [optional]
**duration** | **String**| | [optional] **duration** | **String**| | [optional]
**isArchived** | **bool**| | [optional] **isArchived** | **bool**| | [optional]
**isExternal** | **bool**| | [optional] **isExternal** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional]
**isOffline** | **bool**| | [optional] **isOffline** | **bool**| | [optional]
**isReadOnly** | **bool**| | [optional] **isReadOnly** | **bool**| | [optional]
**isVisible** | **bool**| | [optional] **isVisible** | **bool**| | [optional]

View File

@@ -9,57 +9,16 @@ All URIs are relative to */api*
Method | HTTP request | Description Method | HTTP request | Description
------------- | ------------- | ------------- ------------- | ------------- | -------------
[**adminSignUp**](AuthenticationApi.md#adminsignup) | **POST** /auth/admin-sign-up |
[**changePassword**](AuthenticationApi.md#changepassword) | **POST** /auth/change-password | [**changePassword**](AuthenticationApi.md#changepassword) | **POST** /auth/change-password |
[**getAuthDevices**](AuthenticationApi.md#getauthdevices) | **GET** /auth/devices | [**getAuthDevices**](AuthenticationApi.md#getauthdevices) | **GET** /auth/devices |
[**login**](AuthenticationApi.md#login) | **POST** /auth/login | [**login**](AuthenticationApi.md#login) | **POST** /auth/login |
[**logout**](AuthenticationApi.md#logout) | **POST** /auth/logout | [**logout**](AuthenticationApi.md#logout) | **POST** /auth/logout |
[**logoutAuthDevice**](AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} | [**logoutAuthDevice**](AuthenticationApi.md#logoutauthdevice) | **DELETE** /auth/devices/{id} |
[**logoutAuthDevices**](AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices | [**logoutAuthDevices**](AuthenticationApi.md#logoutauthdevices) | **DELETE** /auth/devices |
[**signUpAdmin**](AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up |
[**validateAccessToken**](AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | [**validateAccessToken**](AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken |
# **adminSignUp**
> AdminSignupResponseDto adminSignUp(signUpDto)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = AuthenticationApi();
final signUpDto = SignUpDto(); // SignUpDto |
try {
final result = api_instance.adminSignUp(signUpDto);
print(result);
} catch (e) {
print('Exception when calling AuthenticationApi->adminSignUp: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**signUpDto** | [**SignUpDto**](SignUpDto.md)| |
### Return type
[**AdminSignupResponseDto**](AdminSignupResponseDto.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **changePassword** # **changePassword**
> UserResponseDto changePassword(changePasswordDto) > UserResponseDto changePassword(changePasswordDto)
@@ -362,6 +321,47 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **signUpAdmin**
> AdminSignupResponseDto signUpAdmin(signUpDto)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = AuthenticationApi();
final signUpDto = SignUpDto(); // SignUpDto |
try {
final result = api_instance.signUpAdmin(signUpDto);
print(result);
} catch (e) {
print('Exception when calling AuthenticationApi->signUpAdmin: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**signUpDto** | [**SignUpDto**](SignUpDto.md)| |
### Return type
[**AdminSignupResponseDto**](AdminSignupResponseDto.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **validateAccessToken** # **validateAccessToken**
> ValidateAccessTokenResponseDto validateAccessToken() > ValidateAccessTokenResponseDto validateAccessToken()

View File

@@ -16,7 +16,7 @@ Name | Type | Description | Notes
**fileModifiedAt** | [**DateTime**](DateTime.md) | | **fileModifiedAt** | [**DateTime**](DateTime.md) | |
**isArchived** | **bool** | | [optional] **isArchived** | **bool** | | [optional]
**isExternal** | **bool** | | [optional] **isExternal** | **bool** | | [optional]
**isFavorite** | **bool** | | **isFavorite** | **bool** | | [optional]
**isOffline** | **bool** | | [optional] **isOffline** | **bool** | | [optional]
**isReadOnly** | **bool** | | [optional] [default to true] **isReadOnly** | **bool** | | [optional] [default to true]
**isVisible** | **bool** | | [optional] **isVisible** | **bool** | | [optional]

View File

@@ -11,7 +11,7 @@ Method | HTTP request | Description
------------- | ------------- | ------------- ------------- | ------------- | -------------
[**createLibrary**](LibraryApi.md#createlibrary) | **POST** /library | [**createLibrary**](LibraryApi.md#createlibrary) | **POST** /library |
[**deleteLibrary**](LibraryApi.md#deletelibrary) | **DELETE** /library/{id} | [**deleteLibrary**](LibraryApi.md#deletelibrary) | **DELETE** /library/{id} |
[**getAllForUser**](LibraryApi.md#getallforuser) | **GET** /library | [**getLibraries**](LibraryApi.md#getlibraries) | **GET** /library |
[**getLibraryInfo**](LibraryApi.md#getlibraryinfo) | **GET** /library/{id} | [**getLibraryInfo**](LibraryApi.md#getlibraryinfo) | **GET** /library/{id} |
[**getLibraryStatistics**](LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics | [**getLibraryStatistics**](LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
[**removeOfflineFiles**](LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline | [**removeOfflineFiles**](LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
@@ -128,8 +128,8 @@ void (empty response body)
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getAllForUser** # **getLibraries**
> List<LibraryResponseDto> getAllForUser() > List<LibraryResponseDto> getLibraries()
@@ -154,10 +154,10 @@ import 'package:openapi/api.dart';
final api_instance = LibraryApi(); final api_instance = LibraryApi();
try { try {
final result = api_instance.getAllForUser(); final result = api_instance.getLibraries();
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling LibraryApi->getAllForUser: $e\n'); print('Exception when calling LibraryApi->getLibraries: $e\n');
} }
``` ```

View File

@@ -9,57 +9,16 @@ All URIs are relative to */api*
Method | HTTP request | Description Method | HTTP request | Description
------------- | ------------- | ------------- ------------- | ------------- | -------------
[**authorizeOAuth**](OAuthApi.md#authorizeoauth) | **POST** /oauth/authorize | [**finishOAuth**](OAuthApi.md#finishoauth) | **POST** /oauth/callback |
[**callback**](OAuthApi.md#callback) | **POST** /oauth/callback | [**generateOAuthConfig**](OAuthApi.md#generateoauthconfig) | **POST** /oauth/config |
[**generateConfig**](OAuthApi.md#generateconfig) | **POST** /oauth/config | [**linkOAuthAccount**](OAuthApi.md#linkoauthaccount) | **POST** /oauth/link |
[**link**](OAuthApi.md#link) | **POST** /oauth/link | [**redirectOAuthToMobile**](OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect |
[**mobileRedirect**](OAuthApi.md#mobileredirect) | **GET** /oauth/mobile-redirect | [**startOAuth**](OAuthApi.md#startoauth) | **POST** /oauth/authorize |
[**unlink**](OAuthApi.md#unlink) | **POST** /oauth/unlink | [**unlinkOAuthAccount**](OAuthApi.md#unlinkoauthaccount) | **POST** /oauth/unlink |
# **authorizeOAuth** # **finishOAuth**
> OAuthAuthorizeResponseDto authorizeOAuth(oAuthConfigDto) > LoginResponseDto finishOAuth(oAuthCallbackDto)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = OAuthApi();
final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto |
try {
final result = api_instance.authorizeOAuth(oAuthConfigDto);
print(result);
} catch (e) {
print('Exception when calling OAuthApi->authorizeOAuth: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**oAuthConfigDto** | [**OAuthConfigDto**](OAuthConfigDto.md)| |
### Return type
[**OAuthAuthorizeResponseDto**](OAuthAuthorizeResponseDto.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **callback**
> LoginResponseDto callback(oAuthCallbackDto)
@@ -71,10 +30,10 @@ final api_instance = OAuthApi();
final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto | final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto |
try { try {
final result = api_instance.callback(oAuthCallbackDto); final result = api_instance.finishOAuth(oAuthCallbackDto);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling OAuthApi->callback: $e\n'); print('Exception when calling OAuthApi->finishOAuth: $e\n');
} }
``` ```
@@ -99,8 +58,8 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **generateConfig** # **generateOAuthConfig**
> OAuthConfigResponseDto generateConfig(oAuthConfigDto) > OAuthConfigResponseDto generateOAuthConfig(oAuthConfigDto)
@@ -114,10 +73,10 @@ final api_instance = OAuthApi();
final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto | final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto |
try { try {
final result = api_instance.generateConfig(oAuthConfigDto); final result = api_instance.generateOAuthConfig(oAuthConfigDto);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling OAuthApi->generateConfig: $e\n'); print('Exception when calling OAuthApi->generateOAuthConfig: $e\n');
} }
``` ```
@@ -142,8 +101,8 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **link** # **linkOAuthAccount**
> UserResponseDto link(oAuthCallbackDto) > UserResponseDto linkOAuthAccount(oAuthCallbackDto)
@@ -169,10 +128,10 @@ final api_instance = OAuthApi();
final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto | final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto |
try { try {
final result = api_instance.link(oAuthCallbackDto); final result = api_instance.linkOAuthAccount(oAuthCallbackDto);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling OAuthApi->link: $e\n'); print('Exception when calling OAuthApi->linkOAuthAccount: $e\n');
} }
``` ```
@@ -197,8 +156,8 @@ Name | Type | Description | Notes
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **mobileRedirect** # **redirectOAuthToMobile**
> mobileRedirect() > redirectOAuthToMobile()
@@ -209,9 +168,9 @@ import 'package:openapi/api.dart';
final api_instance = OAuthApi(); final api_instance = OAuthApi();
try { try {
api_instance.mobileRedirect(); api_instance.redirectOAuthToMobile();
} catch (e) { } catch (e) {
print('Exception when calling OAuthApi->mobileRedirect: $e\n'); print('Exception when calling OAuthApi->redirectOAuthToMobile: $e\n');
} }
``` ```
@@ -233,8 +192,49 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **unlink** # **startOAuth**
> UserResponseDto unlink() > OAuthAuthorizeResponseDto startOAuth(oAuthConfigDto)
### Example
```dart
import 'package:openapi/api.dart';
final api_instance = OAuthApi();
final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto |
try {
final result = api_instance.startOAuth(oAuthConfigDto);
print(result);
} catch (e) {
print('Exception when calling OAuthApi->startOAuth: $e\n');
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**oAuthConfigDto** | [**OAuthConfigDto**](OAuthConfigDto.md)| |
### Return type
[**OAuthAuthorizeResponseDto**](OAuthAuthorizeResponseDto.md)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **unlinkOAuthAccount**
> UserResponseDto unlinkOAuthAccount()
@@ -259,10 +259,10 @@ import 'package:openapi/api.dart';
final api_instance = OAuthApi(); final api_instance = OAuthApi();
try { try {
final result = api_instance.unlink(); final result = api_instance.unlinkOAuthAccount();
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling OAuthApi->unlink: $e\n'); print('Exception when calling OAuthApi->unlinkOAuthAccount: $e\n');
} }
``` ```

View File

@@ -12,8 +12,8 @@ Method | HTTP request | Description
[**getServerConfig**](ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | [**getServerConfig**](ServerInfoApi.md#getserverconfig) | **GET** /server-info/config |
[**getServerFeatures**](ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | [**getServerFeatures**](ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features |
[**getServerInfo**](ServerInfoApi.md#getserverinfo) | **GET** /server-info | [**getServerInfo**](ServerInfoApi.md#getserverinfo) | **GET** /server-info |
[**getServerStatistics**](ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics |
[**getServerVersion**](ServerInfoApi.md#getserverversion) | **GET** /server-info/version | [**getServerVersion**](ServerInfoApi.md#getserverversion) | **GET** /server-info/version |
[**getStats**](ServerInfoApi.md#getstats) | **GET** /server-info/stats |
[**getSupportedMediaTypes**](ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types | [**getSupportedMediaTypes**](ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types |
[**getTheme**](ServerInfoApi.md#gettheme) | **GET** /server-info/theme | [**getTheme**](ServerInfoApi.md#gettheme) | **GET** /server-info/theme |
[**pingServer**](ServerInfoApi.md#pingserver) | **GET** /server-info/ping | [**pingServer**](ServerInfoApi.md#pingserver) | **GET** /server-info/ping |
@@ -144,6 +144,57 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getServerStatistics**
> ServerStatsResponseDto getServerStatistics()
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = ServerInfoApi();
try {
final result = api_instance.getServerStatistics();
print(result);
} catch (e) {
print('Exception when calling ServerInfoApi->getServerStatistics: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
[**ServerStatsResponseDto**](ServerStatsResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getServerVersion** # **getServerVersion**
> ServerVersionResponseDto getServerVersion() > ServerVersionResponseDto getServerVersion()
@@ -181,57 +232,6 @@ No authorization required
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getStats**
> ServerStatsResponseDto getStats()
### Example
```dart
import 'package:openapi/api.dart';
// TODO Configure API key authorization: cookie
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('cookie').apiKeyPrefix = 'Bearer';
// TODO Configure API key authorization: api_key
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKey = 'YOUR_API_KEY';
// uncomment below to setup prefix (e.g. Bearer) for API key, if needed
//defaultApiClient.getAuthentication<ApiKeyAuth>('api_key').apiKeyPrefix = 'Bearer';
// TODO Configure HTTP Bearer authorization: bearer
// Case 1. Use String Token
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken('YOUR_ACCESS_TOKEN');
// Case 2. Use Function which generate token.
// String yourTokenGeneratorFunction() { ... }
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = ServerInfoApi();
try {
final result = api_instance.getStats();
print(result);
} catch (e) {
print('Exception when calling ServerInfoApi->getStats: $e\n');
}
```
### Parameters
This endpoint does not need any parameter.
### Return type
[**ServerStatsResponseDto**](ServerStatsResponseDto.md)
### Authorization
[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer)
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getSupportedMediaTypes** # **getSupportedMediaTypes**
> ServerMediaTypesResponseDto getSupportedMediaTypes() > ServerMediaTypesResponseDto getSupportedMediaTypes()

View File

@@ -10,7 +10,7 @@ All URIs are relative to */api*
Method | HTTP request | Description Method | HTTP request | Description
------------- | ------------- | ------------- ------------- | ------------- | -------------
[**getConfig**](SystemConfigApi.md#getconfig) | **GET** /system-config | [**getConfig**](SystemConfigApi.md#getconfig) | **GET** /system-config |
[**getDefaults**](SystemConfigApi.md#getdefaults) | **GET** /system-config/defaults | [**getConfigDefaults**](SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
[**getStorageTemplateOptions**](SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options | [**getStorageTemplateOptions**](SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options |
[**updateConfig**](SystemConfigApi.md#updateconfig) | **PUT** /system-config | [**updateConfig**](SystemConfigApi.md#updateconfig) | **PUT** /system-config |
@@ -66,8 +66,8 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getDefaults** # **getConfigDefaults**
> SystemConfigDto getDefaults() > SystemConfigDto getConfigDefaults()
@@ -92,10 +92,10 @@ import 'package:openapi/api.dart';
final api_instance = SystemConfigApi(); final api_instance = SystemConfigApi();
try { try {
final result = api_instance.getDefaults(); final result = api_instance.getConfigDefaults();
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling SystemConfigApi->getDefaults: $e\n'); print('Exception when calling SystemConfigApi->getConfigDefaults: $e\n');
} }
``` ```

View File

@@ -11,6 +11,7 @@ Name | Type | Description | Notes
**albumName** | **String** | | [optional] **albumName** | **String** | | [optional]
**albumThumbnailAssetId** | **String** | | [optional] **albumThumbnailAssetId** | **String** | | [optional]
**description** | **String** | | [optional] **description** | **String** | | [optional]
**isActivityEnabled** | **bool** | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -20,7 +20,7 @@ class APIKeyApi {
/// Parameters: /// Parameters:
/// ///
/// * [APIKeyCreateDto] aPIKeyCreateDto (required): /// * [APIKeyCreateDto] aPIKeyCreateDto (required):
Future<Response> createKeyWithHttpInfo(APIKeyCreateDto aPIKeyCreateDto,) async { Future<Response> createApiKeyWithHttpInfo(APIKeyCreateDto aPIKeyCreateDto,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key'; final path = r'/api-key';
@@ -48,8 +48,8 @@ class APIKeyApi {
/// Parameters: /// Parameters:
/// ///
/// * [APIKeyCreateDto] aPIKeyCreateDto (required): /// * [APIKeyCreateDto] aPIKeyCreateDto (required):
Future<APIKeyCreateResponseDto?> createKey(APIKeyCreateDto aPIKeyCreateDto,) async { Future<APIKeyCreateResponseDto?> createApiKey(APIKeyCreateDto aPIKeyCreateDto,) async {
final response = await createKeyWithHttpInfo(aPIKeyCreateDto,); final response = await createApiKeyWithHttpInfo(aPIKeyCreateDto,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -67,7 +67,7 @@ class APIKeyApi {
/// Parameters: /// Parameters:
/// ///
/// * [String] id (required): /// * [String] id (required):
Future<Response> deleteKeyWithHttpInfo(String id,) async { Future<Response> deleteApiKeyWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key/{id}' final path = r'/api-key/{id}'
.replaceAll('{id}', id); .replaceAll('{id}', id);
@@ -96,8 +96,8 @@ class APIKeyApi {
/// Parameters: /// Parameters:
/// ///
/// * [String] id (required): /// * [String] id (required):
Future<void> deleteKey(String id,) async { Future<void> deleteApiKey(String id,) async {
final response = await deleteKeyWithHttpInfo(id,); final response = await deleteApiKeyWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -107,7 +107,7 @@ class APIKeyApi {
/// Parameters: /// Parameters:
/// ///
/// * [String] id (required): /// * [String] id (required):
Future<Response> getKeyWithHttpInfo(String id,) async { Future<Response> getApiKeyWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key/{id}' final path = r'/api-key/{id}'
.replaceAll('{id}', id); .replaceAll('{id}', id);
@@ -136,8 +136,8 @@ class APIKeyApi {
/// Parameters: /// Parameters:
/// ///
/// * [String] id (required): /// * [String] id (required):
Future<APIKeyResponseDto?> getKey(String id,) async { Future<APIKeyResponseDto?> getApiKey(String id,) async {
final response = await getKeyWithHttpInfo(id,); final response = await getApiKeyWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -152,7 +152,7 @@ class APIKeyApi {
} }
/// Performs an HTTP 'GET /api-key' operation and returns the [Response]. /// Performs an HTTP 'GET /api-key' operation and returns the [Response].
Future<Response> getKeysWithHttpInfo() async { Future<Response> getApiKeysWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key'; final path = r'/api-key';
@@ -177,8 +177,8 @@ class APIKeyApi {
); );
} }
Future<List<APIKeyResponseDto>?> getKeys() async { Future<List<APIKeyResponseDto>?> getApiKeys() async {
final response = await getKeysWithHttpInfo(); final response = await getApiKeysWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -201,7 +201,7 @@ class APIKeyApi {
/// * [String] id (required): /// * [String] id (required):
/// ///
/// * [APIKeyUpdateDto] aPIKeyUpdateDto (required): /// * [APIKeyUpdateDto] aPIKeyUpdateDto (required):
Future<Response> updateKeyWithHttpInfo(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async { Future<Response> updateApiKeyWithHttpInfo(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/api-key/{id}' final path = r'/api-key/{id}'
.replaceAll('{id}', id); .replaceAll('{id}', id);
@@ -232,8 +232,8 @@ class APIKeyApi {
/// * [String] id (required): /// * [String] id (required):
/// ///
/// * [APIKeyUpdateDto] aPIKeyUpdateDto (required): /// * [APIKeyUpdateDto] aPIKeyUpdateDto (required):
Future<APIKeyResponseDto?> updateKey(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async { Future<APIKeyResponseDto?> updateApiKey(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async {
final response = await updateKeyWithHttpInfo(id, aPIKeyUpdateDto,); final response = await updateApiKeyWithHttpInfo(id, aPIKeyUpdateDto,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }

View File

@@ -23,7 +23,7 @@ class AssetApi {
/// Parameters: /// Parameters:
/// ///
/// * [AssetBulkUploadCheckDto] assetBulkUploadCheckDto (required): /// * [AssetBulkUploadCheckDto] assetBulkUploadCheckDto (required):
Future<Response> bulkUploadCheckWithHttpInfo(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async { Future<Response> checkBulkUploadWithHttpInfo(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/asset/bulk-upload-check'; final path = r'/asset/bulk-upload-check';
@@ -53,8 +53,8 @@ class AssetApi {
/// Parameters: /// Parameters:
/// ///
/// * [AssetBulkUploadCheckDto] assetBulkUploadCheckDto (required): /// * [AssetBulkUploadCheckDto] assetBulkUploadCheckDto (required):
Future<AssetBulkUploadCheckResponseDto?> bulkUploadCheck(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async { Future<AssetBulkUploadCheckResponseDto?> checkBulkUpload(AssetBulkUploadCheckDto assetBulkUploadCheckDto,) async {
final response = await bulkUploadCheckWithHttpInfo(assetBulkUploadCheckDto,); final response = await checkBulkUploadWithHttpInfo(assetBulkUploadCheckDto,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -309,19 +309,23 @@ class AssetApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [int] skip:
///
/// * [int] take:
///
/// * [String] userId: /// * [String] userId:
/// ///
/// * [bool] isFavorite: /// * [bool] isFavorite:
/// ///
/// * [bool] isArchived: /// * [bool] isArchived:
/// ///
/// * [num] skip:
///
/// * [DateTime] updatedAfter: /// * [DateTime] updatedAfter:
/// ///
/// * [DateTime] updatedBefore:
///
/// * [String] ifNoneMatch: /// * [String] ifNoneMatch:
/// ETag of data already cached on the client /// ETag of data already cached on the client
Future<Response> getAllAssetsWithHttpInfo({ String? userId, bool? isFavorite, bool? isArchived, num? skip, DateTime? updatedAfter, String? ifNoneMatch, }) async { Future<Response> getAllAssetsWithHttpInfo({ int? skip, int? take, String? userId, bool? isFavorite, bool? isArchived, DateTime? updatedAfter, DateTime? updatedBefore, String? ifNoneMatch, }) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/asset'; final path = r'/asset';
@@ -332,6 +336,12 @@ class AssetApi {
final headerParams = <String, String>{}; final headerParams = <String, String>{};
final formParams = <String, String>{}; final formParams = <String, String>{};
if (skip != null) {
queryParams.addAll(_queryParams('', 'skip', skip));
}
if (take != null) {
queryParams.addAll(_queryParams('', 'take', take));
}
if (userId != null) { if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId)); queryParams.addAll(_queryParams('', 'userId', userId));
} }
@@ -341,12 +351,12 @@ class AssetApi {
if (isArchived != null) { if (isArchived != null) {
queryParams.addAll(_queryParams('', 'isArchived', isArchived)); queryParams.addAll(_queryParams('', 'isArchived', isArchived));
} }
if (skip != null) {
queryParams.addAll(_queryParams('', 'skip', skip));
}
if (updatedAfter != null) { if (updatedAfter != null) {
queryParams.addAll(_queryParams('', 'updatedAfter', updatedAfter)); queryParams.addAll(_queryParams('', 'updatedAfter', updatedAfter));
} }
if (updatedBefore != null) {
queryParams.addAll(_queryParams('', 'updatedBefore', updatedBefore));
}
if (ifNoneMatch != null) { if (ifNoneMatch != null) {
headerParams[r'if-none-match'] = parameterToString(ifNoneMatch); headerParams[r'if-none-match'] = parameterToString(ifNoneMatch);
@@ -370,20 +380,24 @@ class AssetApi {
/// ///
/// Parameters: /// Parameters:
/// ///
/// * [int] skip:
///
/// * [int] take:
///
/// * [String] userId: /// * [String] userId:
/// ///
/// * [bool] isFavorite: /// * [bool] isFavorite:
/// ///
/// * [bool] isArchived: /// * [bool] isArchived:
/// ///
/// * [num] skip:
///
/// * [DateTime] updatedAfter: /// * [DateTime] updatedAfter:
/// ///
/// * [DateTime] updatedBefore:
///
/// * [String] ifNoneMatch: /// * [String] ifNoneMatch:
/// ETag of data already cached on the client /// ETag of data already cached on the client
Future<List<AssetResponseDto>?> getAllAssets({ String? userId, bool? isFavorite, bool? isArchived, num? skip, DateTime? updatedAfter, String? ifNoneMatch, }) async { Future<List<AssetResponseDto>?> getAllAssets({ int? skip, int? take, String? userId, bool? isFavorite, bool? isArchived, DateTime? updatedAfter, DateTime? updatedBefore, String? ifNoneMatch, }) async {
final response = await getAllAssetsWithHttpInfo( userId: userId, isFavorite: isFavorite, isArchived: isArchived, skip: skip, updatedAfter: updatedAfter, ifNoneMatch: ifNoneMatch, ); final response = await getAllAssetsWithHttpInfo( skip: skip, take: take, userId: userId, isFavorite: isFavorite, isArchived: isArchived, updatedAfter: updatedAfter, updatedBefore: updatedBefore, ifNoneMatch: ifNoneMatch, );
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -513,7 +527,7 @@ class AssetApi {
/// * [bool] isFavorite: /// * [bool] isFavorite:
/// ///
/// * [bool] isTrashed: /// * [bool] isTrashed:
Future<Response> getAssetStatsWithHttpInfo({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async { Future<Response> getAssetStatisticsWithHttpInfo({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/asset/statistics'; final path = r'/asset/statistics';
@@ -555,8 +569,8 @@ class AssetApi {
/// * [bool] isFavorite: /// * [bool] isFavorite:
/// ///
/// * [bool] isTrashed: /// * [bool] isTrashed:
Future<AssetStatsResponseDto?> getAssetStats({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async { Future<AssetStatsResponseDto?> getAssetStatistics({ bool? isArchived, bool? isFavorite, bool? isTrashed, }) async {
final response = await getAssetStatsWithHttpInfo( isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, ); final response = await getAssetStatisticsWithHttpInfo( isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, );
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -633,119 +647,6 @@ class AssetApi {
return null; return null;
} }
/// Performs an HTTP 'GET /asset/time-bucket' operation and returns the [Response].
/// Parameters:
///
/// * [TimeBucketSize] size (required):
///
/// * [String] timeBucket (required):
///
/// * [String] userId:
///
/// * [String] albumId:
///
/// * [String] personId:
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
///
/// * [bool] isTrashed:
///
/// * [bool] withStacked:
///
/// * [String] key:
Future<Response> getByTimeBucketWithHttpInfo(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/time-bucket';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
queryParams.addAll(_queryParams('', 'size', size));
if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId));
}
if (albumId != null) {
queryParams.addAll(_queryParams('', 'albumId', albumId));
}
if (personId != null) {
queryParams.addAll(_queryParams('', 'personId', personId));
}
if (isArchived != null) {
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
}
if (isFavorite != null) {
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
}
if (isTrashed != null) {
queryParams.addAll(_queryParams('', 'isTrashed', isTrashed));
}
if (withStacked != null) {
queryParams.addAll(_queryParams('', 'withStacked', withStacked));
}
queryParams.addAll(_queryParams('', 'timeBucket', timeBucket));
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [TimeBucketSize] size (required):
///
/// * [String] timeBucket (required):
///
/// * [String] userId:
///
/// * [String] albumId:
///
/// * [String] personId:
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
///
/// * [bool] isTrashed:
///
/// * [bool] withStacked:
///
/// * [String] key:
Future<List<AssetResponseDto>?> getByTimeBucket(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async {
final response = await getByTimeBucketWithHttpInfo(size, timeBucket, userId: userId, albumId: albumId, personId: personId, isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, withStacked: withStacked, key: key, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<AssetResponseDto>') as List)
.cast<AssetResponseDto>()
.toList();
}
return null;
}
/// Performs an HTTP 'GET /asset/curated-locations' operation and returns the [Response]. /// Performs an HTTP 'GET /asset/curated-locations' operation and returns the [Response].
Future<Response> getCuratedLocationsWithHttpInfo() async { Future<Response> getCuratedLocationsWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
@@ -1075,6 +976,119 @@ class AssetApi {
return null; return null;
} }
/// Performs an HTTP 'GET /asset/time-bucket' operation and returns the [Response].
/// Parameters:
///
/// * [TimeBucketSize] size (required):
///
/// * [String] timeBucket (required):
///
/// * [String] userId:
///
/// * [String] albumId:
///
/// * [String] personId:
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
///
/// * [bool] isTrashed:
///
/// * [bool] withStacked:
///
/// * [String] key:
Future<Response> getTimeBucketWithHttpInfo(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/time-bucket';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
queryParams.addAll(_queryParams('', 'size', size));
if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId));
}
if (albumId != null) {
queryParams.addAll(_queryParams('', 'albumId', albumId));
}
if (personId != null) {
queryParams.addAll(_queryParams('', 'personId', personId));
}
if (isArchived != null) {
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
}
if (isFavorite != null) {
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
}
if (isTrashed != null) {
queryParams.addAll(_queryParams('', 'isTrashed', isTrashed));
}
if (withStacked != null) {
queryParams.addAll(_queryParams('', 'withStacked', withStacked));
}
queryParams.addAll(_queryParams('', 'timeBucket', timeBucket));
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [TimeBucketSize] size (required):
///
/// * [String] timeBucket (required):
///
/// * [String] userId:
///
/// * [String] albumId:
///
/// * [String] personId:
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
///
/// * [bool] isTrashed:
///
/// * [bool] withStacked:
///
/// * [String] key:
Future<List<AssetResponseDto>?> getTimeBucket(TimeBucketSize size, String timeBucket, { String? userId, String? albumId, String? personId, bool? isArchived, bool? isFavorite, bool? isTrashed, bool? withStacked, String? key, }) async {
final response = await getTimeBucketWithHttpInfo(size, timeBucket, userId: userId, albumId: albumId, personId: personId, isArchived: isArchived, isFavorite: isFavorite, isTrashed: isTrashed, withStacked: withStacked, key: key, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<AssetResponseDto>') as List)
.cast<AssetResponseDto>()
.toList();
}
return null;
}
/// Performs an HTTP 'GET /asset/time-buckets' operation and returns the [Response]. /// Performs an HTTP 'GET /asset/time-buckets' operation and returns the [Response].
/// Parameters: /// Parameters:
/// ///
@@ -1660,8 +1674,6 @@ class AssetApi {
/// ///
/// * [DateTime] fileModifiedAt (required): /// * [DateTime] fileModifiedAt (required):
/// ///
/// * [bool] isFavorite (required):
///
/// * [String] key: /// * [String] key:
/// ///
/// * [String] duration: /// * [String] duration:
@@ -1670,6 +1682,8 @@ class AssetApi {
/// ///
/// * [bool] isExternal: /// * [bool] isExternal:
/// ///
/// * [bool] isFavorite:
///
/// * [bool] isOffline: /// * [bool] isOffline:
/// ///
/// * [bool] isReadOnly: /// * [bool] isReadOnly:
@@ -1681,7 +1695,7 @@ class AssetApi {
/// * [MultipartFile] livePhotoData: /// * [MultipartFile] livePhotoData:
/// ///
/// * [MultipartFile] sidecarData: /// * [MultipartFile] sidecarData:
Future<Response> uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, String? duration, bool? isArchived, bool? isExternal, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async { Future<Response> uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, bool? isArchived, bool? isExternal, bool? isFavorite, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/asset/upload'; final path = r'/asset/upload';
@@ -1790,8 +1804,6 @@ class AssetApi {
/// ///
/// * [DateTime] fileModifiedAt (required): /// * [DateTime] fileModifiedAt (required):
/// ///
/// * [bool] isFavorite (required):
///
/// * [String] key: /// * [String] key:
/// ///
/// * [String] duration: /// * [String] duration:
@@ -1800,6 +1812,8 @@ class AssetApi {
/// ///
/// * [bool] isExternal: /// * [bool] isExternal:
/// ///
/// * [bool] isFavorite:
///
/// * [bool] isOffline: /// * [bool] isOffline:
/// ///
/// * [bool] isReadOnly: /// * [bool] isReadOnly:
@@ -1811,8 +1825,8 @@ class AssetApi {
/// * [MultipartFile] livePhotoData: /// * [MultipartFile] livePhotoData:
/// ///
/// * [MultipartFile] sidecarData: /// * [MultipartFile] sidecarData:
Future<AssetFileUploadResponseDto?> uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, String? duration, bool? isArchived, bool? isExternal, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async { Future<AssetFileUploadResponseDto?> uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, bool? isArchived, bool? isExternal, bool? isFavorite, bool? isOffline, bool? isReadOnly, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async {
final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key: key, duration: duration, isArchived: isArchived, isExternal: isExternal, isOffline: isOffline, isReadOnly: isReadOnly, isVisible: isVisible, libraryId: libraryId, livePhotoData: livePhotoData, sidecarData: sidecarData, ); final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, duration: duration, isArchived: isArchived, isExternal: isExternal, isFavorite: isFavorite, isOffline: isOffline, isReadOnly: isReadOnly, isVisible: isVisible, libraryId: libraryId, livePhotoData: livePhotoData, sidecarData: sidecarData, );
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }

View File

@@ -16,53 +16,6 @@ class AuthenticationApi {
final ApiClient apiClient; final ApiClient apiClient;
/// Performs an HTTP 'POST /auth/admin-sign-up' operation and returns the [Response].
/// Parameters:
///
/// * [SignUpDto] signUpDto (required):
Future<Response> adminSignUpWithHttpInfo(SignUpDto signUpDto,) async {
// ignore: prefer_const_declarations
final path = r'/auth/admin-sign-up';
// ignore: prefer_final_locals
Object? postBody = signUpDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [SignUpDto] signUpDto (required):
Future<AdminSignupResponseDto?> adminSignUp(SignUpDto signUpDto,) async {
final response = await adminSignUpWithHttpInfo(signUpDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AdminSignupResponseDto',) as AdminSignupResponseDto;
}
return null;
}
/// Performs an HTTP 'POST /auth/change-password' operation and returns the [Response]. /// Performs an HTTP 'POST /auth/change-password' operation and returns the [Response].
/// Parameters: /// Parameters:
/// ///
@@ -315,6 +268,53 @@ class AuthenticationApi {
} }
} }
/// Performs an HTTP 'POST /auth/admin-sign-up' operation and returns the [Response].
/// Parameters:
///
/// * [SignUpDto] signUpDto (required):
Future<Response> signUpAdminWithHttpInfo(SignUpDto signUpDto,) async {
// ignore: prefer_const_declarations
final path = r'/auth/admin-sign-up';
// ignore: prefer_final_locals
Object? postBody = signUpDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [SignUpDto] signUpDto (required):
Future<AdminSignupResponseDto?> signUpAdmin(SignUpDto signUpDto,) async {
final response = await signUpAdminWithHttpInfo(signUpDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AdminSignupResponseDto',) as AdminSignupResponseDto;
}
return null;
}
/// Performs an HTTP 'POST /auth/validateToken' operation and returns the [Response]. /// Performs an HTTP 'POST /auth/validateToken' operation and returns the [Response].
Future<Response> validateAccessTokenWithHttpInfo() async { Future<Response> validateAccessTokenWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations

View File

@@ -104,7 +104,7 @@ class LibraryApi {
} }
/// Performs an HTTP 'GET /library' operation and returns the [Response]. /// Performs an HTTP 'GET /library' operation and returns the [Response].
Future<Response> getAllForUserWithHttpInfo() async { Future<Response> getLibrariesWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/library'; final path = r'/library';
@@ -129,8 +129,8 @@ class LibraryApi {
); );
} }
Future<List<LibraryResponseDto>?> getAllForUser() async { Future<List<LibraryResponseDto>?> getLibraries() async {
final response = await getAllForUserWithHttpInfo(); final response = await getLibrariesWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }

View File

@@ -16,58 +16,11 @@ class OAuthApi {
final ApiClient apiClient; final ApiClient apiClient;
/// Performs an HTTP 'POST /oauth/authorize' operation and returns the [Response].
/// Parameters:
///
/// * [OAuthConfigDto] oAuthConfigDto (required):
Future<Response> authorizeOAuthWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async {
// ignore: prefer_const_declarations
final path = r'/oauth/authorize';
// ignore: prefer_final_locals
Object? postBody = oAuthConfigDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [OAuthConfigDto] oAuthConfigDto (required):
Future<OAuthAuthorizeResponseDto?> authorizeOAuth(OAuthConfigDto oAuthConfigDto,) async {
final response = await authorizeOAuthWithHttpInfo(oAuthConfigDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'OAuthAuthorizeResponseDto',) as OAuthAuthorizeResponseDto;
}
return null;
}
/// Performs an HTTP 'POST /oauth/callback' operation and returns the [Response]. /// Performs an HTTP 'POST /oauth/callback' operation and returns the [Response].
/// Parameters: /// Parameters:
/// ///
/// * [OAuthCallbackDto] oAuthCallbackDto (required): /// * [OAuthCallbackDto] oAuthCallbackDto (required):
Future<Response> callbackWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async { Future<Response> finishOAuthWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/oauth/callback'; final path = r'/oauth/callback';
@@ -95,8 +48,8 @@ class OAuthApi {
/// Parameters: /// Parameters:
/// ///
/// * [OAuthCallbackDto] oAuthCallbackDto (required): /// * [OAuthCallbackDto] oAuthCallbackDto (required):
Future<LoginResponseDto?> callback(OAuthCallbackDto oAuthCallbackDto,) async { Future<LoginResponseDto?> finishOAuth(OAuthCallbackDto oAuthCallbackDto,) async {
final response = await callbackWithHttpInfo(oAuthCallbackDto,); final response = await finishOAuthWithHttpInfo(oAuthCallbackDto,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -117,7 +70,7 @@ class OAuthApi {
/// Parameters: /// Parameters:
/// ///
/// * [OAuthConfigDto] oAuthConfigDto (required): /// * [OAuthConfigDto] oAuthConfigDto (required):
Future<Response> generateConfigWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async { Future<Response> generateOAuthConfigWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/oauth/config'; final path = r'/oauth/config';
@@ -147,8 +100,8 @@ class OAuthApi {
/// Parameters: /// Parameters:
/// ///
/// * [OAuthConfigDto] oAuthConfigDto (required): /// * [OAuthConfigDto] oAuthConfigDto (required):
Future<OAuthConfigResponseDto?> generateConfig(OAuthConfigDto oAuthConfigDto,) async { Future<OAuthConfigResponseDto?> generateOAuthConfig(OAuthConfigDto oAuthConfigDto,) async {
final response = await generateConfigWithHttpInfo(oAuthConfigDto,); final response = await generateOAuthConfigWithHttpInfo(oAuthConfigDto,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -166,7 +119,7 @@ class OAuthApi {
/// Parameters: /// Parameters:
/// ///
/// * [OAuthCallbackDto] oAuthCallbackDto (required): /// * [OAuthCallbackDto] oAuthCallbackDto (required):
Future<Response> linkWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async { Future<Response> linkOAuthAccountWithHttpInfo(OAuthCallbackDto oAuthCallbackDto,) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/oauth/link'; final path = r'/oauth/link';
@@ -194,8 +147,8 @@ class OAuthApi {
/// Parameters: /// Parameters:
/// ///
/// * [OAuthCallbackDto] oAuthCallbackDto (required): /// * [OAuthCallbackDto] oAuthCallbackDto (required):
Future<UserResponseDto?> link(OAuthCallbackDto oAuthCallbackDto,) async { Future<UserResponseDto?> linkOAuthAccount(OAuthCallbackDto oAuthCallbackDto,) async {
final response = await linkWithHttpInfo(oAuthCallbackDto,); final response = await linkOAuthAccountWithHttpInfo(oAuthCallbackDto,);
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
@@ -210,7 +163,7 @@ class OAuthApi {
} }
/// Performs an HTTP 'GET /oauth/mobile-redirect' operation and returns the [Response]. /// Performs an HTTP 'GET /oauth/mobile-redirect' operation and returns the [Response].
Future<Response> mobileRedirectWithHttpInfo() async { Future<Response> redirectOAuthToMobileWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/oauth/mobile-redirect'; final path = r'/oauth/mobile-redirect';
@@ -235,15 +188,62 @@ class OAuthApi {
); );
} }
Future<void> mobileRedirect() async { Future<void> redirectOAuthToMobile() async {
final response = await mobileRedirectWithHttpInfo(); final response = await redirectOAuthToMobileWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
} }
/// Performs an HTTP 'POST /oauth/authorize' operation and returns the [Response].
/// Parameters:
///
/// * [OAuthConfigDto] oAuthConfigDto (required):
Future<Response> startOAuthWithHttpInfo(OAuthConfigDto oAuthConfigDto,) async {
// ignore: prefer_const_declarations
final path = r'/oauth/authorize';
// ignore: prefer_final_locals
Object? postBody = oAuthConfigDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [OAuthConfigDto] oAuthConfigDto (required):
Future<OAuthAuthorizeResponseDto?> startOAuth(OAuthConfigDto oAuthConfigDto,) async {
final response = await startOAuthWithHttpInfo(oAuthConfigDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'OAuthAuthorizeResponseDto',) as OAuthAuthorizeResponseDto;
}
return null;
}
/// Performs an HTTP 'POST /oauth/unlink' operation and returns the [Response]. /// Performs an HTTP 'POST /oauth/unlink' operation and returns the [Response].
Future<Response> unlinkWithHttpInfo() async { Future<Response> unlinkOAuthAccountWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/oauth/unlink'; final path = r'/oauth/unlink';
@@ -268,8 +268,8 @@ class OAuthApi {
); );
} }
Future<UserResponseDto?> unlink() async { Future<UserResponseDto?> unlinkOAuthAccount() async {
final response = await unlinkWithHttpInfo(); final response = await unlinkOAuthAccountWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }

View File

@@ -139,6 +139,47 @@ class ServerInfoApi {
return null; return null;
} }
/// Performs an HTTP 'GET /server-info/statistics' operation and returns the [Response].
Future<Response> getServerStatisticsWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/server-info/statistics';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<ServerStatsResponseDto?> getServerStatistics() async {
final response = await getServerStatisticsWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerStatsResponseDto',) as ServerStatsResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /server-info/version' operation and returns the [Response]. /// Performs an HTTP 'GET /server-info/version' operation and returns the [Response].
Future<Response> getServerVersionWithHttpInfo() async { Future<Response> getServerVersionWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
@@ -180,47 +221,6 @@ class ServerInfoApi {
return null; return null;
} }
/// Performs an HTTP 'GET /server-info/stats' operation and returns the [Response].
Future<Response> getStatsWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/server-info/stats';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<ServerStatsResponseDto?> getStats() async {
final response = await getStatsWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerStatsResponseDto',) as ServerStatsResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /server-info/media-types' operation and returns the [Response]. /// Performs an HTTP 'GET /server-info/media-types' operation and returns the [Response].
Future<Response> getSupportedMediaTypesWithHttpInfo() async { Future<Response> getSupportedMediaTypesWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations

View File

@@ -58,7 +58,7 @@ class SystemConfigApi {
} }
/// Performs an HTTP 'GET /system-config/defaults' operation and returns the [Response]. /// Performs an HTTP 'GET /system-config/defaults' operation and returns the [Response].
Future<Response> getDefaultsWithHttpInfo() async { Future<Response> getConfigDefaultsWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/system-config/defaults'; final path = r'/system-config/defaults';
@@ -83,8 +83,8 @@ class SystemConfigApi {
); );
} }
Future<SystemConfigDto?> getDefaults() async { Future<SystemConfigDto?> getConfigDefaults() async {
final response = await getDefaultsWithHttpInfo(); final response = await getConfigDefaultsWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }

View File

@@ -22,6 +22,7 @@ class AlbumResponseDto {
this.endDate, this.endDate,
required this.hasSharedLink, required this.hasSharedLink,
required this.id, required this.id,
required this.isActivityEnabled,
this.lastModifiedAssetTimestamp, this.lastModifiedAssetTimestamp,
required this.owner, required this.owner,
required this.ownerId, required this.ownerId,
@@ -55,6 +56,8 @@ class AlbumResponseDto {
String id; String id;
bool isActivityEnabled;
/// ///
/// Please note: This property should have been non-nullable! Since the specification file /// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated /// does not include a default value (using the "default:" property), however, the generated
@@ -92,6 +95,7 @@ class AlbumResponseDto {
other.endDate == endDate && other.endDate == endDate &&
other.hasSharedLink == hasSharedLink && other.hasSharedLink == hasSharedLink &&
other.id == id && other.id == id &&
other.isActivityEnabled == isActivityEnabled &&
other.lastModifiedAssetTimestamp == lastModifiedAssetTimestamp && other.lastModifiedAssetTimestamp == lastModifiedAssetTimestamp &&
other.owner == owner && other.owner == owner &&
other.ownerId == ownerId && other.ownerId == ownerId &&
@@ -112,6 +116,7 @@ class AlbumResponseDto {
(endDate == null ? 0 : endDate!.hashCode) + (endDate == null ? 0 : endDate!.hashCode) +
(hasSharedLink.hashCode) + (hasSharedLink.hashCode) +
(id.hashCode) + (id.hashCode) +
(isActivityEnabled.hashCode) +
(lastModifiedAssetTimestamp == null ? 0 : lastModifiedAssetTimestamp!.hashCode) + (lastModifiedAssetTimestamp == null ? 0 : lastModifiedAssetTimestamp!.hashCode) +
(owner.hashCode) + (owner.hashCode) +
(ownerId.hashCode) + (ownerId.hashCode) +
@@ -121,7 +126,7 @@ class AlbumResponseDto {
(updatedAt.hashCode); (updatedAt.hashCode);
@override @override
String toString() => 'AlbumResponseDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, assetCount=$assetCount, assets=$assets, createdAt=$createdAt, description=$description, endDate=$endDate, hasSharedLink=$hasSharedLink, id=$id, lastModifiedAssetTimestamp=$lastModifiedAssetTimestamp, owner=$owner, ownerId=$ownerId, shared=$shared, sharedUsers=$sharedUsers, startDate=$startDate, updatedAt=$updatedAt]'; String toString() => 'AlbumResponseDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, assetCount=$assetCount, assets=$assets, createdAt=$createdAt, description=$description, endDate=$endDate, hasSharedLink=$hasSharedLink, id=$id, isActivityEnabled=$isActivityEnabled, lastModifiedAssetTimestamp=$lastModifiedAssetTimestamp, owner=$owner, ownerId=$ownerId, shared=$shared, sharedUsers=$sharedUsers, startDate=$startDate, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -142,6 +147,7 @@ class AlbumResponseDto {
} }
json[r'hasSharedLink'] = this.hasSharedLink; json[r'hasSharedLink'] = this.hasSharedLink;
json[r'id'] = this.id; json[r'id'] = this.id;
json[r'isActivityEnabled'] = this.isActivityEnabled;
if (this.lastModifiedAssetTimestamp != null) { if (this.lastModifiedAssetTimestamp != null) {
json[r'lastModifiedAssetTimestamp'] = this.lastModifiedAssetTimestamp!.toUtc().toIso8601String(); json[r'lastModifiedAssetTimestamp'] = this.lastModifiedAssetTimestamp!.toUtc().toIso8601String();
} else { } else {
@@ -177,6 +183,7 @@ class AlbumResponseDto {
endDate: mapDateTime(json, r'endDate', ''), endDate: mapDateTime(json, r'endDate', ''),
hasSharedLink: mapValueOfType<bool>(json, r'hasSharedLink')!, hasSharedLink: mapValueOfType<bool>(json, r'hasSharedLink')!,
id: mapValueOfType<String>(json, r'id')!, id: mapValueOfType<String>(json, r'id')!,
isActivityEnabled: mapValueOfType<bool>(json, r'isActivityEnabled')!,
lastModifiedAssetTimestamp: mapDateTime(json, r'lastModifiedAssetTimestamp', ''), lastModifiedAssetTimestamp: mapDateTime(json, r'lastModifiedAssetTimestamp', ''),
owner: UserResponseDto.fromJson(json[r'owner'])!, owner: UserResponseDto.fromJson(json[r'owner'])!,
ownerId: mapValueOfType<String>(json, r'ownerId')!, ownerId: mapValueOfType<String>(json, r'ownerId')!,
@@ -239,6 +246,7 @@ class AlbumResponseDto {
'description', 'description',
'hasSharedLink', 'hasSharedLink',
'id', 'id',
'isActivityEnabled',
'owner', 'owner',
'ownerId', 'ownerId',
'shared', 'shared',

View File

@@ -21,7 +21,7 @@ class ImportAssetDto {
required this.fileModifiedAt, required this.fileModifiedAt,
this.isArchived, this.isArchived,
this.isExternal, this.isExternal,
required this.isFavorite, this.isFavorite,
this.isOffline, this.isOffline,
this.isReadOnly = true, this.isReadOnly = true,
this.isVisible, this.isVisible,
@@ -63,7 +63,13 @@ class ImportAssetDto {
/// ///
bool? isExternal; bool? isExternal;
bool isFavorite; ///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? isFavorite;
/// ///
/// Please note: This property should have been non-nullable! Since the specification file /// Please note: This property should have been non-nullable! Since the specification file
@@ -127,7 +133,7 @@ class ImportAssetDto {
(fileModifiedAt.hashCode) + (fileModifiedAt.hashCode) +
(isArchived == null ? 0 : isArchived!.hashCode) + (isArchived == null ? 0 : isArchived!.hashCode) +
(isExternal == null ? 0 : isExternal!.hashCode) + (isExternal == null ? 0 : isExternal!.hashCode) +
(isFavorite.hashCode) + (isFavorite == null ? 0 : isFavorite!.hashCode) +
(isOffline == null ? 0 : isOffline!.hashCode) + (isOffline == null ? 0 : isOffline!.hashCode) +
(isReadOnly.hashCode) + (isReadOnly.hashCode) +
(isVisible == null ? 0 : isVisible!.hashCode) + (isVisible == null ? 0 : isVisible!.hashCode) +
@@ -159,7 +165,11 @@ class ImportAssetDto {
} else { } else {
// json[r'isExternal'] = null; // json[r'isExternal'] = null;
} }
if (this.isFavorite != null) {
json[r'isFavorite'] = this.isFavorite; json[r'isFavorite'] = this.isFavorite;
} else {
// json[r'isFavorite'] = null;
}
if (this.isOffline != null) { if (this.isOffline != null) {
json[r'isOffline'] = this.isOffline; json[r'isOffline'] = this.isOffline;
} else { } else {
@@ -200,7 +210,7 @@ class ImportAssetDto {
fileModifiedAt: mapDateTime(json, r'fileModifiedAt', '')!, fileModifiedAt: mapDateTime(json, r'fileModifiedAt', '')!,
isArchived: mapValueOfType<bool>(json, r'isArchived'), isArchived: mapValueOfType<bool>(json, r'isArchived'),
isExternal: mapValueOfType<bool>(json, r'isExternal'), isExternal: mapValueOfType<bool>(json, r'isExternal'),
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!, isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
isOffline: mapValueOfType<bool>(json, r'isOffline'), isOffline: mapValueOfType<bool>(json, r'isOffline'),
isReadOnly: mapValueOfType<bool>(json, r'isReadOnly') ?? true, isReadOnly: mapValueOfType<bool>(json, r'isReadOnly') ?? true,
isVisible: mapValueOfType<bool>(json, r'isVisible'), isVisible: mapValueOfType<bool>(json, r'isVisible'),
@@ -258,7 +268,6 @@ class ImportAssetDto {
'deviceId', 'deviceId',
'fileCreatedAt', 'fileCreatedAt',
'fileModifiedAt', 'fileModifiedAt',
'isFavorite',
}; };
} }

View File

@@ -16,6 +16,7 @@ class UpdateAlbumDto {
this.albumName, this.albumName,
this.albumThumbnailAssetId, this.albumThumbnailAssetId,
this.description, this.description,
this.isActivityEnabled,
}); });
/// ///
@@ -42,21 +43,31 @@ class UpdateAlbumDto {
/// ///
String? description; String? description;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? isActivityEnabled;
@override @override
bool operator ==(Object other) => identical(this, other) || other is UpdateAlbumDto && bool operator ==(Object other) => identical(this, other) || other is UpdateAlbumDto &&
other.albumName == albumName && other.albumName == albumName &&
other.albumThumbnailAssetId == albumThumbnailAssetId && other.albumThumbnailAssetId == albumThumbnailAssetId &&
other.description == description; other.description == description &&
other.isActivityEnabled == isActivityEnabled;
@override @override
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(albumName == null ? 0 : albumName!.hashCode) + (albumName == null ? 0 : albumName!.hashCode) +
(albumThumbnailAssetId == null ? 0 : albumThumbnailAssetId!.hashCode) + (albumThumbnailAssetId == null ? 0 : albumThumbnailAssetId!.hashCode) +
(description == null ? 0 : description!.hashCode); (description == null ? 0 : description!.hashCode) +
(isActivityEnabled == null ? 0 : isActivityEnabled!.hashCode);
@override @override
String toString() => 'UpdateAlbumDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, description=$description]'; String toString() => 'UpdateAlbumDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, description=$description, isActivityEnabled=$isActivityEnabled]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -75,6 +86,11 @@ class UpdateAlbumDto {
} else { } else {
// json[r'description'] = null; // json[r'description'] = null;
} }
if (this.isActivityEnabled != null) {
json[r'isActivityEnabled'] = this.isActivityEnabled;
} else {
// json[r'isActivityEnabled'] = null;
}
return json; return json;
} }
@@ -89,6 +105,7 @@ class UpdateAlbumDto {
albumName: mapValueOfType<String>(json, r'albumName'), albumName: mapValueOfType<String>(json, r'albumName'),
albumThumbnailAssetId: mapValueOfType<String>(json, r'albumThumbnailAssetId'), albumThumbnailAssetId: mapValueOfType<String>(json, r'albumThumbnailAssetId'),
description: mapValueOfType<String>(json, r'description'), description: mapValueOfType<String>(json, r'description'),
isActivityEnabled: mapValueOfType<bool>(json, r'isActivityEnabled'),
); );
} }
return null; return null;

View File

@@ -61,6 +61,11 @@ void main() {
// TODO // TODO
}); });
// bool isActivityEnabled
test('to test the property `isActivityEnabled`', () async {
// TODO
});
// DateTime lastModifiedAssetTimestamp // DateTime lastModifiedAssetTimestamp
test('to test the property `lastModifiedAssetTimestamp`', () async { test('to test the property `lastModifiedAssetTimestamp`', () async {
// TODO // TODO

View File

@@ -17,28 +17,28 @@ void main() {
// final instance = APIKeyApi(); // final instance = APIKeyApi();
group('tests for APIKeyApi', () { group('tests for APIKeyApi', () {
//Future<APIKeyCreateResponseDto> createKey(APIKeyCreateDto aPIKeyCreateDto) async //Future<APIKeyCreateResponseDto> createApiKey(APIKeyCreateDto aPIKeyCreateDto) async
test('test createKey', () async { test('test createApiKey', () async {
// TODO // TODO
}); });
//Future deleteKey(String id) async //Future deleteApiKey(String id) async
test('test deleteKey', () async { test('test deleteApiKey', () async {
// TODO // TODO
}); });
//Future<APIKeyResponseDto> getKey(String id) async //Future<APIKeyResponseDto> getApiKey(String id) async
test('test getKey', () async { test('test getApiKey', () async {
// TODO // TODO
}); });
//Future<List<APIKeyResponseDto>> getKeys() async //Future<List<APIKeyResponseDto>> getApiKeys() async
test('test getKeys', () async { test('test getApiKeys', () async {
// TODO // TODO
}); });
//Future<APIKeyResponseDto> updateKey(String id, APIKeyUpdateDto aPIKeyUpdateDto) async //Future<APIKeyResponseDto> updateApiKey(String id, APIKeyUpdateDto aPIKeyUpdateDto) async
test('test updateKey', () async { test('test updateApiKey', () async {
// TODO // TODO
}); });

View File

@@ -19,8 +19,8 @@ void main() {
group('tests for AssetApi', () { group('tests for AssetApi', () {
// Checks if assets exist by checksums // Checks if assets exist by checksums
// //
//Future<AssetBulkUploadCheckResponseDto> bulkUploadCheck(AssetBulkUploadCheckDto assetBulkUploadCheckDto) async //Future<AssetBulkUploadCheckResponseDto> checkBulkUpload(AssetBulkUploadCheckDto assetBulkUploadCheckDto) async
test('test bulkUploadCheck', () async { test('test checkBulkUpload', () async {
// TODO // TODO
}); });
@@ -53,7 +53,7 @@ void main() {
// Get all AssetEntity belong to the user // Get all AssetEntity belong to the user
// //
//Future<List<AssetResponseDto>> getAllAssets({ String userId, bool isFavorite, bool isArchived, num skip, DateTime updatedAfter, String ifNoneMatch }) async //Future<List<AssetResponseDto>> getAllAssets({ int skip, int take, String userId, bool isFavorite, bool isArchived, DateTime updatedAfter, DateTime updatedBefore, String ifNoneMatch }) async
test('test getAllAssets', () async { test('test getAllAssets', () async {
// TODO // TODO
}); });
@@ -70,8 +70,8 @@ void main() {
// TODO // TODO
}); });
//Future<AssetStatsResponseDto> getAssetStats({ bool isArchived, bool isFavorite, bool isTrashed }) async //Future<AssetStatsResponseDto> getAssetStatistics({ bool isArchived, bool isFavorite, bool isTrashed }) async
test('test getAssetStats', () async { test('test getAssetStatistics', () async {
// TODO // TODO
}); });
@@ -80,11 +80,6 @@ void main() {
// TODO // TODO
}); });
//Future<List<AssetResponseDto>> getByTimeBucket(TimeBucketSize size, String timeBucket, { String userId, String albumId, String personId, bool isArchived, bool isFavorite, bool isTrashed, bool withStacked, String key }) async
test('test getByTimeBucket', () async {
// TODO
});
//Future<List<CuratedLocationsResponseDto>> getCuratedLocations() async //Future<List<CuratedLocationsResponseDto>> getCuratedLocations() async
test('test getCuratedLocations', () async { test('test getCuratedLocations', () async {
// TODO // TODO
@@ -115,6 +110,11 @@ void main() {
// TODO // TODO
}); });
//Future<List<AssetResponseDto>> getTimeBucket(TimeBucketSize size, String timeBucket, { String userId, String albumId, String personId, bool isArchived, bool isFavorite, bool isTrashed, bool withStacked, String key }) async
test('test getTimeBucket', () async {
// TODO
});
//Future<List<TimeBucketResponseDto>> getTimeBuckets(TimeBucketSize size, { String userId, String albumId, String personId, bool isArchived, bool isFavorite, bool isTrashed, bool withStacked, String key }) async //Future<List<TimeBucketResponseDto>> getTimeBuckets(TimeBucketSize size, { String userId, String albumId, String personId, bool isArchived, bool isFavorite, bool isTrashed, bool withStacked, String key }) async
test('test getTimeBuckets', () async { test('test getTimeBuckets', () async {
// TODO // TODO
@@ -172,7 +172,7 @@ void main() {
// TODO // TODO
}); });
//Future<AssetFileUploadResponseDto> uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String key, String duration, bool isArchived, bool isExternal, bool isOffline, bool isReadOnly, bool isVisible, String libraryId, MultipartFile livePhotoData, MultipartFile sidecarData }) async //Future<AssetFileUploadResponseDto> uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String key, String duration, bool isArchived, bool isExternal, bool isFavorite, bool isOffline, bool isReadOnly, bool isVisible, String libraryId, MultipartFile livePhotoData, MultipartFile sidecarData }) async
test('test uploadFile', () async { test('test uploadFile', () async {
// TODO // TODO
}); });

View File

@@ -17,11 +17,6 @@ void main() {
// final instance = AuthenticationApi(); // final instance = AuthenticationApi();
group('tests for AuthenticationApi', () { group('tests for AuthenticationApi', () {
//Future<AdminSignupResponseDto> adminSignUp(SignUpDto signUpDto) async
test('test adminSignUp', () async {
// TODO
});
//Future<UserResponseDto> changePassword(ChangePasswordDto changePasswordDto) async //Future<UserResponseDto> changePassword(ChangePasswordDto changePasswordDto) async
test('test changePassword', () async { test('test changePassword', () async {
// TODO // TODO
@@ -52,6 +47,11 @@ void main() {
// TODO // TODO
}); });
//Future<AdminSignupResponseDto> signUpAdmin(SignUpDto signUpDto) async
test('test signUpAdmin', () async {
// TODO
});
//Future<ValidateAccessTokenResponseDto> validateAccessToken() async //Future<ValidateAccessTokenResponseDto> validateAccessToken() async
test('test validateAccessToken', () async { test('test validateAccessToken', () async {
// TODO // TODO

View File

@@ -27,8 +27,8 @@ void main() {
// TODO // TODO
}); });
//Future<List<LibraryResponseDto>> getAllForUser() async //Future<List<LibraryResponseDto>> getLibraries() async
test('test getAllForUser', () async { test('test getLibraries', () async {
// TODO // TODO
}); });

View File

@@ -17,35 +17,35 @@ void main() {
// final instance = OAuthApi(); // final instance = OAuthApi();
group('tests for OAuthApi', () { group('tests for OAuthApi', () {
//Future<OAuthAuthorizeResponseDto> authorizeOAuth(OAuthConfigDto oAuthConfigDto) async //Future<LoginResponseDto> finishOAuth(OAuthCallbackDto oAuthCallbackDto) async
test('test authorizeOAuth', () async { test('test finishOAuth', () async {
// TODO
});
//Future<LoginResponseDto> callback(OAuthCallbackDto oAuthCallbackDto) async
test('test callback', () async {
// TODO // TODO
}); });
// @deprecated use feature flags and /oauth/authorize // @deprecated use feature flags and /oauth/authorize
// //
//Future<OAuthConfigResponseDto> generateConfig(OAuthConfigDto oAuthConfigDto) async //Future<OAuthConfigResponseDto> generateOAuthConfig(OAuthConfigDto oAuthConfigDto) async
test('test generateConfig', () async { test('test generateOAuthConfig', () async {
// TODO // TODO
}); });
//Future<UserResponseDto> link(OAuthCallbackDto oAuthCallbackDto) async //Future<UserResponseDto> linkOAuthAccount(OAuthCallbackDto oAuthCallbackDto) async
test('test link', () async { test('test linkOAuthAccount', () async {
// TODO // TODO
}); });
//Future mobileRedirect() async //Future redirectOAuthToMobile() async
test('test mobileRedirect', () async { test('test redirectOAuthToMobile', () async {
// TODO // TODO
}); });
//Future<UserResponseDto> unlink() async //Future<OAuthAuthorizeResponseDto> startOAuth(OAuthConfigDto oAuthConfigDto) async
test('test unlink', () async { test('test startOAuth', () async {
// TODO
});
//Future<UserResponseDto> unlinkOAuthAccount() async
test('test unlinkOAuthAccount', () async {
// TODO // TODO
}); });

View File

@@ -32,13 +32,13 @@ void main() {
// TODO // TODO
}); });
//Future<ServerVersionResponseDto> getServerVersion() async //Future<ServerStatsResponseDto> getServerStatistics() async
test('test getServerVersion', () async { test('test getServerStatistics', () async {
// TODO // TODO
}); });
//Future<ServerStatsResponseDto> getStats() async //Future<ServerVersionResponseDto> getServerVersion() async
test('test getStats', () async { test('test getServerVersion', () async {
// TODO // TODO
}); });

View File

@@ -22,8 +22,8 @@ void main() {
// TODO // TODO
}); });
//Future<SystemConfigDto> getDefaults() async //Future<SystemConfigDto> getConfigDefaults() async
test('test getDefaults', () async { test('test getConfigDefaults', () async {
// TODO // TODO
}); });

View File

@@ -31,6 +31,11 @@ void main() {
// TODO // TODO
}); });
// bool isActivityEnabled
test('to test the property `isActivityEnabled`', () async {
// TODO
});
}); });

View File

@@ -1401,7 +1401,7 @@ packages:
source: hosted source: hosted
version: "2.1.3" version: "2.1.3"
timezone: timezone:
dependency: transitive dependency: "direct main"
description: description:
name: timezone name: timezone
sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0"

View File

@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone description: Immich - selfhosted backup media file on mobile phone
publish_to: "none" publish_to: "none"
version: 1.84.0+108 version: 1.85.0+109
isar_version: &isar_version 3.1.0+1 isar_version: &isar_version 3.1.0+1
environment: environment:
@@ -52,6 +52,7 @@ dependencies:
crypto: ^3.0.3 # TODO remove once native crypto is used on iOS crypto: ^3.0.3 # TODO remove once native crypto is used on iOS
wakelock_plus: ^1.1.1 wakelock_plus: ^1.1.1
flutter_local_notifications: ^15.1.0+1 flutter_local_notifications: ^15.1.0+1
timezone: ^0.9.2
openapi: openapi:
path: openapi path: openapi

View File

@@ -678,7 +678,7 @@
}, },
"/api-key": { "/api-key": {
"get": { "get": {
"operationId": "getKeys", "operationId": "getApiKeys",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
@@ -711,7 +711,7 @@
] ]
}, },
"post": { "post": {
"operationId": "createKey", "operationId": "createApiKey",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
"content": { "content": {
@@ -753,7 +753,7 @@
}, },
"/api-key/{id}": { "/api-key/{id}": {
"delete": { "delete": {
"operationId": "deleteKey", "operationId": "deleteApiKey",
"parameters": [ "parameters": [
{ {
"name": "id", "name": "id",
@@ -786,7 +786,7 @@
] ]
}, },
"get": { "get": {
"operationId": "getKey", "operationId": "getApiKey",
"parameters": [ "parameters": [
{ {
"name": "id", "name": "id",
@@ -826,7 +826,7 @@
] ]
}, },
"put": { "put": {
"operationId": "updateKey", "operationId": "updateApiKey",
"parameters": [ "parameters": [
{ {
"name": "id", "name": "id",
@@ -914,6 +914,22 @@
"description": "Get all AssetEntity belong to the user", "description": "Get all AssetEntity belong to the user",
"operationId": "getAllAssets", "operationId": "getAllAssets",
"parameters": [ "parameters": [
{
"name": "skip",
"required": false,
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "take",
"required": false,
"in": "query",
"schema": {
"type": "integer"
}
},
{ {
"name": "userId", "name": "userId",
"required": false, "required": false,
@@ -940,15 +956,16 @@
} }
}, },
{ {
"name": "skip", "name": "updatedAfter",
"required": false, "required": false,
"in": "query", "in": "query",
"schema": { "schema": {
"type": "number" "format": "date-time",
"type": "string"
} }
}, },
{ {
"name": "updatedAfter", "name": "updatedBefore",
"required": false, "required": false,
"in": "query", "in": "query",
"schema": { "schema": {
@@ -1084,7 +1101,7 @@
"/asset/bulk-upload-check": { "/asset/bulk-upload-check": {
"post": { "post": {
"description": "Checks if assets exist by checksums", "description": "Checks if assets exist by checksums",
"operationId": "bulkUploadCheck", "operationId": "checkBulkUpload",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
"content": { "content": {
@@ -1855,7 +1872,7 @@
}, },
"/asset/statistics": { "/asset/statistics": {
"get": { "get": {
"operationId": "getAssetStats", "operationId": "getAssetStatistics",
"parameters": [ "parameters": [
{ {
"name": "isArchived", "name": "isArchived",
@@ -1977,7 +1994,7 @@
}, },
"/asset/time-bucket": { "/asset/time-bucket": {
"get": { "get": {
"operationId": "getByTimeBucket", "operationId": "getTimeBucket",
"parameters": [ "parameters": [
{ {
"name": "size", "name": "size",
@@ -2596,7 +2613,7 @@
}, },
"/auth/admin-sign-up": { "/auth/admin-sign-up": {
"post": { "post": {
"operationId": "adminSignUp", "operationId": "signUpAdmin",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
"content": { "content": {
@@ -2943,7 +2960,7 @@
}, },
"/library": { "/library": {
"get": { "get": {
"operationId": "getAllForUser", "operationId": "getLibraries",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
@@ -3265,7 +3282,7 @@
}, },
"/oauth/authorize": { "/oauth/authorize": {
"post": { "post": {
"operationId": "authorizeOAuth", "operationId": "startOAuth",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
"content": { "content": {
@@ -3296,7 +3313,7 @@
}, },
"/oauth/callback": { "/oauth/callback": {
"post": { "post": {
"operationId": "callback", "operationId": "finishOAuth",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
"content": { "content": {
@@ -3329,7 +3346,7 @@
"post": { "post": {
"deprecated": true, "deprecated": true,
"description": "@deprecated use feature flags and /oauth/authorize", "description": "@deprecated use feature flags and /oauth/authorize",
"operationId": "generateConfig", "operationId": "generateOAuthConfig",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
"content": { "content": {
@@ -3360,7 +3377,7 @@
}, },
"/oauth/link": { "/oauth/link": {
"post": { "post": {
"operationId": "link", "operationId": "linkOAuthAccount",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
"content": { "content": {
@@ -3402,7 +3419,7 @@
}, },
"/oauth/mobile-redirect": { "/oauth/mobile-redirect": {
"get": { "get": {
"operationId": "mobileRedirect", "operationId": "redirectOAuthToMobile",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
@@ -3416,7 +3433,7 @@
}, },
"/oauth/unlink": { "/oauth/unlink": {
"post": { "post": {
"operationId": "unlink", "operationId": "unlinkOAuthAccount",
"parameters": [], "parameters": [],
"responses": { "responses": {
"201": { "201": {
@@ -4307,9 +4324,9 @@
] ]
} }
}, },
"/server-info/stats": { "/server-info/statistics": {
"get": { "get": {
"operationId": "getStats", "operationId": "getServerStatistics",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
@@ -4837,7 +4854,7 @@
}, },
"/system-config/defaults": { "/system-config/defaults": {
"get": { "get": {
"operationId": "getDefaults", "operationId": "getConfigDefaults",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
@@ -5621,7 +5638,7 @@
"info": { "info": {
"title": "Immich", "title": "Immich",
"description": "Immich API", "description": "Immich API",
"version": "1.84.0", "version": "1.85.0",
"contact": {} "contact": {}
}, },
"tags": [], "tags": [],
@@ -5877,6 +5894,9 @@
"id": { "id": {
"type": "string" "type": "string"
}, },
"isActivityEnabled": {
"type": "boolean"
},
"lastModifiedAssetTimestamp": { "lastModifiedAssetTimestamp": {
"format": "date-time", "format": "date-time",
"type": "string" "type": "string"
@@ -5918,7 +5938,8 @@
"sharedUsers", "sharedUsers",
"hasSharedLink", "hasSharedLink",
"assets", "assets",
"owner" "owner",
"isActivityEnabled"
], ],
"type": "object" "type": "object"
}, },
@@ -6655,8 +6676,7 @@
"deviceAssetId", "deviceAssetId",
"deviceId", "deviceId",
"fileCreatedAt", "fileCreatedAt",
"fileModifiedAt", "fileModifiedAt"
"isFavorite"
], ],
"type": "object" "type": "object"
}, },
@@ -7143,8 +7163,7 @@
"deviceAssetId", "deviceAssetId",
"deviceId", "deviceId",
"fileCreatedAt", "fileCreatedAt",
"fileModifiedAt", "fileModifiedAt"
"isFavorite"
], ],
"type": "object" "type": "object"
}, },
@@ -8895,6 +8914,9 @@
}, },
"description": { "description": {
"type": "string" "type": "string"
},
"isActivityEnabled": {
"type": "boolean"
} }
}, },
"type": "object" "type": "object"

View File

@@ -1,12 +1,12 @@
{ {
"name": "immich", "name": "immich",
"version": "1.84.0", "version": "1.85.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "immich", "name": "immich",
"version": "1.84.0", "version": "1.85.0",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.22.11", "@babel/runtime": "^7.22.11",

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