diff --git a/lib/api/config.dart b/lib/api/config.dart index c234ea8..68f7ff6 100644 --- a/lib/api/config.dart +++ b/lib/api/config.dart @@ -1,3 +1,5 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:json_annotation/json_annotation.dart'; part 'config.g.dart'; @@ -9,6 +11,31 @@ enum ThumbnailMethod { ffmpegApi, } +enum ImportMethod { + @JsonValue(0) + copy, + @JsonValue(1) + copyThenDelete, + @JsonValue(2) + move, + @JsonValue(3) + keep; + + String localText(BuildContext context) { + final i18n = AppLocalizations.of(context)!; + switch (this) { + case ImportMethod.copy: + return i18n.copy; + case ImportMethod.copyThenDelete: + return i18n.copyThenDelete; + case ImportMethod.move: + return i18n.move; + case ImportMethod.keep: + return i18n.keep; + } + } +} + @JsonSerializable() class Config { Config({ @@ -43,6 +70,10 @@ class Config { required this.downloadTimeoutCheckInterval, required this.ehMetadataCacheTime, this.randomFileSecret, + required this.usePathBasedImgUrl, + required this.checkFileHash, + required this.importMethod, + required this.maxImportImgCount, }); bool cookies; @JsonKey(name: 'db_path') @@ -99,6 +130,14 @@ class Config { int ehMetadataCacheTime; @JsonKey(name: "random_file_secret") String? randomFileSecret; + @JsonKey(name: 'use_path_based_img_url') + bool usePathBasedImgUrl; + @JsonKey(name: 'check_file_hash') + bool checkFileHash; + @JsonKey(name: 'import_method') + ImportMethod importMethod; + @JsonKey(name: 'max_import_img_count') + int maxImportImgCount; factory Config.fromJson(Map json) => _$ConfigFromJson(json); Map toJson() => _$ConfigToJson(this); } @@ -149,6 +188,10 @@ class ConfigOptional { this.downloadTimeoutCheckInterval, this.ehMetadataCacheTime, this.randomFileSecret, + this.usePathBasedImgUrl, + this.checkFileHash, + this.importMethod, + this.maxImportImgCount, }); String? cookies; @JsonKey(name: 'db_path') @@ -205,6 +248,14 @@ class ConfigOptional { int? ehMetadataCacheTime; @JsonKey(name: "random_file_secret") String? randomFileSecret; + @JsonKey(name: 'use_path_based_img_url') + bool? usePathBasedImgUrl; + @JsonKey(name: 'check_file_hash') + bool? checkFileHash; + @JsonKey(name: 'import_method') + ImportMethod? importMethod; + @JsonKey(name: 'max_import_img_count') + int? maxImportImgCount; factory ConfigOptional.fromJson(Map json) => _$ConfigOptionalFromJson(json); Map toJson() => _$ConfigOptionalToJson(this); diff --git a/lib/api/config.g.dart b/lib/api/config.g.dart index 89764a3..baa594b 100644 --- a/lib/api/config.g.dart +++ b/lib/api/config.g.dart @@ -44,6 +44,10 @@ Config _$ConfigFromJson(Map json) => Config( (json['download_timeout_check_interval'] as num).toInt(), ehMetadataCacheTime: (json['eh_metadata_cache_time'] as num).toInt(), randomFileSecret: json['random_file_secret'] as String?, + usePathBasedImgUrl: json['use_path_based_img_url'] as bool, + checkFileHash: json['check_file_hash'] as bool, + importMethod: $enumDecode(_$ImportMethodEnumMap, json['import_method']), + maxImportImgCount: (json['max_import_img_count'] as num).toInt(), ); Map _$ConfigToJson(Config instance) => { @@ -78,6 +82,10 @@ Map _$ConfigToJson(Config instance) => { 'download_timeout_check_interval': instance.downloadTimeoutCheckInterval, 'eh_metadata_cache_time': instance.ehMetadataCacheTime, 'random_file_secret': instance.randomFileSecret, + 'use_path_based_img_url': instance.usePathBasedImgUrl, + 'check_file_hash': instance.checkFileHash, + 'import_method': _$ImportMethodEnumMap[instance.importMethod]!, + 'max_import_img_count': instance.maxImportImgCount, }; const _$ThumbnailMethodEnumMap = { @@ -85,6 +93,13 @@ const _$ThumbnailMethodEnumMap = { ThumbnailMethod.ffmpegApi: 1, }; +const _$ImportMethodEnumMap = { + ImportMethod.copy: 0, + ImportMethod.copyThenDelete: 1, + ImportMethod.move: 2, + ImportMethod.keep: 3, +}; + UpdateConfigResult _$UpdateConfigResultFromJson(Map json) => UpdateConfigResult( isUnsafe: json['is_unsafe'] as bool, @@ -134,6 +149,11 @@ ConfigOptional _$ConfigOptionalFromJson(Map json) => (json['download_timeout_check_interval'] as num?)?.toInt(), ehMetadataCacheTime: (json['eh_metadata_cache_time'] as num?)?.toInt(), randomFileSecret: json['random_file_secret'] as String?, + usePathBasedImgUrl: json['use_path_based_img_url'] as bool?, + checkFileHash: json['check_file_hash'] as bool?, + importMethod: + $enumDecodeNullable(_$ImportMethodEnumMap, json['import_method']), + maxImportImgCount: (json['max_import_img_count'] as num?)?.toInt(), ); Map _$ConfigOptionalToJson(ConfigOptional instance) => @@ -169,4 +189,8 @@ Map _$ConfigOptionalToJson(ConfigOptional instance) => 'download_timeout_check_interval': instance.downloadTimeoutCheckInterval, 'eh_metadata_cache_time': instance.ehMetadataCacheTime, 'random_file_secret': instance.randomFileSecret, + 'use_path_based_img_url': instance.usePathBasedImgUrl, + 'check_file_hash': instance.checkFileHash, + 'import_method': _$ImportMethodEnumMap[instance.importMethod], + 'max_import_img_count': instance.maxImportImgCount, }; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 60869f5..7b1f12b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -248,5 +248,13 @@ "thumbnailSize": "Thumbnail size", "smail": "smail", "medium": "medium", - "big": "big" + "big": "big", + "usePathBasedImgUrl": "Put parameters to image URL path.", + "checkFileHash": "Verify file integrity when downloading or importing.", + "importMethod": "Import method", + "copy": "Copy", + "copyThenDelete": "Copy then delete", + "move": "Move", + "keep": "Keep", + "maxImportImgCount": "Maximum number of images to be imported in parallel" } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 56e1a0d..f7ff268 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -248,5 +248,13 @@ "thumbnailSize": "缩略图大小", "smail": "小", "medium": "中", - "big": "大" + "big": "大", + "usePathBasedImgUrl": "将参数放入图片地址路径。", + "checkFileHash": "下载或导入时校验文件完整性。", + "importMethod": "导入方式", + "copy": "复制", + "copyThenDelete": "复制后删除", + "move": "移动", + "keep": "保留", + "maxImportImgCount": "最大图片并行导入数" } diff --git a/lib/pages/settings/server.dart b/lib/pages/settings/server.dart index c508738..7a06ace 100644 --- a/lib/pages/settings/server.dart +++ b/lib/pages/settings/server.dart @@ -295,6 +295,28 @@ class _ServerSettingsPage extends State } }, label: Text(i18n.redirectToFlutter))), + _buildWithVecticalPadding(LabeledCheckbox( + value: _now.usePathBasedImgUrl ?? _config!.usePathBasedImgUrl, + onChanged: (b) { + if (b != null) { + setState(() { + _now.usePathBasedImgUrl = b; + _changed = true; + }); + } + }, + label: Text(i18n.usePathBasedImgUrl))), + _buildWithVecticalPadding(LabeledCheckbox( + value: _now.checkFileHash ?? _config!.checkFileHash, + onChanged: (b) { + if (b != null) { + setState(() { + _now.checkFileHash = b; + _changed = true; + }); + } + }, + label: Text(i18n.checkFileHash))), ])); } @@ -721,6 +743,38 @@ class _ServerSettingsPage extends State }); }, )), + _buildWithVecticalPadding(DropdownButtonFormField( + items: ImportMethod.values + .map((e) => DropdownMenuItem( + value: e, child: Text(e.localText(context)))) + .toList(), + onChanged: (v) { + if (v != null) { + setState(() { + _now.importMethod = v; + _changed = true; + }); + } + }, + value: _now.importMethod ?? _config!.importMethod, + decoration: InputDecoration( + border: const OutlineInputBorder(), + labelText: i18n.importMethod, + ))), + _buildWithVecticalPadding(NumberFormField( + min: 1, + initialValue: _now.maxImportImgCount ?? _config!.maxImportImgCount, + decoration: InputDecoration( + border: const OutlineInputBorder(), + labelText: i18n.maxImportImgCount, + ), + onChanged: (s) { + setState(() { + _now.maxImportImgCount = s; + _changed = true; + }); + }, + )), ])); }