diff --git a/.vscode/settings.json b/.vscode/settings.json
index 49dbf3944c..b6da258a80 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -20,10 +20,7 @@
"editor.tabSize": 2
},
"svelte.enable-ts-plugin": true,
- "eslint.validate": [
- "javascript",
- "svelte"
- ],
+ "eslint.validate": ["javascript", "svelte"],
"typescript.preferences.importModuleSpecifier": "non-relative",
"[dart]": {
"editor.formatOnSave": true,
diff --git a/mobile-v2/.gitignore b/mobile-v2/.gitignore
new file mode 100644
index 0000000000..4e51a5b910
--- /dev/null
+++ b/mobile-v2/.gitignore
@@ -0,0 +1,48 @@
+# Generated
+*.g.dart
+*.gr.dart
+*.drift.dart
+
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/mobile-v2/.metadata b/mobile-v2/.metadata
new file mode 100644
index 0000000000..d02048cb75
--- /dev/null
+++ b/mobile-v2/.metadata
@@ -0,0 +1,33 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "300451adae589accbece3490f4396f10bdf15e6e"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 300451adae589accbece3490f4396f10bdf15e6e
+ base_revision: 300451adae589accbece3490f4396f10bdf15e6e
+ - platform: android
+ create_revision: 300451adae589accbece3490f4396f10bdf15e6e
+ base_revision: 300451adae589accbece3490f4396f10bdf15e6e
+ - platform: ios
+ create_revision: 300451adae589accbece3490f4396f10bdf15e6e
+ base_revision: 300451adae589accbece3490f4396f10bdf15e6e
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - "lib/main.dart"
+ - "ios/Runner.xcodeproj/project.pbxproj"
diff --git a/mobile-v2/README.md b/mobile-v2/README.md
new file mode 100644
index 0000000000..4f7e28f3d8
--- /dev/null
+++ b/mobile-v2/README.md
@@ -0,0 +1,55 @@
+# Immich Mobile Application - Flutter
+
+The Immich mobile app is a Flutter-based solution leveraging the Isar Database for local storage and Riverpod for state management. This structure optimizes functionality and maintainability, allowing for efficient development and robust performance.
+
+## Setup
+
+You must set up Flutter toolchain in your machine before you can perform any of the development.
+
+## Immich-Flutter Directory Structure
+
+Below are the directory inside the `lib` directory:
+
+- `constants`: Store essential constants utilized across the application, like colors and locale.
+
+- `extensions`: Extensions enhancing various existing functionalities within the app, such as asset_extensions.dart, string_extensions.dart, and more.
+
+- `module_template`: Provides a template structure for different modules within the app, including subdivisions like models, providers, services, UI, and views.
+
+ - `models`: Placeholder for storing module-specific models.
+ - `providers`: Section to define module-specific Riverpod providers.
+ - `services`: Houses services tailored to the module's functionality.
+ - `ui`: Contains UI components and widgets for the module.
+ - `views`: Placeholder for module-specific views.
+
+- `modules`: Organizes different functional modules of the app, each containing subdivisions for models, providers, services, UI, and views. This structure promotes modular development and scalability.
+
+- `routing`: Includes guards like auth_guard.dart, backup_permission_guard.dart, and routers like router.dart and router.gr.dart for streamlined navigation and permission management.
+
+- `shared`: cache, models, providers, services, ui, views: Encapsulates shared functionalities, such as caching mechanisms, common models, providers, services, UI components, and views accessible across the application.
+
+- `utils`: A collection of utility classes and functions catering to different app functionalities, including async_mutex.dart, bytes_units.dart, debounce.dart, migration.dart, and more.
+
+## Immich Architectural Pattern
+
+The Immich Flutter app embraces a well-defined architectural pattern inspired by the Model-View-ViewModel (MVVM) approach. This layout organizes modules for models, providers, services, UI, and views, creating a modular development approach that strongly emphasizes a clean separation of concerns.
+
+Please use the `module_template` provided to create a new module.
+
+### Architecture Breakdown
+
+Below is how your code needs to be structured:
+
+- Models: In Immich, Models are like the app's blueprint—they're essential for organizing and using information. Imagine them as containers that hold data the app needs to function. They also handle basic rules and logic for managing and interacting with this data across the app.
+
+- Providers (Riverpod): Providers in Immich are a bit like traffic managers. They help different parts of the app communicate and share information effectively. They ensure that the right data gets to the right places at the right time. These providers use Riverpod, a tool that helps with managing and organizing how the app's information flows. Everything related to the state goes here.
+
+- Services: Services are the helpful behind-the-scenes workers in Immich. They handle important tasks like handling network requests or managing other essential functions. These services work independently and focus on supporting the app's main functionalities.
+
+- UI: In Immich, the UI focuses solely on how things appear and feel without worrying about the app's complex inner workings. You can slot in your reusable widget here.
+
+- Views: Views use Providers to get the needed information and handle actions without dealing with the technical complexities behind the scenes. Normally Flutter's screen & pages goes here.
+
+## Contributing
+
+Please refer to the [architecture](https://immich.app/docs/developer/architecture/) for contributing to the mobile app!
diff --git a/mobile-v2/analysis_options.yaml b/mobile-v2/analysis_options.yaml
new file mode 100644
index 0000000000..d7485e6d50
--- /dev/null
+++ b/mobile-v2/analysis_options.yaml
@@ -0,0 +1,18 @@
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ rules:
+ avoid_single_cascade_in_expression_statements: false
+
+analyzer:
+ exclude:
+ - openapi/**
+
+dart_code_metrics:
+ extends:
+ - recommended
+ rules:
+ - prefer-match-file-name: false
+ - avoid-passing-self-as-argument: false
diff --git a/mobile-v2/android/.gitignore b/mobile-v2/android/.gitignore
new file mode 100644
index 0000000000..6f568019d3
--- /dev/null
+++ b/mobile-v2/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/mobile-v2/android/app/build.gradle b/mobile-v2/android/app/build.gradle
new file mode 100644
index 0000000000..3c931bca9d
--- /dev/null
+++ b/mobile-v2/android/app/build.gradle
@@ -0,0 +1,67 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+android {
+ namespace "com.alextran.immich"
+ compileSdk flutter.compileSdkVersion
+ ndkVersion flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+
+ defaultConfig {
+ applicationId "com.alextran.immich"
+ minSdkVersion flutter.minSdkVersion
+ targetSdkVersion flutter.targetSdkVersion
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+
+ // Do not build for x86 platform. This will also prevent sqlite3 from bundling the library for x86
+ ndk {
+ abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
+ }
+ }
+
+ buildTypes {
+ release {
+ signingConfig signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {}
diff --git a/mobile-v2/android/app/src/debug/AndroidManifest.xml b/mobile-v2/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000000..399f6981d5
--- /dev/null
+++ b/mobile-v2/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/mobile-v2/android/app/src/main/AndroidManifest.xml b/mobile-v2/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..51d1691704
--- /dev/null
+++ b/mobile-v2/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile-v2/android/app/src/main/kotlin/com/alextran/immich/MainActivity.kt b/mobile-v2/android/app/src/main/kotlin/com/alextran/immich/MainActivity.kt
new file mode 100644
index 0000000000..c2e8c3f565
--- /dev/null
+++ b/mobile-v2/android/app/src/main/kotlin/com/alextran/immich/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.alextran.immich
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()
diff --git a/mobile-v2/android/app/src/main/res/drawable-v21/launch_background.xml b/mobile-v2/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000000..f74085f3f6
--- /dev/null
+++ b/mobile-v2/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/mobile-v2/android/app/src/main/res/drawable/launch_background.xml b/mobile-v2/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000000..304732f884
--- /dev/null
+++ b/mobile-v2/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/mobile-v2/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/mobile-v2/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..db77bb4b7b
Binary files /dev/null and b/mobile-v2/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/mobile-v2/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/mobile-v2/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..17987b79bb
Binary files /dev/null and b/mobile-v2/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/mobile-v2/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/mobile-v2/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..09d4391482
Binary files /dev/null and b/mobile-v2/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/mobile-v2/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mobile-v2/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..d5f1c8d34e
Binary files /dev/null and b/mobile-v2/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/mobile-v2/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mobile-v2/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..4d6372eebd
Binary files /dev/null and b/mobile-v2/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/mobile-v2/android/app/src/main/res/values-night/styles.xml b/mobile-v2/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000000..06952be745
--- /dev/null
+++ b/mobile-v2/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/mobile-v2/android/app/src/main/res/values/styles.xml b/mobile-v2/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000000..cb1ef88056
--- /dev/null
+++ b/mobile-v2/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/mobile-v2/android/app/src/profile/AndroidManifest.xml b/mobile-v2/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000000..399f6981d5
--- /dev/null
+++ b/mobile-v2/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/mobile-v2/android/build.gradle b/mobile-v2/android/build.gradle
new file mode 100644
index 0000000000..bc157bd1a1
--- /dev/null
+++ b/mobile-v2/android/build.gradle
@@ -0,0 +1,18 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/mobile-v2/android/gradle.properties b/mobile-v2/android/gradle.properties
new file mode 100644
index 0000000000..598d13fee4
--- /dev/null
+++ b/mobile-v2/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/mobile-v2/android/gradle/wrapper/gradle-wrapper.properties b/mobile-v2/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..e1ca574ef0
--- /dev/null
+++ b/mobile-v2/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
diff --git a/mobile-v2/android/settings.gradle b/mobile-v2/android/settings.gradle
new file mode 100644
index 0000000000..1d6d19b7f8
--- /dev/null
+++ b/mobile-v2/android/settings.gradle
@@ -0,0 +1,26 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }
+ settings.ext.flutterSdkPath = flutterSdkPath()
+
+ includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+ id "com.android.application" version "7.3.0" apply false
+ id "org.jetbrains.kotlin.android" version "1.7.10" apply false
+}
+
+include ":app"
diff --git a/mobile-v2/build.yaml b/mobile-v2/build.yaml
new file mode 100644
index 0000000000..f656cecae7
--- /dev/null
+++ b/mobile-v2/build.yaml
@@ -0,0 +1,26 @@
+targets:
+ $default:
+ builders:
+ #drift @DriftDatabase()
+ drift_dev:
+ # Disable default builder to use modular builder instead
+ enabled: false
+ drift_dev:analyzer:
+ enabled: true
+ options: &options
+ store_date_time_values_as_text: true
+ named_parameters: true
+ write_from_json_string_constructor: false
+ data_class_to_companions: false
+ skip_verification_code: true
+ drift_dev:modular:
+ enabled: true
+ options: *options
+ #autoroute @RoutePage()
+ auto_route_generator:auto_route_generator:
+ generate_for:
+ - lib/**.page.dart
+ #autoroute @AutoRouterConfig()
+ auto_route_generator:auto_router_generator:
+ generate_for:
+ - lib/presentation/router.dart
diff --git a/mobile-v2/ios/.gitignore b/mobile-v2/ios/.gitignore
new file mode 100644
index 0000000000..7a7f9873ad
--- /dev/null
+++ b/mobile-v2/ios/.gitignore
@@ -0,0 +1,34 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/mobile-v2/ios/Flutter/AppFrameworkInfo.plist b/mobile-v2/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000000..7c56964006
--- /dev/null
+++ b/mobile-v2/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ 12.0
+
+
diff --git a/mobile-v2/ios/Flutter/Debug.xcconfig b/mobile-v2/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000000..ec97fc6f30
--- /dev/null
+++ b/mobile-v2/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/mobile-v2/ios/Flutter/Release.xcconfig b/mobile-v2/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000000..c4855bfe20
--- /dev/null
+++ b/mobile-v2/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/mobile-v2/ios/Podfile b/mobile-v2/ios/Podfile
new file mode 100644
index 0000000000..d97f17e223
--- /dev/null
+++ b/mobile-v2/ios/Podfile
@@ -0,0 +1,44 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '12.0'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+ 'Debug' => :debug,
+ 'Profile' => :release,
+ 'Release' => :release,
+}
+
+def flutter_root
+ generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
+ unless File.exist?(generated_xcode_build_settings_path)
+ raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
+ end
+
+ File.foreach(generated_xcode_build_settings_path) do |line|
+ matches = line.match(/FLUTTER_ROOT\=(.*)/)
+ return matches[1].strip if matches
+ end
+ raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_ios_podfile_setup
+
+target 'Runner' do
+ use_frameworks!
+ use_modular_headers!
+
+ flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+ target 'RunnerTests' do
+ inherit! :search_paths
+ end
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ end
+end
diff --git a/mobile-v2/ios/Runner.xcodeproj/project.pbxproj b/mobile-v2/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..6d9d8e0481
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,616 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 331C8082294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXGroup;
+ children = (
+ 331C807B294A618700263BE5 /* RunnerTests.swift */,
+ );
+ path = RunnerTests;
+ sourceTree = "";
+ };
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ 331C8082294A63A400263BE5 /* RunnerTests */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 331C8080294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+ buildPhases = (
+ 331C807D294A63A400263BE5 /* Sources */,
+ 331C807F294A63A400263BE5 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */,
+ );
+ name = RunnerTests;
+ productName = RunnerTests;
+ productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ LastUpgradeCheck = 1510;
+ ORGANIZATIONNAME = "";
+ TargetAttributes = {
+ 331C8080294A63A400263BE5 = {
+ CreatedOnToolsVersion = 14.0;
+ TestTargetID = 97C146ED1CF9000F007C117D;
+ };
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ LastSwiftMigration = 1100;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ 331C8080294A63A400263BE5 /* RunnerTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 331C807F294A63A400263BE5 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 331C807D294A63A400263BE5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97C146ED1CF9000F007C117D /* Runner */;
+ targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.alextran.immich;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 331C8088294A63A400263BE5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.alextran.immich.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Debug;
+ };
+ 331C8089294A63A400263BE5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.alextran.immich.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Release;
+ };
+ 331C808A294A63A400263BE5 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.alextran.immich.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.alextran.immich;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.alextran.immich;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 331C8088294A63A400263BE5 /* Debug */,
+ 331C8089294A63A400263BE5 /* Release */,
+ 331C808A294A63A400263BE5 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..919434a625
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000000..18d981003d
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000000..f9b0d7c5ea
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/mobile-v2/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mobile-v2/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000000..8e3ca5dfe1
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile-v2/ios/Runner.xcworkspace/contents.xcworkspacedata b/mobile-v2/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..1d526a16ed
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/mobile-v2/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mobile-v2/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000000..18d981003d
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/mobile-v2/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mobile-v2/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000000..f9b0d7c5ea
--- /dev/null
+++ b/mobile-v2/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/mobile-v2/ios/Runner/AppDelegate.swift b/mobile-v2/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000000..70693e4a8c
--- /dev/null
+++ b/mobile-v2/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..d36b1fab2d
--- /dev/null
+++ b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-App-1024x1024@1x.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000000..dc9ada4725
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000000..7353c41ecf
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000000..797d452e45
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000000..6ed2d933e1
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000000..4cd7b0099c
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000000..fe730945a0
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000000..321773cd85
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000000..797d452e45
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000000..502f463a9b
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000000..0ec3034392
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000000..0ec3034392
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000000..e9f5fea27c
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000000..84ac32ae7d
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000000..8953cba090
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000000..0467bf12aa
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000000..0bedcf2fd4
--- /dev/null
+++ b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000000..9da19eacad
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000000..9da19eacad
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000000..9da19eacad
Binary files /dev/null and b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000000..89c2725b70
--- /dev/null
+++ b/mobile-v2/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/mobile-v2/ios/Runner/Base.lproj/LaunchScreen.storyboard b/mobile-v2/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000000..f2e259c7c9
--- /dev/null
+++ b/mobile-v2/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile-v2/ios/Runner/Base.lproj/Main.storyboard b/mobile-v2/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..f3c28516fb
--- /dev/null
+++ b/mobile-v2/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile-v2/ios/Runner/Info.plist b/mobile-v2/ios/Runner/Info.plist
new file mode 100644
index 0000000000..73c6c04d66
--- /dev/null
+++ b/mobile-v2/ios/Runner/Info.plist
@@ -0,0 +1,49 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Immich
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ immich
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSupportsIndirectInputEvents
+
+
+
diff --git a/mobile-v2/ios/Runner/Runner-Bridging-Header.h b/mobile-v2/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000000..308a2a560b
--- /dev/null
+++ b/mobile-v2/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/mobile-v2/ios/RunnerTests/RunnerTests.swift b/mobile-v2/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000000..86a7c3b1b6
--- /dev/null
+++ b/mobile-v2/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+ func testExample() {
+ // If you add code to the Runner application, consider adding tests here.
+ // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+ }
+
+}
diff --git a/mobile-v2/lib/domain/entities/log.entity.dart b/mobile-v2/lib/domain/entities/log.entity.dart
new file mode 100644
index 0000000000..d455c58844
--- /dev/null
+++ b/mobile-v2/lib/domain/entities/log.entity.dart
@@ -0,0 +1,14 @@
+import 'package:drift/drift.dart';
+import 'package:immich_mobile/domain/models/log.model.dart';
+
+class Logs extends Table {
+ const Logs();
+
+ IntColumn get id => integer().autoIncrement()();
+ TextColumn get content => text()();
+ IntColumn get level => intEnum()();
+ DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
+ TextColumn get logger => text().nullable()();
+ TextColumn get error => text().nullable()();
+ TextColumn get stack => text().nullable()();
+}
diff --git a/mobile-v2/lib/domain/entities/store.entity.dart b/mobile-v2/lib/domain/entities/store.entity.dart
new file mode 100644
index 0000000000..c7d7cee09c
--- /dev/null
+++ b/mobile-v2/lib/domain/entities/store.entity.dart
@@ -0,0 +1,12 @@
+import 'package:drift/drift.dart';
+
+class Store extends Table {
+ const Store();
+
+ @override
+ String get tableName => 'store';
+
+ IntColumn get id => integer().autoIncrement()();
+ IntColumn get intValue => integer().nullable()();
+ TextColumn get stringValue => text().nullable()();
+}
diff --git a/mobile-v2/lib/domain/interfaces/database.interface.dart b/mobile-v2/lib/domain/interfaces/database.interface.dart
new file mode 100644
index 0000000000..6cd5c0950f
--- /dev/null
+++ b/mobile-v2/lib/domain/interfaces/database.interface.dart
@@ -0,0 +1,10 @@
+abstract class IDatabaseRepository {
+ /// Current version of the DB to aid with migration
+ int get schemaVersion;
+
+ /// Initializes the DB and returns the corresponding object
+ T init();
+
+ /// Check and migrate the DB to the latest schema
+ void migrateDB();
+}
diff --git a/mobile-v2/lib/domain/interfaces/log.interface.dart b/mobile-v2/lib/domain/interfaces/log.interface.dart
new file mode 100644
index 0000000000..c410e41725
--- /dev/null
+++ b/mobile-v2/lib/domain/interfaces/log.interface.dart
@@ -0,0 +1,11 @@
+import 'dart:async';
+
+import 'package:immich_mobile/domain/models/log.model.dart';
+
+abstract class ILogRepository {
+ /// Fetches all logs
+ FutureOr> fetchLogs();
+
+ /// Truncates the logs to the most recent [limit]. Defaults to recent 250 logs
+ FutureOr truncateLogs({int limit = 250});
+}
diff --git a/mobile-v2/lib/domain/interfaces/store.interface.dart b/mobile-v2/lib/domain/interfaces/store.interface.dart
new file mode 100644
index 0000000000..9c37b8e4d7
--- /dev/null
+++ b/mobile-v2/lib/domain/interfaces/store.interface.dart
@@ -0,0 +1,17 @@
+import 'dart:async';
+
+import 'package:immich_mobile/domain/models/store.model.dart';
+
+abstract class IStoreRepository {
+ FutureOr getValue(StoreKey key);
+
+ FutureOr setValue(StoreKey key, T value);
+
+ FutureOr deleteValue(StoreKey key);
+
+ Stream watchValue(StoreKey key);
+
+ Stream> watchStore();
+
+ FutureOr clearStore();
+}
diff --git a/mobile-v2/lib/domain/models/log.model.dart b/mobile-v2/lib/domain/models/log.model.dart
new file mode 100644
index 0000000000..2b1a120b5a
--- /dev/null
+++ b/mobile-v2/lib/domain/models/log.model.dart
@@ -0,0 +1,59 @@
+import 'package:logging/logging.dart';
+
+/// Log levels according to dart logging [Level]
+enum LogLevel {
+ all,
+ finest,
+ finer,
+ fine,
+ config,
+ info,
+ warning,
+ severe,
+ shout,
+ off,
+}
+
+extension LevelExtension on Level {
+ LogLevel toLogLevel() =>
+ LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ??
+ LogLevel.info;
+}
+
+class LogMessage {
+ final int id;
+ final String content;
+ final LogLevel level;
+ final DateTime createdAt;
+ final String? logger;
+ final String? error;
+ final String? stack;
+
+ const LogMessage({
+ required this.id,
+ required this.content,
+ required this.level,
+ required this.createdAt,
+ this.logger,
+ this.error,
+ this.stack,
+ });
+
+ @override
+ bool operator ==(covariant LogMessage other) {
+ if (identical(this, other)) return true;
+
+ return other.hashCode == hashCode;
+ }
+
+ @override
+ int get hashCode {
+ return id.hashCode ^
+ content.hashCode ^
+ level.hashCode ^
+ createdAt.hashCode ^
+ logger.hashCode ^
+ error.hashCode ^
+ stack.hashCode;
+ }
+}
diff --git a/mobile-v2/lib/domain/models/store.model.dart b/mobile-v2/lib/domain/models/store.model.dart
new file mode 100644
index 0000000000..872a8559a1
--- /dev/null
+++ b/mobile-v2/lib/domain/models/store.model.dart
@@ -0,0 +1,70 @@
+/// Key for each possible value in the `Store`.
+/// Defines the data type for each value
+enum StoreKey {
+ // Server endpoint related stores
+ accessToken(0, type: String),
+ serverEndpoint(1, type: String),
+ ;
+
+ const StoreKey(this.id, {required this.type});
+ final int id;
+ final Type type;
+}
+
+class StoreValue {
+ final int id;
+ final int? intValue;
+ final String? stringValue;
+
+ const StoreValue({required this.id, this.intValue, this.stringValue});
+
+ @override
+ bool operator ==(covariant StoreValue other) {
+ if (identical(this, other)) return true;
+
+ return other.hashCode == hashCode;
+ }
+
+ @override
+ int get hashCode => id.hashCode ^ intValue.hashCode ^ stringValue.hashCode;
+
+ T? extract(Type type) {
+ switch (type) {
+ case const (int):
+ return intValue as T?;
+ case const (bool):
+ return intValue == null ? null : (intValue! == 1) as T;
+ case const (DateTime):
+ return intValue == null
+ ? null
+ : DateTime.fromMicrosecondsSinceEpoch(intValue!) as T;
+ case const (String):
+ return stringValue as T?;
+ default:
+ throw UnsupportedError("Unknown Store Key type");
+ }
+ }
+
+ static StoreValue of(StoreKey key, T? value) {
+ int? i;
+ String? s;
+
+ switch (key.type) {
+ case const (int):
+ i = value as int?;
+ break;
+ case const (bool):
+ i = value == null ? null : (value == true ? 1 : 0);
+ break;
+ case const (DateTime):
+ i = value == null ? null : (value as DateTime).microsecondsSinceEpoch;
+ break;
+ case const (String):
+ s = value as String?;
+ break;
+ default:
+ throw UnsupportedError("Unknown Store Key type");
+ }
+ return StoreValue(id: key.id, intValue: i, stringValue: s);
+ }
+}
diff --git a/mobile-v2/lib/domain/repositories/database.repository.dart b/mobile-v2/lib/domain/repositories/database.repository.dart
new file mode 100644
index 0000000000..066955a9c4
--- /dev/null
+++ b/mobile-v2/lib/domain/repositories/database.repository.dart
@@ -0,0 +1,54 @@
+import 'dart:io';
+
+import 'package:drift/drift.dart';
+import 'package:drift/native.dart';
+import 'package:immich_mobile/domain/entities/log.entity.dart';
+import 'package:immich_mobile/domain/entities/store.entity.dart';
+import 'package:immich_mobile/domain/interfaces/database.interface.dart';
+import 'package:path/path.dart' as p;
+import 'package:path_provider/path_provider.dart';
+import 'package:sqlite3/sqlite3.dart';
+import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
+
+import 'database.repository.drift.dart';
+
+@DriftDatabase(tables: [Logs, Store])
+class DriftDatabaseRepository extends $DriftDatabaseRepository
+ implements IDatabaseRepository {
+ DriftDatabaseRepository() : super(_openConnection());
+
+ static LazyDatabase _openConnection() {
+ return LazyDatabase(() async {
+ final dbFolder = await getApplicationDocumentsDirectory();
+ final file = File(p.join(dbFolder.path, 'db.sqlite'));
+
+ // Work around limitations on old Android versions
+ // https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3_flutter_libs#problems-on-android-6
+ if (Platform.isAndroid) {
+ await applyWorkaroundToOpenSqlite3OnOldAndroidVersions();
+ }
+
+ // Make sqlite3 pick a more suitable location for temporary files - the
+ // one from the system may be inaccessible due to sandboxing.
+ // https://github.com/simolus3/moor/issues/876#issuecomment-710013503
+ final cachebase = (await getTemporaryDirectory()).path;
+ // We can't access /tmp on Android, which sqlite3 would try by default.
+ // Explicitly tell it about the correct temporary directory.
+ sqlite3.tempDirectory = cachebase;
+
+ return NativeDatabase.createInBackground(file);
+ });
+ }
+
+ @override
+ GeneratedDatabase init() => this;
+
+ @override
+ int get schemaVersion => 1;
+
+ @override
+ // ignore: no-empty-block
+ void migrateDB() {
+ // No migrations yet
+ }
+}
diff --git a/mobile-v2/lib/domain/repositories/log.repository.dart b/mobile-v2/lib/domain/repositories/log.repository.dart
new file mode 100644
index 0000000000..09a8f5a8c0
--- /dev/null
+++ b/mobile-v2/lib/domain/repositories/log.repository.dart
@@ -0,0 +1,43 @@
+import 'package:immich_mobile/domain/entities/log.entity.drift.dart';
+import 'package:immich_mobile/domain/interfaces/log.interface.dart';
+import 'package:immich_mobile/domain/models/log.model.dart';
+import 'package:immich_mobile/domain/repositories/database.repository.dart';
+
+class LogDriftRepository implements ILogRepository {
+ final DriftDatabaseRepository db;
+
+ const LogDriftRepository(this.db);
+
+ @override
+ Future> fetchLogs() async {
+ return await db.select(db.logs).map((l) => l.toModel()).get();
+ }
+
+ @override
+ Future truncateLogs({int limit = 250}) {
+ return db.transaction(() async {
+ final totalCount = await db.managers.logs.count();
+ if (totalCount > limit) {
+ final rowsToDelete = totalCount - limit;
+ await db.managers.logs
+ .orderBy((o) => o.createdAt.desc())
+ .limit(rowsToDelete)
+ .delete();
+ }
+ });
+ }
+}
+
+extension _LogToLogMessage on Log {
+ LogMessage toModel() {
+ return LogMessage(
+ id: id,
+ content: content,
+ createdAt: createdAt,
+ level: level,
+ error: error,
+ logger: logger,
+ stack: stack,
+ );
+ }
+}
diff --git a/mobile-v2/lib/domain/repositories/store.repository.dart b/mobile-v2/lib/domain/repositories/store.repository.dart
new file mode 100644
index 0000000000..39ad10273e
--- /dev/null
+++ b/mobile-v2/lib/domain/repositories/store.repository.dart
@@ -0,0 +1,66 @@
+import 'dart:async';
+
+import 'package:drift/drift.dart';
+import 'package:immich_mobile/domain/entities/store.entity.drift.dart';
+import 'package:immich_mobile/domain/interfaces/store.interface.dart';
+import 'package:immich_mobile/domain/models/store.model.dart';
+import 'package:immich_mobile/domain/repositories/database.repository.dart';
+
+class StoreDriftRepository implements IStoreRepository {
+ final DriftDatabaseRepository db;
+
+ const StoreDriftRepository(this.db);
+
+ @override
+ FutureOr getValue(StoreKey key) async {
+ final value = await db.managers.store
+ .filter((s) => s.id.equals(key.id))
+ .getSingleOrNull();
+ return value?.toModel().extract(key.type);
+ }
+
+ @override
+ FutureOr setValue(StoreKey key, T value) {
+ return db.transaction(() async {
+ final storeValue = StoreValue.of(key, value);
+ await db.into(db.store).insertOnConflictUpdate(StoreCompanion.insert(
+ id: Value(storeValue.id),
+ intValue: Value(storeValue.intValue),
+ stringValue: Value(storeValue.stringValue),
+ ));
+ });
+ }
+
+ @override
+ FutureOr deleteValue(StoreKey key) {
+ return db.transaction(() async {
+ await db.managers.store.filter((s) => s.id.equals(key.id)).delete();
+ });
+ }
+
+ @override
+ Stream> watchStore() {
+ return (db.select(db.store).map((s) => s.toModel())).watch();
+ }
+
+ @override
+ Stream watchValue(StoreKey key) {
+ return db.managers.store
+ .filter((s) => s.id.equals(key.id))
+ .watchSingleOrNull()
+ .map((e) => e?.toModel().extract(key.type));
+ }
+
+ @override
+ FutureOr clearStore() {
+ return db.transaction(() async {
+ await db.managers.store.delete();
+ });
+ }
+}
+
+extension _StoreDataToStoreValue on StoreData {
+ StoreValue toModel() {
+ return StoreValue(id: id, intValue: intValue, stringValue: stringValue);
+ }
+}
diff --git a/mobile-v2/lib/domain/service_locator.dart b/mobile-v2/lib/domain/service_locator.dart
new file mode 100644
index 0000000000..e5c42c54f2
--- /dev/null
+++ b/mobile-v2/lib/domain/service_locator.dart
@@ -0,0 +1,29 @@
+import 'package:get_it/get_it.dart';
+import 'package:immich_mobile/domain/interfaces/log.interface.dart';
+import 'package:immich_mobile/domain/interfaces/store.interface.dart';
+import 'package:immich_mobile/domain/repositories/database.repository.dart';
+import 'package:immich_mobile/domain/repositories/log.repository.dart';
+import 'package:immich_mobile/domain/repositories/store.repository.dart';
+import 'package:immich_mobile/domain/store_manager.dart';
+
+/// Ambient instance
+final getIt = GetIt.instance;
+
+class ServiceLocator {
+ const ServiceLocator._internal();
+
+ static void configureServices() {
+ // Register DB
+ getIt.registerSingleton(DriftDatabaseRepository());
+ _registerCoreServices();
+ }
+
+ static void _registerCoreServices() {
+ // Init store
+ getIt
+ .registerFactory(() => StoreDriftRepository(getIt()));
+ getIt.registerSingleton(StoreManager(getIt()));
+ // Logs
+ getIt.registerFactory(() => LogDriftRepository(getIt()));
+ }
+}
diff --git a/mobile-v2/lib/domain/store_manager.dart b/mobile-v2/lib/domain/store_manager.dart
new file mode 100644
index 0000000000..fe6b0bec71
--- /dev/null
+++ b/mobile-v2/lib/domain/store_manager.dart
@@ -0,0 +1,99 @@
+import 'dart:async';
+
+import 'package:collection/collection.dart';
+import 'package:immich_mobile/domain/interfaces/store.interface.dart';
+import 'package:immich_mobile/domain/models/store.model.dart';
+import 'package:immich_mobile/utils/mixins/log_context.mixin.dart';
+
+class StoreKeyNotFoundException implements Exception {
+ final StoreKey key;
+ const StoreKeyNotFoundException(this.key);
+
+ @override
+ String toString() => "Key '${key.name}' not found in Store";
+}
+
+/// Key-value store for individual items enumerated in StoreKey.
+/// Supports String, int and JSON-serializable Objects
+/// Can be used concurrently from multiple isolates
+class StoreManager with LogContext {
+ late final IStoreRepository _db;
+ StreamSubscription? _subscription;
+ final Map _cache = {};
+
+ StoreManager._internal();
+ static final StoreManager _instance = StoreManager._internal();
+
+ factory StoreManager(IStoreRepository db) {
+ if (_instance._subscription == null) {
+ _instance._db = db;
+ _instance._populateCache();
+ _instance._subscription =
+ _instance._db.watchStore().listen(_instance._onChangeListener);
+ }
+ return _instance;
+ }
+
+ void dispose() {
+ _subscription?.cancel();
+ }
+
+ FutureOr _populateCache() async {
+ for (StoreKey key in StoreKey.values) {
+ final StoreValue? value = await _db.getValue(key);
+ if (value != null) {
+ _cache[key.id] = value;
+ }
+ }
+ }
+
+ /// clears all values from this store (cache and DB), only for testing!
+ Future clear() async {
+ _cache.clear();
+ return await _db.clearStore();
+ }
+
+ /// Returns the stored value for the given key (possibly null)
+ T? tryGet(StoreKey key) => _cache[key.id] as T?;
+
+ /// Returns the stored value for the given key or if null the [defaultValue]
+ /// Throws a [StoreKeyNotFoundException] if both are null
+ T get(StoreKey key, [T? defaultValue]) {
+ final value = _cache[key.id] ?? defaultValue;
+ if (value == null) {
+ throw StoreKeyNotFoundException(key);
+ }
+ return value;
+ }
+
+ /// Watches a specific key for changes
+ Stream watch(StoreKey key) => _db.watchValue(key);
+
+ /// Stores the value synchronously in the cache and asynchronously in the DB
+ FutureOr put(StoreKey key, T value) async {
+ if (_cache[key.id] == value) return Future.value();
+ _cache[key.id] = value;
+ return await _db.setValue(key, value);
+ }
+
+ /// Removes the value synchronously from the cache and asynchronously from the DB
+ Future delete(StoreKey key) async {
+ if (_cache[key.id] == null) return Future.value();
+ _cache.remove(key.id);
+ return await _db.deleteValue(key);
+ }
+
+ /// Updates the state in cache if a value is updated in any isolate
+ void _onChangeListener(List? data) {
+ if (data != null) {
+ for (StoreValue value in data) {
+ final key = StoreKey.values.firstWhereOrNull((e) => e.id == value.id);
+ if (key != null) {
+ _cache[value.id] = value.extract(key.type);
+ } else {
+ log.warning("No key available for value Id - ${value.id}");
+ }
+ }
+ }
+ }
+}
diff --git a/mobile-v2/lib/main.dart b/mobile-v2/lib/main.dart
new file mode 100644
index 0000000000..7862fadfd0
--- /dev/null
+++ b/mobile-v2/lib/main.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+import 'package:immich_mobile/domain/service_locator.dart';
+
+void main() {
+ // Ensure the bindings are initialized
+ WidgetsFlutterBinding.ensureInitialized();
+
+ // DI Injection
+ ServiceLocator.configureServices();
+
+ runApp(const MainWidget());
+}
+
+class MainWidget extends StatelessWidget {
+ const MainWidget({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Demo',
+ theme: ThemeData(
+ colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+ useMaterial3: true,
+ ),
+ home: const Text('Flutter Demo Home Page'),
+ );
+ }
+}
diff --git a/mobile-v2/lib/presentation/router.dart b/mobile-v2/lib/presentation/router.dart
new file mode 100644
index 0000000000..2c9c639adf
--- /dev/null
+++ b/mobile-v2/lib/presentation/router.dart
@@ -0,0 +1,9 @@
+import 'package:auto_route/auto_route.dart';
+
+part 'router.gr.dart';
+
+@AutoRouterConfig(replaceInRouteName: 'Page,Route')
+class AppRouter extends _$AppRouter {
+ @override
+ List get routes => [];
+}
diff --git a/mobile-v2/lib/utils/constants/assets.gen.dart b/mobile-v2/lib/utils/constants/assets.gen.dart
new file mode 100644
index 0000000000..4899ed03ae
--- /dev/null
+++ b/mobile-v2/lib/utils/constants/assets.gen.dart
@@ -0,0 +1,112 @@
+/// GENERATED CODE - DO NOT MODIFY BY HAND
+/// *****************************************************
+/// FlutterGen
+/// *****************************************************
+
+// coverage:ignore-file
+// ignore_for_file: type=lint
+// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use
+
+import 'package:flutter/widgets.dart';
+
+class $AssetsImagesGen {
+ const $AssetsImagesGen();
+
+ /// File path: assets/images/immich-logo.png
+ AssetGenImage get immichLogo =>
+ const AssetGenImage('assets/images/immich-logo.png');
+
+ /// File path: assets/images/immich-text-dark.png
+ AssetGenImage get immichTextDark =>
+ const AssetGenImage('assets/images/immich-text-dark.png');
+
+ /// File path: assets/images/immich-text-light.png
+ AssetGenImage get immichTextLight =>
+ const AssetGenImage('assets/images/immich-text-light.png');
+
+ /// List of all assets
+ List get values =>
+ [immichLogo, immichTextDark, immichTextLight];
+}
+
+class Assets {
+ Assets._();
+
+ static const $AssetsImagesGen images = $AssetsImagesGen();
+}
+
+class AssetGenImage {
+ const AssetGenImage(this._assetName, {this.size = null});
+
+ final String _assetName;
+
+ final Size? size;
+
+ Image image({
+ Key? key,
+ AssetBundle? bundle,
+ ImageFrameBuilder? frameBuilder,
+ ImageErrorWidgetBuilder? errorBuilder,
+ String? semanticLabel,
+ bool excludeFromSemantics = false,
+ double? scale,
+ double? width,
+ double? height,
+ Color? color,
+ Animation? opacity,
+ BlendMode? colorBlendMode,
+ BoxFit? fit,
+ AlignmentGeometry alignment = Alignment.center,
+ ImageRepeat repeat = ImageRepeat.noRepeat,
+ Rect? centerSlice,
+ bool matchTextDirection = false,
+ bool gaplessPlayback = false,
+ bool isAntiAlias = false,
+ String? package,
+ FilterQuality filterQuality = FilterQuality.low,
+ int? cacheWidth,
+ int? cacheHeight,
+ }) {
+ return Image.asset(
+ _assetName,
+ key: key,
+ bundle: bundle,
+ frameBuilder: frameBuilder,
+ errorBuilder: errorBuilder,
+ semanticLabel: semanticLabel,
+ excludeFromSemantics: excludeFromSemantics,
+ scale: scale,
+ width: width,
+ height: height,
+ color: color,
+ opacity: opacity,
+ colorBlendMode: colorBlendMode,
+ fit: fit,
+ alignment: alignment,
+ repeat: repeat,
+ centerSlice: centerSlice,
+ matchTextDirection: matchTextDirection,
+ gaplessPlayback: gaplessPlayback,
+ isAntiAlias: isAntiAlias,
+ package: package,
+ filterQuality: filterQuality,
+ cacheWidth: cacheWidth,
+ cacheHeight: cacheHeight,
+ );
+ }
+
+ ImageProvider provider({
+ AssetBundle? bundle,
+ String? package,
+ }) {
+ return AssetImage(
+ _assetName,
+ bundle: bundle,
+ package: package,
+ );
+ }
+
+ String get path => _assetName;
+
+ String get keyName => _assetName;
+}
diff --git a/mobile-v2/lib/utils/mixins/log_context.mixin.dart b/mobile-v2/lib/utils/mixins/log_context.mixin.dart
new file mode 100644
index 0000000000..54b3eaf9d6
--- /dev/null
+++ b/mobile-v2/lib/utils/mixins/log_context.mixin.dart
@@ -0,0 +1,14 @@
+import 'package:flutter/foundation.dart';
+import 'package:logging/logging.dart';
+
+mixin LogContext {
+ late final String ctx = logContext;
+
+ /// Context name of the log message
+ /// Override this to provide a custom name
+ String get logContext => runtimeType.toString();
+
+ @protected
+ @nonVirtual
+ Logger get log => Logger.detached(ctx);
+}
diff --git a/mobile-v2/openapi/.gitignore b/mobile-v2/openapi/.gitignore
new file mode 100644
index 0000000000..4298cdcbd1
--- /dev/null
+++ b/mobile-v2/openapi/.gitignore
@@ -0,0 +1,41 @@
+# See https://dart.dev/guides/libraries/private-files
+
+# Files and directories created by pub
+.dart_tool/
+.buildlog
+.packages
+.project
+.pub/
+build/
+**/packages/
+
+# Files created by dart2js
+# (Most Dart developers will use pub build to compile Dart, use/modify these
+# rules if you intend to use dart2js directly
+# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
+# differentiate from explicit Javascript files)
+*.dart.js
+*.part.js
+*.js.deps
+*.js.map
+*.info.json
+
+# Directory created by dartdoc
+doc/api/
+
+# Don't commit pubspec lock file
+# (Library packages only! Remove pattern if developing an application package)
+pubspec.lock
+
+# Don’t commit files and directories created by other development environments.
+# For example, if your development environment creates any of the following files,
+# consider putting them in a global ignore file:
+
+# IntelliJ
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# Mac
+.DS_Store
diff --git a/mobile-v2/openapi/.openapi-generator-ignore b/mobile-v2/openapi/.openapi-generator-ignore
new file mode 100644
index 0000000000..7484ee590a
--- /dev/null
+++ b/mobile-v2/openapi/.openapi-generator-ignore
@@ -0,0 +1,23 @@
+# OpenAPI Generator Ignore
+# Generated by openapi-generator https://github.com/openapitools/openapi-generator
+
+# Use this file to prevent files from being overwritten by the generator.
+# The patterns follow closely to .gitignore or .dockerignore.
+
+# As an example, the C# client generator defines ApiClient.cs.
+# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
+#ApiClient.cs
+
+# You can match any string of characters against a directory, file or extension with a single asterisk (*):
+#foo/*/qux
+# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
+
+# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
+#foo/**/qux
+# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
+
+# You can also negate patterns with an exclamation (!).
+# For example, you can ignore all files in a docs folder with the file extension .md:
+#docs/*.md
+# Then explicitly reverse the ignore rule for a single file:
+#!docs/README.md
diff --git a/mobile-v2/openapi/.openapi-generator/FILES b/mobile-v2/openapi/.openapi-generator/FILES
new file mode 100644
index 0000000000..45401dd919
--- /dev/null
+++ b/mobile-v2/openapi/.openapi-generator/FILES
@@ -0,0 +1,221 @@
+.gitignore
+.openapi-generator-ignore
+README.md
+analysis_options.yaml
+lib/openapi.dart
+lib/src/api.dart
+lib/src/api/activity_api.dart
+lib/src/api/album_api.dart
+lib/src/api/api_key_api.dart
+lib/src/api/asset_api.dart
+lib/src/api/audit_api.dart
+lib/src/api/authentication_api.dart
+lib/src/api/download_api.dart
+lib/src/api/face_api.dart
+lib/src/api/file_report_api.dart
+lib/src/api/job_api.dart
+lib/src/api/library_api.dart
+lib/src/api/memory_api.dart
+lib/src/api/o_auth_api.dart
+lib/src/api/partner_api.dart
+lib/src/api/person_api.dart
+lib/src/api/search_api.dart
+lib/src/api/server_info_api.dart
+lib/src/api/sessions_api.dart
+lib/src/api/shared_link_api.dart
+lib/src/api/sync_api.dart
+lib/src/api/system_config_api.dart
+lib/src/api/system_metadata_api.dart
+lib/src/api/tag_api.dart
+lib/src/api/timeline_api.dart
+lib/src/api/trash_api.dart
+lib/src/api/user_api.dart
+lib/src/api_util.dart
+lib/src/auth/api_key_auth.dart
+lib/src/auth/auth.dart
+lib/src/auth/basic_auth.dart
+lib/src/auth/bearer_auth.dart
+lib/src/auth/oauth.dart
+lib/src/date_serializer.dart
+lib/src/model/activity_create_dto.dart
+lib/src/model/activity_response_dto.dart
+lib/src/model/activity_statistics_response_dto.dart
+lib/src/model/add_users_dto.dart
+lib/src/model/admin_onboarding_update_dto.dart
+lib/src/model/album_count_response_dto.dart
+lib/src/model/album_response_dto.dart
+lib/src/model/all_job_status_response_dto.dart
+lib/src/model/api_key_create_dto.dart
+lib/src/model/api_key_create_response_dto.dart
+lib/src/model/api_key_response_dto.dart
+lib/src/model/api_key_update_dto.dart
+lib/src/model/asset_bulk_delete_dto.dart
+lib/src/model/asset_bulk_update_dto.dart
+lib/src/model/asset_bulk_upload_check_dto.dart
+lib/src/model/asset_bulk_upload_check_item.dart
+lib/src/model/asset_bulk_upload_check_response_dto.dart
+lib/src/model/asset_bulk_upload_check_result.dart
+lib/src/model/asset_delta_sync_response_dto.dart
+lib/src/model/asset_face_response_dto.dart
+lib/src/model/asset_face_update_dto.dart
+lib/src/model/asset_face_update_item.dart
+lib/src/model/asset_face_without_person_response_dto.dart
+lib/src/model/asset_file_upload_response_dto.dart
+lib/src/model/asset_ids_dto.dart
+lib/src/model/asset_ids_response_dto.dart
+lib/src/model/asset_job_name.dart
+lib/src/model/asset_jobs_dto.dart
+lib/src/model/asset_order.dart
+lib/src/model/asset_response_dto.dart
+lib/src/model/asset_stats_response_dto.dart
+lib/src/model/asset_type_enum.dart
+lib/src/model/audio_codec.dart
+lib/src/model/audit_deletes_response_dto.dart
+lib/src/model/bulk_id_response_dto.dart
+lib/src/model/bulk_ids_dto.dart
+lib/src/model/change_password_dto.dart
+lib/src/model/check_existing_assets_dto.dart
+lib/src/model/check_existing_assets_response_dto.dart
+lib/src/model/clip_config.dart
+lib/src/model/clip_mode.dart
+lib/src/model/colorspace.dart
+lib/src/model/cq_mode.dart
+lib/src/model/create_album_dto.dart
+lib/src/model/create_asset_dto.dart
+lib/src/model/create_library_dto.dart
+lib/src/model/create_profile_image_dto.dart
+lib/src/model/create_profile_image_response_dto.dart
+lib/src/model/create_tag_dto.dart
+lib/src/model/create_user_dto.dart
+lib/src/model/curated_locations_response_dto.dart
+lib/src/model/curated_objects_response_dto.dart
+lib/src/model/date.dart
+lib/src/model/delete_user_dto.dart
+lib/src/model/download_archive_info.dart
+lib/src/model/download_info_dto.dart
+lib/src/model/download_response_dto.dart
+lib/src/model/entity_type.dart
+lib/src/model/exif_response_dto.dart
+lib/src/model/face_dto.dart
+lib/src/model/file_checksum_dto.dart
+lib/src/model/file_checksum_response_dto.dart
+lib/src/model/file_report_dto.dart
+lib/src/model/file_report_fix_dto.dart
+lib/src/model/file_report_item_dto.dart
+lib/src/model/image_format.dart
+lib/src/model/job_command.dart
+lib/src/model/job_command_dto.dart
+lib/src/model/job_counts_dto.dart
+lib/src/model/job_name.dart
+lib/src/model/job_settings_dto.dart
+lib/src/model/job_status_dto.dart
+lib/src/model/library_response_dto.dart
+lib/src/model/library_stats_response_dto.dart
+lib/src/model/library_type.dart
+lib/src/model/log_level.dart
+lib/src/model/login_credential_dto.dart
+lib/src/model/login_response_dto.dart
+lib/src/model/logout_response_dto.dart
+lib/src/model/map_marker_response_dto.dart
+lib/src/model/map_theme.dart
+lib/src/model/memory_create_dto.dart
+lib/src/model/memory_lane_response_dto.dart
+lib/src/model/memory_response_dto.dart
+lib/src/model/memory_type.dart
+lib/src/model/memory_update_dto.dart
+lib/src/model/merge_person_dto.dart
+lib/src/model/metadata_search_dto.dart
+lib/src/model/model_type.dart
+lib/src/model/o_auth_authorize_response_dto.dart
+lib/src/model/o_auth_callback_dto.dart
+lib/src/model/o_auth_config_dto.dart
+lib/src/model/on_this_day_dto.dart
+lib/src/model/partner_response_dto.dart
+lib/src/model/path_entity_type.dart
+lib/src/model/path_type.dart
+lib/src/model/people_response_dto.dart
+lib/src/model/people_update_dto.dart
+lib/src/model/people_update_item.dart
+lib/src/model/person_create_dto.dart
+lib/src/model/person_response_dto.dart
+lib/src/model/person_statistics_response_dto.dart
+lib/src/model/person_update_dto.dart
+lib/src/model/person_with_faces_response_dto.dart
+lib/src/model/places_response_dto.dart
+lib/src/model/queue_status_dto.dart
+lib/src/model/reaction_level.dart
+lib/src/model/reaction_type.dart
+lib/src/model/recognition_config.dart
+lib/src/model/reverse_geocoding_state_response_dto.dart
+lib/src/model/scan_library_dto.dart
+lib/src/model/search_album_response_dto.dart
+lib/src/model/search_asset_response_dto.dart
+lib/src/model/search_explore_item.dart
+lib/src/model/search_explore_response_dto.dart
+lib/src/model/search_facet_count_response_dto.dart
+lib/src/model/search_facet_response_dto.dart
+lib/src/model/search_response_dto.dart
+lib/src/model/search_suggestion_type.dart
+lib/src/model/server_config_dto.dart
+lib/src/model/server_features_dto.dart
+lib/src/model/server_info_response_dto.dart
+lib/src/model/server_media_types_response_dto.dart
+lib/src/model/server_ping_response.dart
+lib/src/model/server_stats_response_dto.dart
+lib/src/model/server_theme_dto.dart
+lib/src/model/server_version_response_dto.dart
+lib/src/model/session_response_dto.dart
+lib/src/model/shared_link_create_dto.dart
+lib/src/model/shared_link_edit_dto.dart
+lib/src/model/shared_link_response_dto.dart
+lib/src/model/shared_link_type.dart
+lib/src/model/sign_up_dto.dart
+lib/src/model/smart_info_response_dto.dart
+lib/src/model/smart_search_dto.dart
+lib/src/model/system_config_dto.dart
+lib/src/model/system_config_f_fmpeg_dto.dart
+lib/src/model/system_config_image_dto.dart
+lib/src/model/system_config_job_dto.dart
+lib/src/model/system_config_library_dto.dart
+lib/src/model/system_config_library_scan_dto.dart
+lib/src/model/system_config_library_watch_dto.dart
+lib/src/model/system_config_logging_dto.dart
+lib/src/model/system_config_machine_learning_dto.dart
+lib/src/model/system_config_map_dto.dart
+lib/src/model/system_config_new_version_check_dto.dart
+lib/src/model/system_config_o_auth_dto.dart
+lib/src/model/system_config_password_login_dto.dart
+lib/src/model/system_config_reverse_geocoding_dto.dart
+lib/src/model/system_config_server_dto.dart
+lib/src/model/system_config_storage_template_dto.dart
+lib/src/model/system_config_template_storage_option_dto.dart
+lib/src/model/system_config_theme_dto.dart
+lib/src/model/system_config_trash_dto.dart
+lib/src/model/system_config_user_dto.dart
+lib/src/model/tag_response_dto.dart
+lib/src/model/tag_type_enum.dart
+lib/src/model/thumbnail_format.dart
+lib/src/model/time_bucket_response_dto.dart
+lib/src/model/time_bucket_size.dart
+lib/src/model/tone_mapping.dart
+lib/src/model/transcode_hw_accel.dart
+lib/src/model/transcode_policy.dart
+lib/src/model/update_album_dto.dart
+lib/src/model/update_asset_dto.dart
+lib/src/model/update_library_dto.dart
+lib/src/model/update_partner_dto.dart
+lib/src/model/update_stack_parent_dto.dart
+lib/src/model/update_tag_dto.dart
+lib/src/model/update_user_dto.dart
+lib/src/model/usage_by_user_dto.dart
+lib/src/model/user_avatar_color.dart
+lib/src/model/user_dto.dart
+lib/src/model/user_response_dto.dart
+lib/src/model/user_status.dart
+lib/src/model/validate_access_token_response_dto.dart
+lib/src/model/validate_library_dto.dart
+lib/src/model/validate_library_import_path_response_dto.dart
+lib/src/model/validate_library_response_dto.dart
+lib/src/model/video_codec.dart
+lib/src/serializers.dart
+pubspec.yaml
diff --git a/mobile-v2/openapi/.openapi-generator/VERSION b/mobile-v2/openapi/.openapi-generator/VERSION
new file mode 100644
index 0000000000..4b49d9bb63
--- /dev/null
+++ b/mobile-v2/openapi/.openapi-generator/VERSION
@@ -0,0 +1 @@
+7.2.0
\ No newline at end of file
diff --git a/mobile-v2/openapi/README.md b/mobile-v2/openapi/README.md
new file mode 100644
index 0000000000..c62219a1d0
--- /dev/null
+++ b/mobile-v2/openapi/README.md
@@ -0,0 +1,427 @@
+# openapi (EXPERIMENTAL)
+Immich API
+
+This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
+
+- API version: 1.102.3
+- Build package: org.openapitools.codegen.languages.DartDioClientCodegen
+
+## Requirements
+
+* Dart 2.15.0+ or Flutter 2.8.0+
+* Dio 5.0.0+ (https://pub.dev/packages/dio)
+
+## Installation & Usage
+
+### pub.dev
+To use the package from [pub.dev](https://pub.dev), please include the following in pubspec.yaml
+```yaml
+dependencies:
+ openapi: 1.0.0
+```
+
+### Github
+If this Dart package is published to Github, please include the following in pubspec.yaml
+```yaml
+dependencies:
+ openapi:
+ git:
+ url: https://github.com/GIT_USER_ID/GIT_REPO_ID.git
+ #ref: main
+```
+
+### Local development
+To use the package from your local drive, please include the following in pubspec.yaml
+```yaml
+dependencies:
+ openapi:
+ path: /path/to/openapi
+```
+
+## Getting Started
+
+Please follow the [installation procedure](#installation--usage) and then run the following:
+
+```dart
+import 'package:openapi/openapi.dart';
+
+
+final api = Openapi().getAPIKeyApi();
+final APIKeyCreateDto aPIKeyCreateDto = ; // APIKeyCreateDto |
+
+try {
+ final response = await api.createApiKey(aPIKeyCreateDto);
+ print(response);
+} catch on DioException (e) {
+ print("Exception when calling APIKeyApi->createApiKey: $e\n");
+}
+
+```
+
+## Documentation for API Endpoints
+
+All URIs are relative to */api*
+
+Class | Method | HTTP request | Description
+------------ | ------------- | ------------- | -------------
+[*APIKeyApi*](doc/APIKeyApi.md) | [**createApiKey**](doc/APIKeyApi.md#createapikey) | **POST** /api-key |
+[*APIKeyApi*](doc/APIKeyApi.md) | [**deleteApiKey**](doc/APIKeyApi.md#deleteapikey) | **DELETE** /api-key/{id} |
+[*APIKeyApi*](doc/APIKeyApi.md) | [**getApiKey**](doc/APIKeyApi.md#getapikey) | **GET** /api-key/{id} |
+[*APIKeyApi*](doc/APIKeyApi.md) | [**getApiKeys**](doc/APIKeyApi.md#getapikeys) | **GET** /api-key |
+[*APIKeyApi*](doc/APIKeyApi.md) | [**updateApiKey**](doc/APIKeyApi.md#updateapikey) | **PUT** /api-key/{id} |
+[*ActivityApi*](doc/ActivityApi.md) | [**createActivity**](doc/ActivityApi.md#createactivity) | **POST** /activity |
+[*ActivityApi*](doc/ActivityApi.md) | [**deleteActivity**](doc/ActivityApi.md#deleteactivity) | **DELETE** /activity/{id} |
+[*ActivityApi*](doc/ActivityApi.md) | [**getActivities**](doc/ActivityApi.md#getactivities) | **GET** /activity |
+[*ActivityApi*](doc/ActivityApi.md) | [**getActivityStatistics**](doc/ActivityApi.md#getactivitystatistics) | **GET** /activity/statistics |
+[*AlbumApi*](doc/AlbumApi.md) | [**addAssetsToAlbum**](doc/AlbumApi.md#addassetstoalbum) | **PUT** /album/{id}/assets |
+[*AlbumApi*](doc/AlbumApi.md) | [**addUsersToAlbum**](doc/AlbumApi.md#adduserstoalbum) | **PUT** /album/{id}/users |
+[*AlbumApi*](doc/AlbumApi.md) | [**createAlbum**](doc/AlbumApi.md#createalbum) | **POST** /album |
+[*AlbumApi*](doc/AlbumApi.md) | [**deleteAlbum**](doc/AlbumApi.md#deletealbum) | **DELETE** /album/{id} |
+[*AlbumApi*](doc/AlbumApi.md) | [**getAlbumCount**](doc/AlbumApi.md#getalbumcount) | **GET** /album/count |
+[*AlbumApi*](doc/AlbumApi.md) | [**getAlbumInfo**](doc/AlbumApi.md#getalbuminfo) | **GET** /album/{id} |
+[*AlbumApi*](doc/AlbumApi.md) | [**getAllAlbums**](doc/AlbumApi.md#getallalbums) | **GET** /album |
+[*AlbumApi*](doc/AlbumApi.md) | [**removeAssetFromAlbum**](doc/AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets |
+[*AlbumApi*](doc/AlbumApi.md) | [**removeUserFromAlbum**](doc/AlbumApi.md#removeuserfromalbum) | **DELETE** /album/{id}/user/{userId} |
+[*AlbumApi*](doc/AlbumApi.md) | [**updateAlbumInfo**](doc/AlbumApi.md#updatealbuminfo) | **PATCH** /album/{id} |
+[*AssetApi*](doc/AssetApi.md) | [**checkBulkUpload**](doc/AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check |
+[*AssetApi*](doc/AssetApi.md) | [**checkExistingAssets**](doc/AssetApi.md#checkexistingassets) | **POST** /asset/exist |
+[*AssetApi*](doc/AssetApi.md) | [**deleteAssets**](doc/AssetApi.md#deleteassets) | **DELETE** /asset |
+[*AssetApi*](doc/AssetApi.md) | [**getAllAssets**](doc/AssetApi.md#getallassets) | **GET** /asset |
+[*AssetApi*](doc/AssetApi.md) | [**getAllUserAssetsByDeviceId**](doc/AssetApi.md#getalluserassetsbydeviceid) | **GET** /asset/device/{deviceId} |
+[*AssetApi*](doc/AssetApi.md) | [**getAssetInfo**](doc/AssetApi.md#getassetinfo) | **GET** /asset/{id} |
+[*AssetApi*](doc/AssetApi.md) | [**getAssetSearchTerms**](doc/AssetApi.md#getassetsearchterms) | **GET** /asset/search-terms |
+[*AssetApi*](doc/AssetApi.md) | [**getAssetStatistics**](doc/AssetApi.md#getassetstatistics) | **GET** /asset/statistics |
+[*AssetApi*](doc/AssetApi.md) | [**getAssetThumbnail**](doc/AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} |
+[*AssetApi*](doc/AssetApi.md) | [**getCuratedLocations**](doc/AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
+[*AssetApi*](doc/AssetApi.md) | [**getCuratedObjects**](doc/AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
+[*AssetApi*](doc/AssetApi.md) | [**getMapMarkers**](doc/AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
+[*AssetApi*](doc/AssetApi.md) | [**getMemoryLane**](doc/AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
+[*AssetApi*](doc/AssetApi.md) | [**getRandom**](doc/AssetApi.md#getrandom) | **GET** /asset/random |
+[*AssetApi*](doc/AssetApi.md) | [**runAssetJobs**](doc/AssetApi.md#runassetjobs) | **POST** /asset/jobs |
+[*AssetApi*](doc/AssetApi.md) | [**searchAssets**](doc/AssetApi.md#searchassets) | **GET** /assets |
+[*AssetApi*](doc/AssetApi.md) | [**serveFile**](doc/AssetApi.md#servefile) | **GET** /asset/file/{id} |
+[*AssetApi*](doc/AssetApi.md) | [**updateAsset**](doc/AssetApi.md#updateasset) | **PUT** /asset/{id} |
+[*AssetApi*](doc/AssetApi.md) | [**updateAssets**](doc/AssetApi.md#updateassets) | **PUT** /asset |
+[*AssetApi*](doc/AssetApi.md) | [**updateStackParent**](doc/AssetApi.md#updatestackparent) | **PUT** /asset/stack/parent |
+[*AssetApi*](doc/AssetApi.md) | [**uploadFile**](doc/AssetApi.md#uploadfile) | **POST** /asset/upload |
+[*AuditApi*](doc/AuditApi.md) | [**getAuditDeletes**](doc/AuditApi.md#getauditdeletes) | **GET** /audit/deletes |
+[*AuthenticationApi*](doc/AuthenticationApi.md) | [**changePassword**](doc/AuthenticationApi.md#changepassword) | **POST** /auth/change-password |
+[*AuthenticationApi*](doc/AuthenticationApi.md) | [**login**](doc/AuthenticationApi.md#login) | **POST** /auth/login |
+[*AuthenticationApi*](doc/AuthenticationApi.md) | [**logout**](doc/AuthenticationApi.md#logout) | **POST** /auth/logout |
+[*AuthenticationApi*](doc/AuthenticationApi.md) | [**signUpAdmin**](doc/AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up |
+[*AuthenticationApi*](doc/AuthenticationApi.md) | [**validateAccessToken**](doc/AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken |
+[*DownloadApi*](doc/DownloadApi.md) | [**downloadArchive**](doc/DownloadApi.md#downloadarchive) | **POST** /download/archive |
+[*DownloadApi*](doc/DownloadApi.md) | [**downloadFile**](doc/DownloadApi.md#downloadfile) | **POST** /download/asset/{id} |
+[*DownloadApi*](doc/DownloadApi.md) | [**getDownloadInfo**](doc/DownloadApi.md#getdownloadinfo) | **POST** /download/info |
+[*FaceApi*](doc/FaceApi.md) | [**getFaces**](doc/FaceApi.md#getfaces) | **GET** /face |
+[*FaceApi*](doc/FaceApi.md) | [**reassignFacesById**](doc/FaceApi.md#reassignfacesbyid) | **PUT** /face/{id} |
+[*FileReportApi*](doc/FileReportApi.md) | [**fixAuditFiles**](doc/FileReportApi.md#fixauditfiles) | **POST** /report/fix |
+[*FileReportApi*](doc/FileReportApi.md) | [**getAuditFiles**](doc/FileReportApi.md#getauditfiles) | **GET** /report |
+[*FileReportApi*](doc/FileReportApi.md) | [**getFileChecksums**](doc/FileReportApi.md#getfilechecksums) | **POST** /report/checksum |
+[*JobApi*](doc/JobApi.md) | [**getAllJobsStatus**](doc/JobApi.md#getalljobsstatus) | **GET** /jobs |
+[*JobApi*](doc/JobApi.md) | [**sendJobCommand**](doc/JobApi.md#sendjobcommand) | **PUT** /jobs/{id} |
+[*LibraryApi*](doc/LibraryApi.md) | [**createLibrary**](doc/LibraryApi.md#createlibrary) | **POST** /library |
+[*LibraryApi*](doc/LibraryApi.md) | [**deleteLibrary**](doc/LibraryApi.md#deletelibrary) | **DELETE** /library/{id} |
+[*LibraryApi*](doc/LibraryApi.md) | [**getAllLibraries**](doc/LibraryApi.md#getalllibraries) | **GET** /library |
+[*LibraryApi*](doc/LibraryApi.md) | [**getLibrary**](doc/LibraryApi.md#getlibrary) | **GET** /library/{id} |
+[*LibraryApi*](doc/LibraryApi.md) | [**getLibraryStatistics**](doc/LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
+[*LibraryApi*](doc/LibraryApi.md) | [**removeOfflineFiles**](doc/LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
+[*LibraryApi*](doc/LibraryApi.md) | [**scanLibrary**](doc/LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan |
+[*LibraryApi*](doc/LibraryApi.md) | [**updateLibrary**](doc/LibraryApi.md#updatelibrary) | **PUT** /library/{id} |
+[*LibraryApi*](doc/LibraryApi.md) | [**validate**](doc/LibraryApi.md#validate) | **POST** /library/{id}/validate |
+[*MemoryApi*](doc/MemoryApi.md) | [**addMemoryAssets**](doc/MemoryApi.md#addmemoryassets) | **PUT** /memories/{id}/assets |
+[*MemoryApi*](doc/MemoryApi.md) | [**createMemory**](doc/MemoryApi.md#creatememory) | **POST** /memories |
+[*MemoryApi*](doc/MemoryApi.md) | [**deleteMemory**](doc/MemoryApi.md#deletememory) | **DELETE** /memories/{id} |
+[*MemoryApi*](doc/MemoryApi.md) | [**getMemory**](doc/MemoryApi.md#getmemory) | **GET** /memories/{id} |
+[*MemoryApi*](doc/MemoryApi.md) | [**removeMemoryAssets**](doc/MemoryApi.md#removememoryassets) | **DELETE** /memories/{id}/assets |
+[*MemoryApi*](doc/MemoryApi.md) | [**searchMemories**](doc/MemoryApi.md#searchmemories) | **GET** /memories |
+[*MemoryApi*](doc/MemoryApi.md) | [**updateMemory**](doc/MemoryApi.md#updatememory) | **PUT** /memories/{id} |
+[*OAuthApi*](doc/OAuthApi.md) | [**finishOAuth**](doc/OAuthApi.md#finishoauth) | **POST** /oauth/callback |
+[*OAuthApi*](doc/OAuthApi.md) | [**linkOAuthAccount**](doc/OAuthApi.md#linkoauthaccount) | **POST** /oauth/link |
+[*OAuthApi*](doc/OAuthApi.md) | [**redirectOAuthToMobile**](doc/OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect |
+[*OAuthApi*](doc/OAuthApi.md) | [**startOAuth**](doc/OAuthApi.md#startoauth) | **POST** /oauth/authorize |
+[*OAuthApi*](doc/OAuthApi.md) | [**unlinkOAuthAccount**](doc/OAuthApi.md#unlinkoauthaccount) | **POST** /oauth/unlink |
+[*PartnerApi*](doc/PartnerApi.md) | [**createPartner**](doc/PartnerApi.md#createpartner) | **POST** /partner/{id} |
+[*PartnerApi*](doc/PartnerApi.md) | [**getPartners**](doc/PartnerApi.md#getpartners) | **GET** /partner |
+[*PartnerApi*](doc/PartnerApi.md) | [**removePartner**](doc/PartnerApi.md#removepartner) | **DELETE** /partner/{id} |
+[*PartnerApi*](doc/PartnerApi.md) | [**updatePartner**](doc/PartnerApi.md#updatepartner) | **PUT** /partner/{id} |
+[*PersonApi*](doc/PersonApi.md) | [**createPerson**](doc/PersonApi.md#createperson) | **POST** /person |
+[*PersonApi*](doc/PersonApi.md) | [**getAllPeople**](doc/PersonApi.md#getallpeople) | **GET** /person |
+[*PersonApi*](doc/PersonApi.md) | [**getPerson**](doc/PersonApi.md#getperson) | **GET** /person/{id} |
+[*PersonApi*](doc/PersonApi.md) | [**getPersonAssets**](doc/PersonApi.md#getpersonassets) | **GET** /person/{id}/assets |
+[*PersonApi*](doc/PersonApi.md) | [**getPersonStatistics**](doc/PersonApi.md#getpersonstatistics) | **GET** /person/{id}/statistics |
+[*PersonApi*](doc/PersonApi.md) | [**getPersonThumbnail**](doc/PersonApi.md#getpersonthumbnail) | **GET** /person/{id}/thumbnail |
+[*PersonApi*](doc/PersonApi.md) | [**mergePerson**](doc/PersonApi.md#mergeperson) | **POST** /person/{id}/merge |
+[*PersonApi*](doc/PersonApi.md) | [**reassignFaces**](doc/PersonApi.md#reassignfaces) | **PUT** /person/{id}/reassign |
+[*PersonApi*](doc/PersonApi.md) | [**updatePeople**](doc/PersonApi.md#updatepeople) | **PUT** /person |
+[*PersonApi*](doc/PersonApi.md) | [**updatePerson**](doc/PersonApi.md#updateperson) | **PUT** /person/{id} |
+[*SearchApi*](doc/SearchApi.md) | [**getAssetsByCity**](doc/SearchApi.md#getassetsbycity) | **GET** /search/cities |
+[*SearchApi*](doc/SearchApi.md) | [**getExploreData**](doc/SearchApi.md#getexploredata) | **GET** /search/explore |
+[*SearchApi*](doc/SearchApi.md) | [**getSearchSuggestions**](doc/SearchApi.md#getsearchsuggestions) | **GET** /search/suggestions |
+[*SearchApi*](doc/SearchApi.md) | [**search**](doc/SearchApi.md#search) | **GET** /search |
+[*SearchApi*](doc/SearchApi.md) | [**searchMetadata**](doc/SearchApi.md#searchmetadata) | **POST** /search/metadata |
+[*SearchApi*](doc/SearchApi.md) | [**searchPerson**](doc/SearchApi.md#searchperson) | **GET** /search/person |
+[*SearchApi*](doc/SearchApi.md) | [**searchPlaces**](doc/SearchApi.md#searchplaces) | **GET** /search/places |
+[*SearchApi*](doc/SearchApi.md) | [**searchSmart**](doc/SearchApi.md#searchsmart) | **POST** /search/smart |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**getServerConfig**](doc/ServerInfoApi.md#getserverconfig) | **GET** /server-info/config |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**getServerFeatures**](doc/ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**getServerInfo**](doc/ServerInfoApi.md#getserverinfo) | **GET** /server-info |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**getServerStatistics**](doc/ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**getServerVersion**](doc/ServerInfoApi.md#getserverversion) | **GET** /server-info/version |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**getSupportedMediaTypes**](doc/ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**getTheme**](doc/ServerInfoApi.md#gettheme) | **GET** /server-info/theme |
+[*ServerInfoApi*](doc/ServerInfoApi.md) | [**pingServer**](doc/ServerInfoApi.md#pingserver) | **GET** /server-info/ping |
+[*SessionsApi*](doc/SessionsApi.md) | [**deleteAllSessions**](doc/SessionsApi.md#deleteallsessions) | **DELETE** /sessions |
+[*SessionsApi*](doc/SessionsApi.md) | [**deleteSession**](doc/SessionsApi.md#deletesession) | **DELETE** /sessions/{id} |
+[*SessionsApi*](doc/SessionsApi.md) | [**getSessions**](doc/SessionsApi.md#getsessions) | **GET** /sessions |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**addSharedLinkAssets**](doc/SharedLinkApi.md#addsharedlinkassets) | **PUT** /shared-link/{id}/assets |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**createSharedLink**](doc/SharedLinkApi.md#createsharedlink) | **POST** /shared-link |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**getAllSharedLinks**](doc/SharedLinkApi.md#getallsharedlinks) | **GET** /shared-link |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**getMySharedLink**](doc/SharedLinkApi.md#getmysharedlink) | **GET** /shared-link/me |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**getSharedLinkById**](doc/SharedLinkApi.md#getsharedlinkbyid) | **GET** /shared-link/{id} |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**removeSharedLink**](doc/SharedLinkApi.md#removesharedlink) | **DELETE** /shared-link/{id} |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**removeSharedLinkAssets**](doc/SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets |
+[*SharedLinkApi*](doc/SharedLinkApi.md) | [**updateSharedLink**](doc/SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} |
+[*SyncApi*](doc/SyncApi.md) | [**getAllForUserFullSync**](doc/SyncApi.md#getallforuserfullsync) | **GET** /sync/full-sync |
+[*SyncApi*](doc/SyncApi.md) | [**getDeltaSync**](doc/SyncApi.md#getdeltasync) | **GET** /sync/delta-sync |
+[*SystemConfigApi*](doc/SystemConfigApi.md) | [**getConfig**](doc/SystemConfigApi.md#getconfig) | **GET** /system-config |
+[*SystemConfigApi*](doc/SystemConfigApi.md) | [**getConfigDefaults**](doc/SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults |
+[*SystemConfigApi*](doc/SystemConfigApi.md) | [**getMapStyle**](doc/SystemConfigApi.md#getmapstyle) | **GET** /system-config/map/style.json |
+[*SystemConfigApi*](doc/SystemConfigApi.md) | [**getStorageTemplateOptions**](doc/SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options |
+[*SystemConfigApi*](doc/SystemConfigApi.md) | [**updateConfig**](doc/SystemConfigApi.md#updateconfig) | **PUT** /system-config |
+[*SystemMetadataApi*](doc/SystemMetadataApi.md) | [**getAdminOnboarding**](doc/SystemMetadataApi.md#getadminonboarding) | **GET** /system-metadata/admin-onboarding |
+[*SystemMetadataApi*](doc/SystemMetadataApi.md) | [**getReverseGeocodingState**](doc/SystemMetadataApi.md#getreversegeocodingstate) | **GET** /system-metadata/reverse-geocoding-state |
+[*SystemMetadataApi*](doc/SystemMetadataApi.md) | [**updateAdminOnboarding**](doc/SystemMetadataApi.md#updateadminonboarding) | **POST** /system-metadata/admin-onboarding |
+[*TagApi*](doc/TagApi.md) | [**createTag**](doc/TagApi.md#createtag) | **POST** /tag |
+[*TagApi*](doc/TagApi.md) | [**deleteTag**](doc/TagApi.md#deletetag) | **DELETE** /tag/{id} |
+[*TagApi*](doc/TagApi.md) | [**getAllTags**](doc/TagApi.md#getalltags) | **GET** /tag |
+[*TagApi*](doc/TagApi.md) | [**getTagAssets**](doc/TagApi.md#gettagassets) | **GET** /tag/{id}/assets |
+[*TagApi*](doc/TagApi.md) | [**getTagById**](doc/TagApi.md#gettagbyid) | **GET** /tag/{id} |
+[*TagApi*](doc/TagApi.md) | [**tagAssets**](doc/TagApi.md#tagassets) | **PUT** /tag/{id}/assets |
+[*TagApi*](doc/TagApi.md) | [**untagAssets**](doc/TagApi.md#untagassets) | **DELETE** /tag/{id}/assets |
+[*TagApi*](doc/TagApi.md) | [**updateTag**](doc/TagApi.md#updatetag) | **PATCH** /tag/{id} |
+[*TimelineApi*](doc/TimelineApi.md) | [**getTimeBucket**](doc/TimelineApi.md#gettimebucket) | **GET** /timeline/bucket |
+[*TimelineApi*](doc/TimelineApi.md) | [**getTimeBuckets**](doc/TimelineApi.md#gettimebuckets) | **GET** /timeline/buckets |
+[*TrashApi*](doc/TrashApi.md) | [**emptyTrash**](doc/TrashApi.md#emptytrash) | **POST** /trash/empty |
+[*TrashApi*](doc/TrashApi.md) | [**restoreAssets**](doc/TrashApi.md#restoreassets) | **POST** /trash/restore/assets |
+[*TrashApi*](doc/TrashApi.md) | [**restoreTrash**](doc/TrashApi.md#restoretrash) | **POST** /trash/restore |
+[*UserApi*](doc/UserApi.md) | [**createProfileImage**](doc/UserApi.md#createprofileimage) | **POST** /user/profile-image |
+[*UserApi*](doc/UserApi.md) | [**createUser**](doc/UserApi.md#createuser) | **POST** /user |
+[*UserApi*](doc/UserApi.md) | [**deleteProfileImage**](doc/UserApi.md#deleteprofileimage) | **DELETE** /user/profile-image |
+[*UserApi*](doc/UserApi.md) | [**deleteUser**](doc/UserApi.md#deleteuser) | **DELETE** /user/{id} |
+[*UserApi*](doc/UserApi.md) | [**getAllUsers**](doc/UserApi.md#getallusers) | **GET** /user |
+[*UserApi*](doc/UserApi.md) | [**getMyUserInfo**](doc/UserApi.md#getmyuserinfo) | **GET** /user/me |
+[*UserApi*](doc/UserApi.md) | [**getProfileImage**](doc/UserApi.md#getprofileimage) | **GET** /user/profile-image/{id} |
+[*UserApi*](doc/UserApi.md) | [**getUserById**](doc/UserApi.md#getuserbyid) | **GET** /user/info/{id} |
+[*UserApi*](doc/UserApi.md) | [**restoreUser**](doc/UserApi.md#restoreuser) | **POST** /user/{id}/restore |
+[*UserApi*](doc/UserApi.md) | [**updateUser**](doc/UserApi.md#updateuser) | **PUT** /user |
+
+
+## Documentation For Models
+
+ - [APIKeyCreateDto](doc/APIKeyCreateDto.md)
+ - [APIKeyCreateResponseDto](doc/APIKeyCreateResponseDto.md)
+ - [APIKeyResponseDto](doc/APIKeyResponseDto.md)
+ - [APIKeyUpdateDto](doc/APIKeyUpdateDto.md)
+ - [ActivityCreateDto](doc/ActivityCreateDto.md)
+ - [ActivityResponseDto](doc/ActivityResponseDto.md)
+ - [ActivityStatisticsResponseDto](doc/ActivityStatisticsResponseDto.md)
+ - [AddUsersDto](doc/AddUsersDto.md)
+ - [AdminOnboardingUpdateDto](doc/AdminOnboardingUpdateDto.md)
+ - [AlbumCountResponseDto](doc/AlbumCountResponseDto.md)
+ - [AlbumResponseDto](doc/AlbumResponseDto.md)
+ - [AllJobStatusResponseDto](doc/AllJobStatusResponseDto.md)
+ - [AssetBulkDeleteDto](doc/AssetBulkDeleteDto.md)
+ - [AssetBulkUpdateDto](doc/AssetBulkUpdateDto.md)
+ - [AssetBulkUploadCheckDto](doc/AssetBulkUploadCheckDto.md)
+ - [AssetBulkUploadCheckItem](doc/AssetBulkUploadCheckItem.md)
+ - [AssetBulkUploadCheckResponseDto](doc/AssetBulkUploadCheckResponseDto.md)
+ - [AssetBulkUploadCheckResult](doc/AssetBulkUploadCheckResult.md)
+ - [AssetDeltaSyncResponseDto](doc/AssetDeltaSyncResponseDto.md)
+ - [AssetFaceResponseDto](doc/AssetFaceResponseDto.md)
+ - [AssetFaceUpdateDto](doc/AssetFaceUpdateDto.md)
+ - [AssetFaceUpdateItem](doc/AssetFaceUpdateItem.md)
+ - [AssetFaceWithoutPersonResponseDto](doc/AssetFaceWithoutPersonResponseDto.md)
+ - [AssetFileUploadResponseDto](doc/AssetFileUploadResponseDto.md)
+ - [AssetIdsDto](doc/AssetIdsDto.md)
+ - [AssetIdsResponseDto](doc/AssetIdsResponseDto.md)
+ - [AssetJobName](doc/AssetJobName.md)
+ - [AssetJobsDto](doc/AssetJobsDto.md)
+ - [AssetOrder](doc/AssetOrder.md)
+ - [AssetResponseDto](doc/AssetResponseDto.md)
+ - [AssetStatsResponseDto](doc/AssetStatsResponseDto.md)
+ - [AssetTypeEnum](doc/AssetTypeEnum.md)
+ - [AudioCodec](doc/AudioCodec.md)
+ - [AuditDeletesResponseDto](doc/AuditDeletesResponseDto.md)
+ - [BulkIdResponseDto](doc/BulkIdResponseDto.md)
+ - [BulkIdsDto](doc/BulkIdsDto.md)
+ - [CLIPConfig](doc/CLIPConfig.md)
+ - [CLIPMode](doc/CLIPMode.md)
+ - [CQMode](doc/CQMode.md)
+ - [ChangePasswordDto](doc/ChangePasswordDto.md)
+ - [CheckExistingAssetsDto](doc/CheckExistingAssetsDto.md)
+ - [CheckExistingAssetsResponseDto](doc/CheckExistingAssetsResponseDto.md)
+ - [Colorspace](doc/Colorspace.md)
+ - [CreateAlbumDto](doc/CreateAlbumDto.md)
+ - [CreateAssetDto](doc/CreateAssetDto.md)
+ - [CreateLibraryDto](doc/CreateLibraryDto.md)
+ - [CreateProfileImageDto](doc/CreateProfileImageDto.md)
+ - [CreateProfileImageResponseDto](doc/CreateProfileImageResponseDto.md)
+ - [CreateTagDto](doc/CreateTagDto.md)
+ - [CreateUserDto](doc/CreateUserDto.md)
+ - [CuratedLocationsResponseDto](doc/CuratedLocationsResponseDto.md)
+ - [CuratedObjectsResponseDto](doc/CuratedObjectsResponseDto.md)
+ - [DeleteUserDto](doc/DeleteUserDto.md)
+ - [DownloadArchiveInfo](doc/DownloadArchiveInfo.md)
+ - [DownloadInfoDto](doc/DownloadInfoDto.md)
+ - [DownloadResponseDto](doc/DownloadResponseDto.md)
+ - [EntityType](doc/EntityType.md)
+ - [ExifResponseDto](doc/ExifResponseDto.md)
+ - [FaceDto](doc/FaceDto.md)
+ - [FileChecksumDto](doc/FileChecksumDto.md)
+ - [FileChecksumResponseDto](doc/FileChecksumResponseDto.md)
+ - [FileReportDto](doc/FileReportDto.md)
+ - [FileReportFixDto](doc/FileReportFixDto.md)
+ - [FileReportItemDto](doc/FileReportItemDto.md)
+ - [ImageFormat](doc/ImageFormat.md)
+ - [JobCommand](doc/JobCommand.md)
+ - [JobCommandDto](doc/JobCommandDto.md)
+ - [JobCountsDto](doc/JobCountsDto.md)
+ - [JobName](doc/JobName.md)
+ - [JobSettingsDto](doc/JobSettingsDto.md)
+ - [JobStatusDto](doc/JobStatusDto.md)
+ - [LibraryResponseDto](doc/LibraryResponseDto.md)
+ - [LibraryStatsResponseDto](doc/LibraryStatsResponseDto.md)
+ - [LibraryType](doc/LibraryType.md)
+ - [LogLevel](doc/LogLevel.md)
+ - [LoginCredentialDto](doc/LoginCredentialDto.md)
+ - [LoginResponseDto](doc/LoginResponseDto.md)
+ - [LogoutResponseDto](doc/LogoutResponseDto.md)
+ - [MapMarkerResponseDto](doc/MapMarkerResponseDto.md)
+ - [MapTheme](doc/MapTheme.md)
+ - [MemoryCreateDto](doc/MemoryCreateDto.md)
+ - [MemoryLaneResponseDto](doc/MemoryLaneResponseDto.md)
+ - [MemoryResponseDto](doc/MemoryResponseDto.md)
+ - [MemoryType](doc/MemoryType.md)
+ - [MemoryUpdateDto](doc/MemoryUpdateDto.md)
+ - [MergePersonDto](doc/MergePersonDto.md)
+ - [MetadataSearchDto](doc/MetadataSearchDto.md)
+ - [ModelType](doc/ModelType.md)
+ - [OAuthAuthorizeResponseDto](doc/OAuthAuthorizeResponseDto.md)
+ - [OAuthCallbackDto](doc/OAuthCallbackDto.md)
+ - [OAuthConfigDto](doc/OAuthConfigDto.md)
+ - [OnThisDayDto](doc/OnThisDayDto.md)
+ - [PartnerResponseDto](doc/PartnerResponseDto.md)
+ - [PathEntityType](doc/PathEntityType.md)
+ - [PathType](doc/PathType.md)
+ - [PeopleResponseDto](doc/PeopleResponseDto.md)
+ - [PeopleUpdateDto](doc/PeopleUpdateDto.md)
+ - [PeopleUpdateItem](doc/PeopleUpdateItem.md)
+ - [PersonCreateDto](doc/PersonCreateDto.md)
+ - [PersonResponseDto](doc/PersonResponseDto.md)
+ - [PersonStatisticsResponseDto](doc/PersonStatisticsResponseDto.md)
+ - [PersonUpdateDto](doc/PersonUpdateDto.md)
+ - [PersonWithFacesResponseDto](doc/PersonWithFacesResponseDto.md)
+ - [PlacesResponseDto](doc/PlacesResponseDto.md)
+ - [QueueStatusDto](doc/QueueStatusDto.md)
+ - [ReactionLevel](doc/ReactionLevel.md)
+ - [ReactionType](doc/ReactionType.md)
+ - [RecognitionConfig](doc/RecognitionConfig.md)
+ - [ReverseGeocodingStateResponseDto](doc/ReverseGeocodingStateResponseDto.md)
+ - [ScanLibraryDto](doc/ScanLibraryDto.md)
+ - [SearchAlbumResponseDto](doc/SearchAlbumResponseDto.md)
+ - [SearchAssetResponseDto](doc/SearchAssetResponseDto.md)
+ - [SearchExploreItem](doc/SearchExploreItem.md)
+ - [SearchExploreResponseDto](doc/SearchExploreResponseDto.md)
+ - [SearchFacetCountResponseDto](doc/SearchFacetCountResponseDto.md)
+ - [SearchFacetResponseDto](doc/SearchFacetResponseDto.md)
+ - [SearchResponseDto](doc/SearchResponseDto.md)
+ - [SearchSuggestionType](doc/SearchSuggestionType.md)
+ - [ServerConfigDto](doc/ServerConfigDto.md)
+ - [ServerFeaturesDto](doc/ServerFeaturesDto.md)
+ - [ServerInfoResponseDto](doc/ServerInfoResponseDto.md)
+ - [ServerMediaTypesResponseDto](doc/ServerMediaTypesResponseDto.md)
+ - [ServerPingResponse](doc/ServerPingResponse.md)
+ - [ServerStatsResponseDto](doc/ServerStatsResponseDto.md)
+ - [ServerThemeDto](doc/ServerThemeDto.md)
+ - [ServerVersionResponseDto](doc/ServerVersionResponseDto.md)
+ - [SessionResponseDto](doc/SessionResponseDto.md)
+ - [SharedLinkCreateDto](doc/SharedLinkCreateDto.md)
+ - [SharedLinkEditDto](doc/SharedLinkEditDto.md)
+ - [SharedLinkResponseDto](doc/SharedLinkResponseDto.md)
+ - [SharedLinkType](doc/SharedLinkType.md)
+ - [SignUpDto](doc/SignUpDto.md)
+ - [SmartInfoResponseDto](doc/SmartInfoResponseDto.md)
+ - [SmartSearchDto](doc/SmartSearchDto.md)
+ - [SystemConfigDto](doc/SystemConfigDto.md)
+ - [SystemConfigFFmpegDto](doc/SystemConfigFFmpegDto.md)
+ - [SystemConfigImageDto](doc/SystemConfigImageDto.md)
+ - [SystemConfigJobDto](doc/SystemConfigJobDto.md)
+ - [SystemConfigLibraryDto](doc/SystemConfigLibraryDto.md)
+ - [SystemConfigLibraryScanDto](doc/SystemConfigLibraryScanDto.md)
+ - [SystemConfigLibraryWatchDto](doc/SystemConfigLibraryWatchDto.md)
+ - [SystemConfigLoggingDto](doc/SystemConfigLoggingDto.md)
+ - [SystemConfigMachineLearningDto](doc/SystemConfigMachineLearningDto.md)
+ - [SystemConfigMapDto](doc/SystemConfigMapDto.md)
+ - [SystemConfigNewVersionCheckDto](doc/SystemConfigNewVersionCheckDto.md)
+ - [SystemConfigOAuthDto](doc/SystemConfigOAuthDto.md)
+ - [SystemConfigPasswordLoginDto](doc/SystemConfigPasswordLoginDto.md)
+ - [SystemConfigReverseGeocodingDto](doc/SystemConfigReverseGeocodingDto.md)
+ - [SystemConfigServerDto](doc/SystemConfigServerDto.md)
+ - [SystemConfigStorageTemplateDto](doc/SystemConfigStorageTemplateDto.md)
+ - [SystemConfigTemplateStorageOptionDto](doc/SystemConfigTemplateStorageOptionDto.md)
+ - [SystemConfigThemeDto](doc/SystemConfigThemeDto.md)
+ - [SystemConfigTrashDto](doc/SystemConfigTrashDto.md)
+ - [SystemConfigUserDto](doc/SystemConfigUserDto.md)
+ - [TagResponseDto](doc/TagResponseDto.md)
+ - [TagTypeEnum](doc/TagTypeEnum.md)
+ - [ThumbnailFormat](doc/ThumbnailFormat.md)
+ - [TimeBucketResponseDto](doc/TimeBucketResponseDto.md)
+ - [TimeBucketSize](doc/TimeBucketSize.md)
+ - [ToneMapping](doc/ToneMapping.md)
+ - [TranscodeHWAccel](doc/TranscodeHWAccel.md)
+ - [TranscodePolicy](doc/TranscodePolicy.md)
+ - [UpdateAlbumDto](doc/UpdateAlbumDto.md)
+ - [UpdateAssetDto](doc/UpdateAssetDto.md)
+ - [UpdateLibraryDto](doc/UpdateLibraryDto.md)
+ - [UpdatePartnerDto](doc/UpdatePartnerDto.md)
+ - [UpdateStackParentDto](doc/UpdateStackParentDto.md)
+ - [UpdateTagDto](doc/UpdateTagDto.md)
+ - [UpdateUserDto](doc/UpdateUserDto.md)
+ - [UsageByUserDto](doc/UsageByUserDto.md)
+ - [UserAvatarColor](doc/UserAvatarColor.md)
+ - [UserDto](doc/UserDto.md)
+ - [UserResponseDto](doc/UserResponseDto.md)
+ - [UserStatus](doc/UserStatus.md)
+ - [ValidateAccessTokenResponseDto](doc/ValidateAccessTokenResponseDto.md)
+ - [ValidateLibraryDto](doc/ValidateLibraryDto.md)
+ - [ValidateLibraryImportPathResponseDto](doc/ValidateLibraryImportPathResponseDto.md)
+ - [ValidateLibraryResponseDto](doc/ValidateLibraryResponseDto.md)
+ - [VideoCodec](doc/VideoCodec.md)
+
+
+## Documentation For Authorization
+
+
+Authentication schemes defined for the API:
+### bearer
+
+- **Type**: HTTP Bearer Token authentication (JWT)
+
+### cookie
+
+- **Type**: API key
+- **API key parameter name**: immich_access_token
+- **Location**:
+
+### api_key
+
+- **Type**: API key
+- **API key parameter name**: x-api-key
+- **Location**: HTTP header
+
+
+## Author
+
+
+
diff --git a/mobile-v2/openapi/lib/openapi.dart b/mobile-v2/openapi/lib/openapi.dart
new file mode 100644
index 0000000000..bb60b4ce8d
--- /dev/null
+++ b/mobile-v2/openapi/lib/openapi.dart
@@ -0,0 +1,218 @@
+//
+// AUTO-GENERATED FILE, DO NOT MODIFY!
+//
+
+export 'package:openapi/src/api.dart';
+export 'package:openapi/src/auth/api_key_auth.dart';
+export 'package:openapi/src/auth/basic_auth.dart';
+export 'package:openapi/src/auth/oauth.dart';
+export 'package:openapi/src/serializers.dart';
+export 'package:openapi/src/model/date.dart';
+
+export 'package:openapi/src/api/api_key_api.dart';
+export 'package:openapi/src/api/activity_api.dart';
+export 'package:openapi/src/api/album_api.dart';
+export 'package:openapi/src/api/asset_api.dart';
+export 'package:openapi/src/api/audit_api.dart';
+export 'package:openapi/src/api/authentication_api.dart';
+export 'package:openapi/src/api/download_api.dart';
+export 'package:openapi/src/api/face_api.dart';
+export 'package:openapi/src/api/file_report_api.dart';
+export 'package:openapi/src/api/job_api.dart';
+export 'package:openapi/src/api/library_api.dart';
+export 'package:openapi/src/api/memory_api.dart';
+export 'package:openapi/src/api/o_auth_api.dart';
+export 'package:openapi/src/api/partner_api.dart';
+export 'package:openapi/src/api/person_api.dart';
+export 'package:openapi/src/api/search_api.dart';
+export 'package:openapi/src/api/server_info_api.dart';
+export 'package:openapi/src/api/sessions_api.dart';
+export 'package:openapi/src/api/shared_link_api.dart';
+export 'package:openapi/src/api/sync_api.dart';
+export 'package:openapi/src/api/system_config_api.dart';
+export 'package:openapi/src/api/system_metadata_api.dart';
+export 'package:openapi/src/api/tag_api.dart';
+export 'package:openapi/src/api/timeline_api.dart';
+export 'package:openapi/src/api/trash_api.dart';
+export 'package:openapi/src/api/user_api.dart';
+
+export 'package:openapi/src/model/api_key_create_dto.dart';
+export 'package:openapi/src/model/api_key_create_response_dto.dart';
+export 'package:openapi/src/model/api_key_response_dto.dart';
+export 'package:openapi/src/model/api_key_update_dto.dart';
+export 'package:openapi/src/model/activity_create_dto.dart';
+export 'package:openapi/src/model/activity_response_dto.dart';
+export 'package:openapi/src/model/activity_statistics_response_dto.dart';
+export 'package:openapi/src/model/add_users_dto.dart';
+export 'package:openapi/src/model/admin_onboarding_update_dto.dart';
+export 'package:openapi/src/model/album_count_response_dto.dart';
+export 'package:openapi/src/model/album_response_dto.dart';
+export 'package:openapi/src/model/all_job_status_response_dto.dart';
+export 'package:openapi/src/model/asset_bulk_delete_dto.dart';
+export 'package:openapi/src/model/asset_bulk_update_dto.dart';
+export 'package:openapi/src/model/asset_bulk_upload_check_dto.dart';
+export 'package:openapi/src/model/asset_bulk_upload_check_item.dart';
+export 'package:openapi/src/model/asset_bulk_upload_check_response_dto.dart';
+export 'package:openapi/src/model/asset_bulk_upload_check_result.dart';
+export 'package:openapi/src/model/asset_delta_sync_response_dto.dart';
+export 'package:openapi/src/model/asset_face_response_dto.dart';
+export 'package:openapi/src/model/asset_face_update_dto.dart';
+export 'package:openapi/src/model/asset_face_update_item.dart';
+export 'package:openapi/src/model/asset_face_without_person_response_dto.dart';
+export 'package:openapi/src/model/asset_file_upload_response_dto.dart';
+export 'package:openapi/src/model/asset_ids_dto.dart';
+export 'package:openapi/src/model/asset_ids_response_dto.dart';
+export 'package:openapi/src/model/asset_job_name.dart';
+export 'package:openapi/src/model/asset_jobs_dto.dart';
+export 'package:openapi/src/model/asset_order.dart';
+export 'package:openapi/src/model/asset_response_dto.dart';
+export 'package:openapi/src/model/asset_stats_response_dto.dart';
+export 'package:openapi/src/model/asset_type_enum.dart';
+export 'package:openapi/src/model/audio_codec.dart';
+export 'package:openapi/src/model/audit_deletes_response_dto.dart';
+export 'package:openapi/src/model/bulk_id_response_dto.dart';
+export 'package:openapi/src/model/bulk_ids_dto.dart';
+export 'package:openapi/src/model/clip_config.dart';
+export 'package:openapi/src/model/clip_mode.dart';
+export 'package:openapi/src/model/cq_mode.dart';
+export 'package:openapi/src/model/change_password_dto.dart';
+export 'package:openapi/src/model/check_existing_assets_dto.dart';
+export 'package:openapi/src/model/check_existing_assets_response_dto.dart';
+export 'package:openapi/src/model/colorspace.dart';
+export 'package:openapi/src/model/create_album_dto.dart';
+export 'package:openapi/src/model/create_asset_dto.dart';
+export 'package:openapi/src/model/create_library_dto.dart';
+export 'package:openapi/src/model/create_profile_image_dto.dart';
+export 'package:openapi/src/model/create_profile_image_response_dto.dart';
+export 'package:openapi/src/model/create_tag_dto.dart';
+export 'package:openapi/src/model/create_user_dto.dart';
+export 'package:openapi/src/model/curated_locations_response_dto.dart';
+export 'package:openapi/src/model/curated_objects_response_dto.dart';
+export 'package:openapi/src/model/delete_user_dto.dart';
+export 'package:openapi/src/model/download_archive_info.dart';
+export 'package:openapi/src/model/download_info_dto.dart';
+export 'package:openapi/src/model/download_response_dto.dart';
+export 'package:openapi/src/model/entity_type.dart';
+export 'package:openapi/src/model/exif_response_dto.dart';
+export 'package:openapi/src/model/face_dto.dart';
+export 'package:openapi/src/model/file_checksum_dto.dart';
+export 'package:openapi/src/model/file_checksum_response_dto.dart';
+export 'package:openapi/src/model/file_report_dto.dart';
+export 'package:openapi/src/model/file_report_fix_dto.dart';
+export 'package:openapi/src/model/file_report_item_dto.dart';
+export 'package:openapi/src/model/image_format.dart';
+export 'package:openapi/src/model/job_command.dart';
+export 'package:openapi/src/model/job_command_dto.dart';
+export 'package:openapi/src/model/job_counts_dto.dart';
+export 'package:openapi/src/model/job_name.dart';
+export 'package:openapi/src/model/job_settings_dto.dart';
+export 'package:openapi/src/model/job_status_dto.dart';
+export 'package:openapi/src/model/library_response_dto.dart';
+export 'package:openapi/src/model/library_stats_response_dto.dart';
+export 'package:openapi/src/model/library_type.dart';
+export 'package:openapi/src/model/log_level.dart';
+export 'package:openapi/src/model/login_credential_dto.dart';
+export 'package:openapi/src/model/login_response_dto.dart';
+export 'package:openapi/src/model/logout_response_dto.dart';
+export 'package:openapi/src/model/map_marker_response_dto.dart';
+export 'package:openapi/src/model/map_theme.dart';
+export 'package:openapi/src/model/memory_create_dto.dart';
+export 'package:openapi/src/model/memory_lane_response_dto.dart';
+export 'package:openapi/src/model/memory_response_dto.dart';
+export 'package:openapi/src/model/memory_type.dart';
+export 'package:openapi/src/model/memory_update_dto.dart';
+export 'package:openapi/src/model/merge_person_dto.dart';
+export 'package:openapi/src/model/metadata_search_dto.dart';
+export 'package:openapi/src/model/model_type.dart';
+export 'package:openapi/src/model/o_auth_authorize_response_dto.dart';
+export 'package:openapi/src/model/o_auth_callback_dto.dart';
+export 'package:openapi/src/model/o_auth_config_dto.dart';
+export 'package:openapi/src/model/on_this_day_dto.dart';
+export 'package:openapi/src/model/partner_response_dto.dart';
+export 'package:openapi/src/model/path_entity_type.dart';
+export 'package:openapi/src/model/path_type.dart';
+export 'package:openapi/src/model/people_response_dto.dart';
+export 'package:openapi/src/model/people_update_dto.dart';
+export 'package:openapi/src/model/people_update_item.dart';
+export 'package:openapi/src/model/person_create_dto.dart';
+export 'package:openapi/src/model/person_response_dto.dart';
+export 'package:openapi/src/model/person_statistics_response_dto.dart';
+export 'package:openapi/src/model/person_update_dto.dart';
+export 'package:openapi/src/model/person_with_faces_response_dto.dart';
+export 'package:openapi/src/model/places_response_dto.dart';
+export 'package:openapi/src/model/queue_status_dto.dart';
+export 'package:openapi/src/model/reaction_level.dart';
+export 'package:openapi/src/model/reaction_type.dart';
+export 'package:openapi/src/model/recognition_config.dart';
+export 'package:openapi/src/model/reverse_geocoding_state_response_dto.dart';
+export 'package:openapi/src/model/scan_library_dto.dart';
+export 'package:openapi/src/model/search_album_response_dto.dart';
+export 'package:openapi/src/model/search_asset_response_dto.dart';
+export 'package:openapi/src/model/search_explore_item.dart';
+export 'package:openapi/src/model/search_explore_response_dto.dart';
+export 'package:openapi/src/model/search_facet_count_response_dto.dart';
+export 'package:openapi/src/model/search_facet_response_dto.dart';
+export 'package:openapi/src/model/search_response_dto.dart';
+export 'package:openapi/src/model/search_suggestion_type.dart';
+export 'package:openapi/src/model/server_config_dto.dart';
+export 'package:openapi/src/model/server_features_dto.dart';
+export 'package:openapi/src/model/server_info_response_dto.dart';
+export 'package:openapi/src/model/server_media_types_response_dto.dart';
+export 'package:openapi/src/model/server_ping_response.dart';
+export 'package:openapi/src/model/server_stats_response_dto.dart';
+export 'package:openapi/src/model/server_theme_dto.dart';
+export 'package:openapi/src/model/server_version_response_dto.dart';
+export 'package:openapi/src/model/session_response_dto.dart';
+export 'package:openapi/src/model/shared_link_create_dto.dart';
+export 'package:openapi/src/model/shared_link_edit_dto.dart';
+export 'package:openapi/src/model/shared_link_response_dto.dart';
+export 'package:openapi/src/model/shared_link_type.dart';
+export 'package:openapi/src/model/sign_up_dto.dart';
+export 'package:openapi/src/model/smart_info_response_dto.dart';
+export 'package:openapi/src/model/smart_search_dto.dart';
+export 'package:openapi/src/model/system_config_dto.dart';
+export 'package:openapi/src/model/system_config_f_fmpeg_dto.dart';
+export 'package:openapi/src/model/system_config_image_dto.dart';
+export 'package:openapi/src/model/system_config_job_dto.dart';
+export 'package:openapi/src/model/system_config_library_dto.dart';
+export 'package:openapi/src/model/system_config_library_scan_dto.dart';
+export 'package:openapi/src/model/system_config_library_watch_dto.dart';
+export 'package:openapi/src/model/system_config_logging_dto.dart';
+export 'package:openapi/src/model/system_config_machine_learning_dto.dart';
+export 'package:openapi/src/model/system_config_map_dto.dart';
+export 'package:openapi/src/model/system_config_new_version_check_dto.dart';
+export 'package:openapi/src/model/system_config_o_auth_dto.dart';
+export 'package:openapi/src/model/system_config_password_login_dto.dart';
+export 'package:openapi/src/model/system_config_reverse_geocoding_dto.dart';
+export 'package:openapi/src/model/system_config_server_dto.dart';
+export 'package:openapi/src/model/system_config_storage_template_dto.dart';
+export 'package:openapi/src/model/system_config_template_storage_option_dto.dart';
+export 'package:openapi/src/model/system_config_theme_dto.dart';
+export 'package:openapi/src/model/system_config_trash_dto.dart';
+export 'package:openapi/src/model/system_config_user_dto.dart';
+export 'package:openapi/src/model/tag_response_dto.dart';
+export 'package:openapi/src/model/tag_type_enum.dart';
+export 'package:openapi/src/model/thumbnail_format.dart';
+export 'package:openapi/src/model/time_bucket_response_dto.dart';
+export 'package:openapi/src/model/time_bucket_size.dart';
+export 'package:openapi/src/model/tone_mapping.dart';
+export 'package:openapi/src/model/transcode_hw_accel.dart';
+export 'package:openapi/src/model/transcode_policy.dart';
+export 'package:openapi/src/model/update_album_dto.dart';
+export 'package:openapi/src/model/update_asset_dto.dart';
+export 'package:openapi/src/model/update_library_dto.dart';
+export 'package:openapi/src/model/update_partner_dto.dart';
+export 'package:openapi/src/model/update_stack_parent_dto.dart';
+export 'package:openapi/src/model/update_tag_dto.dart';
+export 'package:openapi/src/model/update_user_dto.dart';
+export 'package:openapi/src/model/usage_by_user_dto.dart';
+export 'package:openapi/src/model/user_avatar_color.dart';
+export 'package:openapi/src/model/user_dto.dart';
+export 'package:openapi/src/model/user_response_dto.dart';
+export 'package:openapi/src/model/user_status.dart';
+export 'package:openapi/src/model/validate_access_token_response_dto.dart';
+export 'package:openapi/src/model/validate_library_dto.dart';
+export 'package:openapi/src/model/validate_library_import_path_response_dto.dart';
+export 'package:openapi/src/model/validate_library_response_dto.dart';
+export 'package:openapi/src/model/video_codec.dart';
+export 'package:openapi/src/auth/bearer_auth.dart';
diff --git a/mobile-v2/openapi/lib/src/api.dart b/mobile-v2/openapi/lib/src/api.dart
new file mode 100644
index 0000000000..796fbe2a42
--- /dev/null
+++ b/mobile-v2/openapi/lib/src/api.dart
@@ -0,0 +1,248 @@
+//
+// AUTO-GENERATED FILE, DO NOT MODIFY!
+//
+
+import 'package:dio/dio.dart';
+import 'package:built_value/serializer.dart';
+import 'package:openapi/src/serializers.dart';
+import 'package:openapi/src/auth/api_key_auth.dart';
+import 'package:openapi/src/auth/basic_auth.dart';
+import 'package:openapi/src/auth/bearer_auth.dart';
+import 'package:openapi/src/auth/oauth.dart';
+import 'package:openapi/src/api/api_key_api.dart';
+import 'package:openapi/src/api/activity_api.dart';
+import 'package:openapi/src/api/album_api.dart';
+import 'package:openapi/src/api/asset_api.dart';
+import 'package:openapi/src/api/audit_api.dart';
+import 'package:openapi/src/api/authentication_api.dart';
+import 'package:openapi/src/api/download_api.dart';
+import 'package:openapi/src/api/face_api.dart';
+import 'package:openapi/src/api/file_report_api.dart';
+import 'package:openapi/src/api/job_api.dart';
+import 'package:openapi/src/api/library_api.dart';
+import 'package:openapi/src/api/memory_api.dart';
+import 'package:openapi/src/api/o_auth_api.dart';
+import 'package:openapi/src/api/partner_api.dart';
+import 'package:openapi/src/api/person_api.dart';
+import 'package:openapi/src/api/search_api.dart';
+import 'package:openapi/src/api/server_info_api.dart';
+import 'package:openapi/src/api/sessions_api.dart';
+import 'package:openapi/src/api/shared_link_api.dart';
+import 'package:openapi/src/api/sync_api.dart';
+import 'package:openapi/src/api/system_config_api.dart';
+import 'package:openapi/src/api/system_metadata_api.dart';
+import 'package:openapi/src/api/tag_api.dart';
+import 'package:openapi/src/api/timeline_api.dart';
+import 'package:openapi/src/api/trash_api.dart';
+import 'package:openapi/src/api/user_api.dart';
+
+class Openapi {
+ static const String basePath = r'/api';
+
+ final Dio dio;
+ final Serializers serializers;
+
+ Openapi({
+ Dio? dio,
+ Serializers? serializers,
+ String? basePathOverride,
+ List? interceptors,
+ }) : this.serializers = serializers ?? standardSerializers,
+ this.dio = dio ??
+ Dio(BaseOptions(
+ baseUrl: basePathOverride ?? basePath,
+ connectTimeout: const Duration(milliseconds: 5000),
+ receiveTimeout: const Duration(milliseconds: 3000),
+ )) {
+ if (interceptors == null) {
+ this.dio.interceptors.addAll([
+ OAuthInterceptor(),
+ BasicAuthInterceptor(),
+ BearerAuthInterceptor(),
+ ApiKeyAuthInterceptor(),
+ ]);
+ } else {
+ this.dio.interceptors.addAll(interceptors);
+ }
+ }
+
+ void setOAuthToken(String name, String token) {
+ if (this.dio.interceptors.any((i) => i is OAuthInterceptor)) {
+ (this.dio.interceptors.firstWhere((i) => i is OAuthInterceptor) as OAuthInterceptor).tokens[name] = token;
+ }
+ }
+
+ void setBearerAuth(String name, String token) {
+ if (this.dio.interceptors.any((i) => i is BearerAuthInterceptor)) {
+ (this.dio.interceptors.firstWhere((i) => i is BearerAuthInterceptor) as BearerAuthInterceptor).tokens[name] = token;
+ }
+ }
+
+ void setBasicAuth(String name, String username, String password) {
+ if (this.dio.interceptors.any((i) => i is BasicAuthInterceptor)) {
+ (this.dio.interceptors.firstWhere((i) => i is BasicAuthInterceptor) as BasicAuthInterceptor).authInfo[name] = BasicAuthInfo(username, password);
+ }
+ }
+
+ void setApiKey(String name, String apiKey) {
+ if (this.dio.interceptors.any((i) => i is ApiKeyAuthInterceptor)) {
+ (this.dio.interceptors.firstWhere((element) => element is ApiKeyAuthInterceptor) as ApiKeyAuthInterceptor).apiKeys[name] = apiKey;
+ }
+ }
+
+ /// Get APIKeyApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ APIKeyApi getAPIKeyApi() {
+ return APIKeyApi(dio, serializers);
+ }
+
+ /// Get ActivityApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ ActivityApi getActivityApi() {
+ return ActivityApi(dio, serializers);
+ }
+
+ /// Get AlbumApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ AlbumApi getAlbumApi() {
+ return AlbumApi(dio, serializers);
+ }
+
+ /// Get AssetApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ AssetApi getAssetApi() {
+ return AssetApi(dio, serializers);
+ }
+
+ /// Get AuditApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ AuditApi getAuditApi() {
+ return AuditApi(dio, serializers);
+ }
+
+ /// Get AuthenticationApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ AuthenticationApi getAuthenticationApi() {
+ return AuthenticationApi(dio, serializers);
+ }
+
+ /// Get DownloadApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ DownloadApi getDownloadApi() {
+ return DownloadApi(dio, serializers);
+ }
+
+ /// Get FaceApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ FaceApi getFaceApi() {
+ return FaceApi(dio, serializers);
+ }
+
+ /// Get FileReportApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ FileReportApi getFileReportApi() {
+ return FileReportApi(dio, serializers);
+ }
+
+ /// Get JobApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ JobApi getJobApi() {
+ return JobApi(dio, serializers);
+ }
+
+ /// Get LibraryApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ LibraryApi getLibraryApi() {
+ return LibraryApi(dio, serializers);
+ }
+
+ /// Get MemoryApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ MemoryApi getMemoryApi() {
+ return MemoryApi(dio, serializers);
+ }
+
+ /// Get OAuthApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ OAuthApi getOAuthApi() {
+ return OAuthApi(dio, serializers);
+ }
+
+ /// Get PartnerApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ PartnerApi getPartnerApi() {
+ return PartnerApi(dio, serializers);
+ }
+
+ /// Get PersonApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ PersonApi getPersonApi() {
+ return PersonApi(dio, serializers);
+ }
+
+ /// Get SearchApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ SearchApi getSearchApi() {
+ return SearchApi(dio, serializers);
+ }
+
+ /// Get ServerInfoApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ ServerInfoApi getServerInfoApi() {
+ return ServerInfoApi(dio, serializers);
+ }
+
+ /// Get SessionsApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ SessionsApi getSessionsApi() {
+ return SessionsApi(dio, serializers);
+ }
+
+ /// Get SharedLinkApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ SharedLinkApi getSharedLinkApi() {
+ return SharedLinkApi(dio, serializers);
+ }
+
+ /// Get SyncApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ SyncApi getSyncApi() {
+ return SyncApi(dio, serializers);
+ }
+
+ /// Get SystemConfigApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ SystemConfigApi getSystemConfigApi() {
+ return SystemConfigApi(dio, serializers);
+ }
+
+ /// Get SystemMetadataApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ SystemMetadataApi getSystemMetadataApi() {
+ return SystemMetadataApi(dio, serializers);
+ }
+
+ /// Get TagApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ TagApi getTagApi() {
+ return TagApi(dio, serializers);
+ }
+
+ /// Get TimelineApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ TimelineApi getTimelineApi() {
+ return TimelineApi(dio, serializers);
+ }
+
+ /// Get TrashApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ TrashApi getTrashApi() {
+ return TrashApi(dio, serializers);
+ }
+
+ /// Get UserApi instance, base route and serializer can be overridden by a given but be careful,
+ /// by doing that all interceptors will not be executed
+ UserApi getUserApi() {
+ return UserApi(dio, serializers);
+ }
+}
diff --git a/mobile-v2/openapi/lib/src/api/activity_api.dart b/mobile-v2/openapi/lib/src/api/activity_api.dart
new file mode 100644
index 0000000000..488af14d66
--- /dev/null
+++ b/mobile-v2/openapi/lib/src/api/activity_api.dart
@@ -0,0 +1,407 @@
+//
+// AUTO-GENERATED FILE, DO NOT MODIFY!
+//
+
+import 'dart:async';
+
+import 'package:built_value/serializer.dart';
+import 'package:dio/dio.dart';
+
+import 'package:built_collection/built_collection.dart';
+import 'package:openapi/src/api_util.dart';
+import 'package:openapi/src/model/activity_create_dto.dart';
+import 'package:openapi/src/model/activity_response_dto.dart';
+import 'package:openapi/src/model/activity_statistics_response_dto.dart';
+import 'package:openapi/src/model/reaction_level.dart';
+import 'package:openapi/src/model/reaction_type.dart';
+
+class ActivityApi {
+
+ final Dio _dio;
+
+ final Serializers _serializers;
+
+ const ActivityApi(this._dio, this._serializers);
+
+ /// createActivity
+ ///
+ ///
+ /// Parameters:
+ /// * [activityCreateDto]
+ /// * [cancelToken] - A [CancelToken] that can be used to cancel the operation
+ /// * [headers] - Can be used to add additional headers to the request
+ /// * [extras] - Can be used to add flags to the request
+ /// * [validateStatus] - A [ValidateStatus] callback that can be used to determine request success based on the HTTP status of the response
+ /// * [onSendProgress] - A [ProgressCallback] that can be used to get the send progress
+ /// * [onReceiveProgress] - A [ProgressCallback] that can be used to get the receive progress
+ ///
+ /// Returns a [Future] containing a [Response] with a [ActivityResponseDto] as data
+ /// Throws [DioException] if API call or serialization fails
+ Future> createActivity({
+ required ActivityCreateDto activityCreateDto,
+ CancelToken? cancelToken,
+ Map? headers,
+ Map? extra,
+ ValidateStatus? validateStatus,
+ ProgressCallback? onSendProgress,
+ ProgressCallback? onReceiveProgress,
+ }) async {
+ final _path = r'/activity';
+ final _options = Options(
+ method: r'POST',
+ headers: {
+ ...?headers,
+ },
+ extra: {
+ 'secure':