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:
Alex
2022-03-22 01:22:04 -05:00
committed by GitHub
parent be72df70fe
commit e407a4fa13
29 changed files with 480 additions and 244 deletions

View 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;
}
}

View 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;
}
}

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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());
}
}