mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
Get thumbnail from app (#68)
* Renamed multipart filed name 'files' to 'assetData'. * Added an additional field name of 'thumbnailData' to multipart form. * Implemented upload mechanism for thumbnail directly from the mobile client. * Removed dead code * Implemented a version checking mechanism.
This commit is contained in:
@@ -9,6 +9,8 @@ PODS:
|
||||
- FMDB (2.7.5):
|
||||
- FMDB/standard (= 2.7.5)
|
||||
- FMDB/standard (2.7.5)
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider_ios (0.0.1):
|
||||
- Flutter
|
||||
- photo_manager (1.0.0):
|
||||
@@ -28,6 +30,7 @@ DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||
@@ -47,6 +50,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/flutter_udid/ios"
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_ios:
|
||||
:path: ".symlinks/plugins/path_provider_ios/ios"
|
||||
photo_manager:
|
||||
@@ -63,6 +68,7 @@ SPEC CHECKSUMS:
|
||||
flutter_udid: 0848809dbed4c055175747ae6a45a8b4f6771e1c
|
||||
fluttertoast: 6122fa75143e992b1d3470f61000f591a798cc58
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
|
||||
photo_manager: 84fa94fbeb82e607333ea9a13c43b58e0903a463
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
|
||||
@@ -18,6 +18,9 @@ default_platform(:ios)
|
||||
platform :ios do
|
||||
desc "iOS deployment"
|
||||
lane :beta do
|
||||
increment_version_number(
|
||||
version_number: "1.3.0" # Set a specific version number
|
||||
)
|
||||
increment_build_number({
|
||||
build_number: latest_testflight_build_number + 1
|
||||
})
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/routing/tab_navigation_observer.dart';
|
||||
import 'package:immich_mobile/shared/providers/app_state.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/backup.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
|
||||
import 'constants/hive_box.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -43,7 +44,10 @@ class _ImmichAppState extends ConsumerState<ImmichApp> with WidgetsBindingObserv
|
||||
ref.watch(backupProvider.notifier).resumeBackup();
|
||||
ref.watch(websocketProvider.notifier).connect();
|
||||
ref.watch(assetProvider.notifier).getAllAsset();
|
||||
ref.watch(serverInfoProvider.notifier).getServerVersion();
|
||||
|
||||
break;
|
||||
|
||||
case AppLifecycleState.inactive:
|
||||
debugPrint("[APP STATE] inactive");
|
||||
ref.watch(appStateProvider.notifier).state = AppStateEnum.inactive;
|
||||
@@ -51,10 +55,12 @@ class _ImmichAppState extends ConsumerState<ImmichApp> with WidgetsBindingObserv
|
||||
ref.watch(backupProvider.notifier).cancelBackup();
|
||||
|
||||
break;
|
||||
|
||||
case AppLifecycleState.paused:
|
||||
debugPrint("[APP STATE] paused");
|
||||
ref.watch(appStateProvider.notifier).state = AppStateEnum.paused;
|
||||
break;
|
||||
|
||||
case AppLifecycleState.detached:
|
||||
debugPrint("[APP STATE] detached");
|
||||
ref.watch(appStateProvider.notifier).state = AppStateEnum.detached;
|
||||
|
||||
@@ -7,7 +7,9 @@ import 'package:immich_mobile/modules/login/providers/authentication.provider.da
|
||||
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/shared/models/backup_state.model.dart';
|
||||
import 'package:immich_mobile/shared/models/server_info_state.model.dart';
|
||||
import 'package:immich_mobile/shared/providers/backup.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||
|
||||
class ImmichSliverAppBar extends ConsumerWidget {
|
||||
const ImmichSliverAppBar({
|
||||
@@ -21,6 +23,8 @@ class ImmichSliverAppBar extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final BackUpState _backupState = ref.watch(backupProvider);
|
||||
bool _isEnableAutoBackup = ref.watch(authenticationProvider).deviceInfo.isAutoBackup;
|
||||
final ServerInfoState _serverInfoState = ref.watch(serverInfoProvider);
|
||||
|
||||
return SliverAppBar(
|
||||
centerTitle: true,
|
||||
floating: true,
|
||||
@@ -30,12 +34,46 @@ class ImmichSliverAppBar extends ConsumerWidget {
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))),
|
||||
leading: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.account_circle_rounded),
|
||||
onPressed: () {
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
|
||||
return Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
top: 5,
|
||||
child: IconButton(
|
||||
splashRadius: 25,
|
||||
icon: const Icon(
|
||||
Icons.account_circle_rounded,
|
||||
size: 30,
|
||||
),
|
||||
onPressed: () {
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
),
|
||||
),
|
||||
_serverInfoState.isVersionMismatch
|
||||
? Positioned(
|
||||
bottom: 12,
|
||||
right: 12,
|
||||
child: GestureDetector(
|
||||
onTap: () => Scaffold.of(context).openDrawer(),
|
||||
child: Material(
|
||||
color: Colors.grey[200],
|
||||
elevation: 1,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(50.0),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(2.0),
|
||||
child: Icon(
|
||||
Icons.info,
|
||||
color: Color.fromARGB(255, 243, 188, 106),
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -5,7 +5,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/home/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/modules/login/models/authentication_state.model.dart';
|
||||
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
|
||||
import 'package:immich_mobile/shared/models/server_info_state.model.dart';
|
||||
import 'package:immich_mobile/shared/providers/backup.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
@@ -15,6 +17,8 @@ class ProfileDrawer extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
AuthenticationState _authState = ref.watch(authenticationProvider);
|
||||
ServerInfoState _serverInfoState = ref.watch(serverInfoProvider);
|
||||
|
||||
final appInfo = useState({});
|
||||
|
||||
_getPackageInfo() async {
|
||||
@@ -92,13 +96,70 @@ class ProfileDrawer extends HookConsumerWidget {
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
"Version V${appInfo.value["version"]}+${appInfo.value["buildNumber"]}",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[400],
|
||||
fontWeight: FontWeight.bold,
|
||||
fontStyle: FontStyle.italic,
|
||||
child: Card(
|
||||
color: Colors.grey[100],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
_serverInfoState.isVersionMismatch
|
||||
? _serverInfoState.versionMismatchErrorMessage
|
||||
: "Client and Server are up-to-date",
|
||||
textAlign: TextAlign.center,
|
||||
style:
|
||||
TextStyle(fontSize: 11, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"App Version",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey[500],
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${appInfo.value["version"]} build.${appInfo.value["buildNumber"]}",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey[500],
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Server Version",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey[500],
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"${_serverInfoState.serverVersion.major}.${_serverInfoState.serverVersion.minor}.${_serverInfoState.serverVersion.patch}",
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey[500],
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:immich_mobile/modules/home/ui/immich_sliver_appbar.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/monthly_title_text.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/profile_drawer.dart';
|
||||
import 'package:immich_mobile/modules/home/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
|
||||
import 'package:sliver_tools/sliver_tools.dart';
|
||||
|
||||
@@ -28,6 +29,7 @@ class HomePage extends HookConsumerWidget {
|
||||
useEffect(() {
|
||||
ref.read(websocketProvider.notifier).connect();
|
||||
ref.read(assetProvider.notifier).getAllAsset();
|
||||
ref.watch(serverInfoProvider.notifier).getServerVersion();
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'package:immich_mobile/modules/search/providers/search_page_state.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
|
||||
|
||||
class TabNavigationObserver extends AutoRouterObserver {
|
||||
/// Riverpod Instance
|
||||
@@ -26,5 +27,7 @@ class TabNavigationObserver extends AutoRouterObserver {
|
||||
// Refresh Location State
|
||||
ref.refresh(getCuratedLocationProvider);
|
||||
}
|
||||
|
||||
ref.watch(serverInfoProvider.notifier).getServerVersion();
|
||||
}
|
||||
}
|
||||
|
||||
78
mobile/lib/shared/models/server_info_state.model.dart
Normal file
78
mobile/lib/shared/models/server_info_state.model.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:immich_mobile/shared/models/mapbox_info.model.dart';
|
||||
import 'package:immich_mobile/shared/models/server_version.model.dart';
|
||||
|
||||
class ServerInfoState {
|
||||
final MapboxInfo mapboxInfo;
|
||||
final ServerVersion serverVersion;
|
||||
final bool isVersionMismatch;
|
||||
final String versionMismatchErrorMessage;
|
||||
|
||||
ServerInfoState({
|
||||
required this.mapboxInfo,
|
||||
required this.serverVersion,
|
||||
required this.isVersionMismatch,
|
||||
required this.versionMismatchErrorMessage,
|
||||
});
|
||||
|
||||
ServerInfoState copyWith({
|
||||
MapboxInfo? mapboxInfo,
|
||||
ServerVersion? serverVersion,
|
||||
bool? isVersionMismatch,
|
||||
String? versionMismatchErrorMessage,
|
||||
}) {
|
||||
return ServerInfoState(
|
||||
mapboxInfo: mapboxInfo ?? this.mapboxInfo,
|
||||
serverVersion: serverVersion ?? this.serverVersion,
|
||||
isVersionMismatch: isVersionMismatch ?? this.isVersionMismatch,
|
||||
versionMismatchErrorMessage: versionMismatchErrorMessage ?? this.versionMismatchErrorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'mapboxInfo': mapboxInfo.toMap(),
|
||||
'serverVersion': serverVersion.toMap(),
|
||||
'isVersionMismatch': isVersionMismatch,
|
||||
'versionMismatchErrorMessage': versionMismatchErrorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
factory ServerInfoState.fromMap(Map<String, dynamic> map) {
|
||||
return ServerInfoState(
|
||||
mapboxInfo: MapboxInfo.fromMap(map['mapboxInfo']),
|
||||
serverVersion: ServerVersion.fromMap(map['serverVersion']),
|
||||
isVersionMismatch: map['isVersionMismatch'] ?? false,
|
||||
versionMismatchErrorMessage: map['versionMismatchErrorMessage'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory ServerInfoState.fromJson(String source) => ServerInfoState.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerInfoState(mapboxInfo: $mapboxInfo, serverVersion: $serverVersion, isVersionMismatch: $isVersionMismatch, versionMismatchErrorMessage: $versionMismatchErrorMessage)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is ServerInfoState &&
|
||||
other.mapboxInfo == mapboxInfo &&
|
||||
other.serverVersion == serverVersion &&
|
||||
other.isVersionMismatch == isVersionMismatch &&
|
||||
other.versionMismatchErrorMessage == versionMismatchErrorMessage;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return mapboxInfo.hashCode ^
|
||||
serverVersion.hashCode ^
|
||||
isVersionMismatch.hashCode ^
|
||||
versionMismatchErrorMessage.hashCode;
|
||||
}
|
||||
}
|
||||
72
mobile/lib/shared/models/server_version.model.dart
Normal file
72
mobile/lib/shared/models/server_version.model.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class ServerVersion {
|
||||
final int major;
|
||||
final int minor;
|
||||
final int patch;
|
||||
final int build;
|
||||
|
||||
ServerVersion({
|
||||
required this.major,
|
||||
required this.minor,
|
||||
required this.patch,
|
||||
required this.build,
|
||||
});
|
||||
|
||||
ServerVersion copyWith({
|
||||
int? major,
|
||||
int? minor,
|
||||
int? patch,
|
||||
int? build,
|
||||
}) {
|
||||
return ServerVersion(
|
||||
major: major ?? this.major,
|
||||
minor: minor ?? this.minor,
|
||||
patch: patch ?? this.patch,
|
||||
build: build ?? this.build,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'major': major,
|
||||
'minor': minor,
|
||||
'patch': patch,
|
||||
'build': build,
|
||||
};
|
||||
}
|
||||
|
||||
factory ServerVersion.fromMap(Map<String, dynamic> map) {
|
||||
return ServerVersion(
|
||||
major: map['major']?.toInt() ?? 0,
|
||||
minor: map['minor']?.toInt() ?? 0,
|
||||
patch: map['patch']?.toInt() ?? 0,
|
||||
build: map['build']?.toInt() ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory ServerVersion.fromJson(String source) => ServerVersion.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ServerVersion(major: $major, minor: $minor, patch: $patch, build: $build)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is ServerVersion &&
|
||||
other.major == major &&
|
||||
other.minor == minor &&
|
||||
other.patch == patch &&
|
||||
other.build == build;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return major.hashCode ^ minor.hashCode ^ patch.hashCode ^ build.hashCode;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,19 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'package:immich_mobile/shared/models/mapbox_info.model.dart';
|
||||
import 'package:immich_mobile/shared/models/server_info_state.model.dart';
|
||||
import 'package:immich_mobile/shared/models/server_version.model.dart';
|
||||
import 'package:immich_mobile/shared/services/server_info.service.dart';
|
||||
|
||||
class ServerInfoState {
|
||||
final MapboxInfo mapboxInfo;
|
||||
ServerInfoState({
|
||||
required this.mapboxInfo,
|
||||
});
|
||||
|
||||
ServerInfoState copyWith({
|
||||
MapboxInfo? mapboxInfo,
|
||||
}) {
|
||||
return ServerInfoState(
|
||||
mapboxInfo: mapboxInfo ?? this.mapboxInfo,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'mapboxInfo': mapboxInfo.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
factory ServerInfoState.fromMap(Map<String, dynamic> map) {
|
||||
return ServerInfoState(
|
||||
mapboxInfo: MapboxInfo.fromMap(map['mapboxInfo']),
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory ServerInfoState.fromJson(String source) => ServerInfoState.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() => 'ServerInfoState(mapboxInfo: $mapboxInfo)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is ServerInfoState && other.mapboxInfo == mapboxInfo;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => mapboxInfo.hashCode;
|
||||
}
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
||||
ServerInfoNotifier()
|
||||
: super(
|
||||
ServerInfoState(
|
||||
mapboxInfo: MapboxInfo(isEnable: false, mapboxSecret: ""),
|
||||
serverVersion: ServerVersion(major: 0, patch: 0, minor: 0, build: 0),
|
||||
isVersionMismatch: false,
|
||||
versionMismatchErrorMessage: "",
|
||||
),
|
||||
);
|
||||
|
||||
@@ -61,9 +21,63 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
||||
|
||||
getMapboxInfo() async {
|
||||
MapboxInfo mapboxInfoRes = await _serverInfoService.getMapboxInfo();
|
||||
print(mapboxInfoRes);
|
||||
state = state.copyWith(mapboxInfo: mapboxInfoRes);
|
||||
}
|
||||
|
||||
getServerVersion() async {
|
||||
ServerVersion? serverVersion = await _serverInfoService.getServerVersion();
|
||||
|
||||
if (serverVersion == null) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage:
|
||||
"Server is out of date. Some functionalities might not working correctly. Download and rebuild server",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(serverVersion: serverVersion);
|
||||
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
Map<String, int> appVersion = _getDetailVersion(packageInfo.version);
|
||||
|
||||
if (appVersion["major"]! > serverVersion.major) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage:
|
||||
"Server is out of date in major version. Some functionalities might not work correctly. Download and rebuild server",
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (appVersion["minor"]! > serverVersion.minor) {
|
||||
state = state.copyWith(
|
||||
isVersionMismatch: true,
|
||||
versionMismatchErrorMessage:
|
||||
"Server is out of date in minor version. Some functionalities might not work correctly. Consider download and rebuild server",
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
state = state.copyWith(isVersionMismatch: false, versionMismatchErrorMessage: "");
|
||||
}
|
||||
|
||||
Map<String, int> _getDetailVersion(String version) {
|
||||
List<String> detail = version.split(".");
|
||||
|
||||
var major = detail[0];
|
||||
var minor = detail[1];
|
||||
var patch = detail[2];
|
||||
|
||||
return {
|
||||
"major": int.parse(major),
|
||||
"minor": int.parse(minor),
|
||||
"patch": int.parse(patch),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
final serverInfoProvider = StateNotifierProvider<ServerInfoNotifier, ServerInfoState>((ref) {
|
||||
|
||||
@@ -30,10 +30,14 @@ class BackupService {
|
||||
Function(int, int) uploadProgress) async {
|
||||
var dio = Dio();
|
||||
dio.interceptors.add(AuthenticatedRequestInterceptor());
|
||||
|
||||
String deviceId = Hive.box(userInfoBox).get(deviceIdKey);
|
||||
String savedEndpoint = Hive.box(userInfoBox).get(serverEndpointKey);
|
||||
File? file;
|
||||
|
||||
MultipartFile assetRawUploadData;
|
||||
MultipartFile thumbnailUploadData;
|
||||
|
||||
for (var entity in assetList) {
|
||||
try {
|
||||
if (entity.type == AssetType.video) {
|
||||
@@ -43,12 +47,20 @@ class BackupService {
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
FormData formData;
|
||||
String originalFileName = await entity.titleAsync;
|
||||
String fileNameWithoutPath = originalFileName.toString().split(".")[0];
|
||||
var fileExtension = p.extension(file.path);
|
||||
var mimeType = FileHelper.getMimeType(file.path);
|
||||
|
||||
var formData = FormData.fromMap({
|
||||
assetRawUploadData = await MultipartFile.fromFile(
|
||||
file.path,
|
||||
filename: fileNameWithoutPath,
|
||||
contentType: MediaType(
|
||||
mimeType["type"],
|
||||
mimeType["subType"],
|
||||
),
|
||||
);
|
||||
formData = FormData.fromMap({
|
||||
'deviceAssetId': entity.id,
|
||||
'deviceId': deviceId,
|
||||
'assetType': _getAssetType(entity.type),
|
||||
@@ -57,18 +69,36 @@ class BackupService {
|
||||
'isFavorite': entity.isFavorite,
|
||||
'fileExtension': fileExtension,
|
||||
'duration': entity.videoDuration,
|
||||
'files': [
|
||||
await MultipartFile.fromFile(
|
||||
file.path,
|
||||
filename: fileNameWithoutPath,
|
||||
contentType: MediaType(
|
||||
mimeType["type"],
|
||||
mimeType["subType"],
|
||||
),
|
||||
),
|
||||
]
|
||||
'assetData': [assetRawUploadData]
|
||||
});
|
||||
|
||||
// Build thumbnail multipart data
|
||||
var thumbnailData = await entity.thumbDataWithSize(1280, 720);
|
||||
if (thumbnailData != null) {
|
||||
thumbnailUploadData = MultipartFile.fromBytes(
|
||||
List.from(thumbnailData),
|
||||
filename: fileNameWithoutPath,
|
||||
contentType: MediaType(
|
||||
"image",
|
||||
"jpeg",
|
||||
),
|
||||
);
|
||||
|
||||
// Send thumbnail data if it is exist
|
||||
formData = FormData.fromMap({
|
||||
'deviceAssetId': entity.id,
|
||||
'deviceId': deviceId,
|
||||
'assetType': _getAssetType(entity.type),
|
||||
'createdAt': entity.createDateTime.toIso8601String(),
|
||||
'modifiedAt': entity.modifiedDateTime.toIso8601String(),
|
||||
'isFavorite': entity.isFavorite,
|
||||
'fileExtension': fileExtension,
|
||||
'duration': entity.videoDuration,
|
||||
'thumbnailData': [thumbnailUploadData],
|
||||
'assetData': [assetRawUploadData]
|
||||
});
|
||||
}
|
||||
|
||||
Response res = await dio.post(
|
||||
'$savedEndpoint/asset/upload',
|
||||
data: formData,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:immich_mobile/shared/models/mapbox_info.model.dart';
|
||||
import 'package:immich_mobile/shared/models/server_version.model.dart';
|
||||
import 'package:immich_mobile/shared/services/network.service.dart';
|
||||
import 'package:immich_mobile/shared/models/server_info.model.dart';
|
||||
|
||||
@@ -17,4 +18,10 @@ class ServerInfoService {
|
||||
|
||||
return MapboxInfo.fromJson(response.toString());
|
||||
}
|
||||
|
||||
Future<ServerVersion?> getServerVersion() async {
|
||||
Response response = await _networkService.getRequest(url: 'server-info/version');
|
||||
|
||||
return ServerVersion.fromJson(response.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ name: immich_mobile
|
||||
description: A new Flutter project.
|
||||
|
||||
publish_to: "none"
|
||||
version: 1.1.0+1
|
||||
version: 1.3.0+0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.15.1 <3.0.0"
|
||||
|
||||
Reference in New Issue
Block a user