Mztj67_#M}W?l>kYSliK<%xAp;0j{!}J0!o7b
zE>q9${Lb$D&h7k=+4=!ek^n+`0zq>LL1O?lVyea53S5x`Nqqo2YyeuIrQrJj9XjOp
z{;T5qbj3}&1vg1VK~#9!?b~^C5-}JC@Pyrv-6dSEqJqT}#j9#dJ@GzT@B8}x
zU&J@bBI>f6w6en+CeI)3^kC*U?}X%OD8$Fd$H&LV$H&LV$H&LV#|K5~mLYf|VqzOc
zkc7qL~0sOYuM{tG`rYEDV{DWY`Z8&)kW*hc2VkBuY+^Yx&92j&StN}Wp=LD
zxoGxXw6f&8sB^u})h@b@z0RBeD`K7RMR9deyL(ZJu#39Z>rT)^>v}Khq8U-IbIvT>
z?4pV9qGj=2)TNH3d)=De<+^w;>S7m_eFKTvzeaBeir45xY!^m!FmxnljbSS_3o=g(
z->^wC9%qkR{kbGnW8MfFew_o9h3(r55Is`L$8KI@d+*%{=Nx+FXJ98L0PjFIu;rGnnfY
zn1R5Qnp<{Jq0M1vX=X&F8gtLmcWv$1*M@4ZfF^9``()#hGTeKeP`1!iED
ztNE(TN}M5}3Bbc*d=FIv`DNv&@|C6yYj{sSqUj5oo$#*0$7pu|Dd2TLI>t5%I
zIa4Dvr(iayb+5x=j*Vum9&irk)xV1`t509lnPO0%skL8_1c#Xbamh(2@f?4yUI
zhhuT5<#8RJhGz4%b$`PJwKPAudsm|at?u;*hGgnA
zU1;9gnxVBC)wA(BsB`AW54N{|qmikJR*%x0c`{LGsSfa|NK61pYH(r-UQ4_JXd!Rsz)=k
zL{GMc5{h138)fF5CzHEDM>+FqY)$pdN3}Ml+riTgJOLN0F*Vh?{9ESR{SVVg>*>=#
zix;VJHPtvFFCRY$Ks*F;VX~%*r9F)W`PmPE9F!(&s#x07n2<}?S{(ygpXgX-&B&OM
zONY&BRQ(#%0%jeQs?oJ4P!p*R98>qCy5p8w>_gpuh39NcOlp)(wOoz0sY-Qz55eB~
z7OC-fKBaD1sE3$l-6QgBJO!n?QOTza`!S_YK
z_v-lm^7{VO^8Q@M_^8F)09Ki6%=s?2_5eupee(w1FB%aqSweusQ-T+CH0Xt{`
zFjMvW{@C&TB)k25()nh~_yJ9coBRL(0oO@HK~z}7?bm5j;y@69;bvlHb2tf!$ReA~x{22wTq550
z?f?Hnw(;m3ip30;QzdV~7pi!wyMYhDtXW#cO7T>|f=bdFhu+F!zMZ2UFj;GUKX7tI
z;hv3{q~!*pMj75WP_c}>6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FaF{8
z;u`Mw0ly(uE>*CgQYv{be6ab2LWhlaH1^iLIM{olnag$78^Fd}%dR7;JECQ+hmk|o
z!u2&!3MqPfP5ChDSkFSH8F2WVOEf0(E_M(JL17G}Y+fg0_IuW%WQ
zG(mG&u?|->YSdk0;8rc{yw2@2Z&GA}z{Wb91Ooz9VhA{b2DYE7RmG
zjL}?eq#iX%3#k;JWMx_{^2nNax`xPhByFiDX+a7uTGU|otOvIAUy|dEKkXOm-`aWS
z27pUzD{a)Ct<6p{{3)+lq@i`t@%>-wT4r?*S}k)58e09WZYP0{{R3FC5Sl00039P)t-s|Ns9~
z#rP?<_5oL$Q^olD{r_0T`27C={r>*`|Nj71npVa5OTzc(_WfbW_({R{p56NV{r*M2
z_xt?)2V0#0NsfV0u>{42ctGP(8vQj-Btk1n|O0ZD=YLwd&R{Ko41Gr9H=
zY@z@@bOAMB5Ltl$E>bJJ{>JP30ZxkmI%?eW{k`b?Wy<&gOo;dS`~CR$Vwb@XWtR|N
zi~t=w02?-0&j0TD{>bb6sNwsK*!p?V`RMQUl(*DVjk-9Cx+-z1KXab|Ka2oXhX5f%
z`$|e!000AhNklrxs)5QTeTVRiEmz~MKK1WAjCw(c-JK6eox;2O)?`?
zTG`AHia671e^vgmp!llKp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?hz91
z7p83F3%LVu9;S$tSI$C^%^yud1dfTM_6p2|+5Ejp$bd`GDvbR|xit>i!ZD&F>@CJrPmu*UjD&?DfZs=$@e3FQA(vNiU+$A*%a}
z?`XcG2jDxJ_ZQ#Md`H{4Lpf6QBDp81_KWZ6Tk#yCy1)32zO#3<7>b`eT7UyYH1eGz
z;O(rH$=QR*L%%ZcBpc=eGua?N55nD^K(8<#gl2+pN_j~b2MHs4#mcLmv%DkspS-3<
zpI1F=^9siI0s-;IN_IrA;5xm~3?3!StX}pUv0vkxMaqm+zxrg7X7(I&*N~&dEd0kD
z-FRV|g=|QuUsuh>-xCI}vD2imzYIOIdcCVV=$Bz@*u0+Bs<|L^)32nN*=wu3n%Ynw
z@1|eLG>!8ruU1pFXUfb`j>(=Gy~?Rn4QJ-c3%3T|(Frd!bI`9u&zAnyFYTqlG#&J7
zAkD(jpw|oZLNiA>;>hgp1KX7-wxC~31II47gc
zHcehD6Uxlf%+M^^uN5Wc*G%^;>D5qT{>=uxUhX%WJu^Z*(_Wq9y}npFO{Hhb>s6<9
zNi0pHXWFaVZnb)1+RS&F)xOv6&aeILcI)`k#0YE+?e)5r7J#c`3Z7x!LpTc01dx
zrdC3{Z;joZ^KN&))zB_i)I9fWedoN>Zl-6_Iz+^G&*ak2jpF07*qoM6N<$f;w%0(f|Me
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8
GIT binary patch
literal 1418
zcmV;51$Fv~P)q
zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+
zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq
z^={4hPQv)y=I|4n+?>7Fim=dxt1
z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT
zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf`
zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_>
z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3
zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF
z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a
z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE
z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62(
zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;?
zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-<
z{s<&cCV_1`^TD^ia9!*mQDq&
zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw
zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv
zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF
z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC
YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
GIT binary patch
literal 68
zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J
Q1PU{Fy85}Sb4q9e0B4a5jsO4v
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
GIT binary patch
literal 68
zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J
Q1PU{Fy85}Sb4q9e0B4a5jsO4v
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
GIT binary patch
literal 68
zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J
Q1PU{Fy85}Sb4q9e0B4a5jsO4v
literal 0
HcmV?d00001
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':