mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
merge main
This commit is contained in:
@@ -22,10 +22,10 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/open_in_browse
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_lock_folder_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/set_album_cover.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/set_profile_picture_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/similar_photos_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/set_profile_picture_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/unarchive_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/unstack_action_button.widget.dart';
|
||||
@@ -44,7 +44,6 @@ class ActionButtonContext {
|
||||
final ActionSource source;
|
||||
final bool isCasting;
|
||||
final TimelineOrigin timelineOrigin;
|
||||
final ThemeData? originalTheme;
|
||||
final int selectedCount;
|
||||
|
||||
const ActionButtonContext({
|
||||
@@ -59,7 +58,6 @@ class ActionButtonContext {
|
||||
required this.source,
|
||||
this.isCasting = false,
|
||||
this.timelineOrigin = TimelineOrigin.main,
|
||||
this.originalTheme,
|
||||
this.selectedCount = 1,
|
||||
});
|
||||
}
|
||||
@@ -244,7 +242,6 @@ enum ActionButtonType {
|
||||
origin: context.timelineOrigin,
|
||||
iconOnly: iconOnly,
|
||||
menuItem: menuItem,
|
||||
iconColor: context.originalTheme?.iconTheme.color,
|
||||
),
|
||||
ActionButtonType.similarPhotos => SimilarPhotosActionButton(
|
||||
assetId: (context.asset as RemoteAsset).id,
|
||||
@@ -259,14 +256,12 @@ enum ActionButtonType {
|
||||
ActionButtonType.openInfo => BaseActionButton(
|
||||
label: 'info'.tr(),
|
||||
iconData: Icons.info_outline,
|
||||
iconColor: context.originalTheme?.iconTheme.color,
|
||||
menuItem: true,
|
||||
onPressed: () => EventStream.shared.emit(const ViewerShowDetailsEvent()),
|
||||
),
|
||||
ActionButtonType.viewInTimeline => BaseActionButton(
|
||||
label: 'view_in_timeline'.tr(),
|
||||
iconData: Icons.image_search,
|
||||
iconColor: context.originalTheme?.iconTheme.color,
|
||||
iconOnly: iconOnly,
|
||||
menuItem: menuItem,
|
||||
onPressed: buildContext == null
|
||||
@@ -320,7 +315,7 @@ class ActionButtonBuilder {
|
||||
return _actionTypes.where((type) => type.shouldShow(context)).map((type) => type.buildButton(context)).toList();
|
||||
}
|
||||
|
||||
static List<Widget> buildViewerKebabMenu(ActionButtonContext context, BuildContext buildContext, WidgetRef ref) {
|
||||
static List<Widget> buildViewerKebabMenu(ActionButtonContext context, BuildContext buildContext) {
|
||||
final visibleButtons = defaultViewerKebabMenuOrder
|
||||
.where((type) => !defaultViewerBottomBarButtons.contains(type) && type.shouldShow(context))
|
||||
.toList();
|
||||
@@ -336,7 +331,7 @@ class ActionButtonBuilder {
|
||||
if (lastGroup != null && type.kebabMenuGroup != lastGroup) {
|
||||
result.add(const Divider(height: 1));
|
||||
}
|
||||
result.add(type.buildButton(context, buildContext, false, true).build(buildContext, ref));
|
||||
result.add(type.buildButton(context, buildContext, false, true));
|
||||
lastGroup = type.kebabMenuGroup;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ String formatBytes(int bytes) {
|
||||
}
|
||||
|
||||
String formatHumanReadableBytes(int bytes, int decimals) {
|
||||
if (bytes <= 0) return "0 B";
|
||||
if (bytes <= 0) {
|
||||
return "0 B";
|
||||
}
|
||||
const suffixes = ["B", "KiB", "MiB", "GiB", "TiB"];
|
||||
var i = (log(bytes) / log(1024)).floor();
|
||||
return '${(bytes / pow(1024, i)).toStringAsFixed(decimals)} ${suffixes[i]}';
|
||||
|
||||
@@ -34,7 +34,9 @@ Future<void> migrateDatabaseIfNeeded(Drift drift) async {
|
||||
|
||||
Future<void> _migrateTo25() async {
|
||||
final accessToken = Store.tryGet(StoreKey.accessToken);
|
||||
if (accessToken == null || accessToken.isEmpty) return;
|
||||
if (accessToken == null || accessToken.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final urls = <String>[];
|
||||
final serverEndpoint = Store.tryGet(StoreKey.serverEndpoint);
|
||||
@@ -50,10 +52,14 @@ Future<void> _migrateTo25() async {
|
||||
final List<dynamic> list = jsonDecode(externalJson);
|
||||
for (final entry in list) {
|
||||
final url = AuxilaryEndpoint.fromJson(entry).url;
|
||||
if (url.isNotEmpty) urls.add(url);
|
||||
if (url.isNotEmpty) {
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (urls.isEmpty) return;
|
||||
if (urls.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final customHeadersStr = Store.get(StoreKey.legacyCustomHeaders, "");
|
||||
final headers = customHeadersStr.isEmpty
|
||||
@@ -125,7 +131,9 @@ Future<void> _migrateTo26(Drift drift) async {
|
||||
|
||||
Future<void> _migrateExternalEndpointList(Drift drift, _StoreMigrator migrator) async {
|
||||
final raw = await migrator.readLegacyStoreString(StoreKey.legacyExternalEndpointList.id);
|
||||
if (raw == null) return;
|
||||
if (raw == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final urls = <String>[];
|
||||
try {
|
||||
@@ -133,7 +141,9 @@ Future<void> _migrateExternalEndpointList(Drift drift, _StoreMigrator migrator)
|
||||
if (decoded is List) {
|
||||
for (final entry in decoded) {
|
||||
final url = AuxilaryEndpoint.fromJson(entry).url;
|
||||
if (url.isNotEmpty) urls.add(url);
|
||||
if (url.isNotEmpty) {
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
} on FormatException {
|
||||
@@ -152,14 +162,18 @@ Future<void> _migrateExternalEndpointList(Drift drift, _StoreMigrator migrator)
|
||||
|
||||
Future<void> _migrateCustomHeaders(Drift drift, _StoreMigrator migrator) async {
|
||||
final raw = await migrator.readLegacyStoreString(StoreKey.legacyCustomHeaders.id);
|
||||
if (raw == null) return;
|
||||
if (raw == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final headers = <String, String>{};
|
||||
try {
|
||||
final decoded = jsonDecode(raw);
|
||||
if (decoded is Map) {
|
||||
decoded.forEach((key, value) {
|
||||
if (key is String && value is String) headers[key] = value;
|
||||
if (key is String && value is String) {
|
||||
headers[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
} on FormatException {
|
||||
@@ -185,7 +199,9 @@ class _StoreMigrator {
|
||||
|
||||
Future<void> migrateEnumIndex<T extends Enum>(StoreKey<int> legacyKey, MetadataKey<T> newKey, List<T> values) async {
|
||||
final index = await readLegacyStoreInt(legacyKey.id);
|
||||
if (index == null) return;
|
||||
if (index == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final enumValue = values.elementAtOrNull(index) ?? newKey.defaultValue;
|
||||
_cache[newKey] = enumValue;
|
||||
@@ -198,7 +214,9 @@ class _StoreMigrator {
|
||||
List<T> values,
|
||||
) async {
|
||||
final name = await readLegacyStoreString(legacyKey.id);
|
||||
if (name == null) return;
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final enumValue = values.firstWhere((e) => e.name == name, orElse: () => newKey.defaultValue);
|
||||
_cache[newKey] = enumValue;
|
||||
@@ -207,7 +225,9 @@ class _StoreMigrator {
|
||||
|
||||
Future<void> migrateBool(StoreKey<bool> legacyKey, MetadataKey<bool> newKey) async {
|
||||
final intValue = await readLegacyStoreInt(legacyKey.id);
|
||||
if (intValue == null) return;
|
||||
if (intValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolValue = intValue != 0;
|
||||
_cache[newKey] = boolValue;
|
||||
@@ -216,7 +236,9 @@ class _StoreMigrator {
|
||||
|
||||
Future<void> migrateInt(StoreKey<int> legacyKey, MetadataKey<int> newKey) async {
|
||||
final intValue = await readLegacyStoreInt(legacyKey.id);
|
||||
if (intValue == null) return;
|
||||
if (intValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache[newKey] = intValue;
|
||||
_migratedStoreIds.add(legacyKey.id);
|
||||
@@ -224,7 +246,9 @@ class _StoreMigrator {
|
||||
|
||||
Future<void> migrateString(StoreKey<String> legacyKey, MetadataKey<String> newKey) async {
|
||||
final value = await readLegacyStoreString(legacyKey.id);
|
||||
if (value == null) return;
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
_cache[newKey] = value;
|
||||
_migratedStoreIds.add(legacyKey.id);
|
||||
@@ -254,7 +278,9 @@ class _StoreMigrator {
|
||||
}
|
||||
|
||||
Future<void> deleteLegacyStoreRows(List<int> ids) async {
|
||||
if (ids.isEmpty) return;
|
||||
if (ids.isEmpty) {
|
||||
return;
|
||||
}
|
||||
await (_db.storeEntity.delete()..where((t) => t.id.isIn(ids))).go();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,9 @@ class SemVer {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other is SemVer && other.major == major && other.minor == minor && other.patch == patch;
|
||||
}
|
||||
|
||||
@@ -42,13 +42,17 @@ String? getServerUrl() {
|
||||
///
|
||||
String punycodeEncodeUrl(String serverUrl) {
|
||||
final serverUri = Uri.tryParse(serverUrl);
|
||||
if (serverUri == null || serverUri.host.isEmpty) return '';
|
||||
if (serverUri == null || serverUri.host.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
final encodedHost = Uri.decodeComponent(serverUri.host)
|
||||
.split('.')
|
||||
.map((segment) {
|
||||
// If segment is already ASCII, then return as it is.
|
||||
if (segment.runes.every((c) => c < 0x80)) return segment;
|
||||
if (segment.runes.every((c) => c < 0x80)) {
|
||||
return segment;
|
||||
}
|
||||
return 'xn--${punycodeEncode(segment)}';
|
||||
})
|
||||
.join('.');
|
||||
@@ -75,7 +79,9 @@ String punycodeEncodeUrl(String serverUrl) {
|
||||
///
|
||||
String? punycodeDecodeUrl(String? serverUrl) {
|
||||
final serverUri = serverUrl != null ? Uri.tryParse(serverUrl) : null;
|
||||
if (serverUri == null || serverUri.host.isEmpty) return null;
|
||||
if (serverUri == null || serverUri.host.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final decodedHost = serverUri.host
|
||||
.split('.')
|
||||
|
||||
Reference in New Issue
Block a user