diff --git a/mobile/lib/constants/locales.dart b/mobile/lib/constants/locales.dart index 429a3718d..ad405841e 100644 --- a/mobile/lib/constants/locales.dart +++ b/mobile/lib/constants/locales.dart @@ -1,7 +1,9 @@ import 'dart:ui'; +const defaultAppLocale = Locale('ru'); + const Map locales = { - // Default locale + // Fallback locale for missing translations 'English (en)': Locale('en'), // Additional locales 'Arabic (ar)': Locale('ar'), diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 21189783b..d224760d4 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -309,6 +309,7 @@ class MainWidget extends StatelessWidget { Widget build(BuildContext context) { return EasyLocalization( supportedLocales: locales.values.toList(), + startLocale: defaultAppLocale, path: translationsPath, useFallbackTranslations: true, fallbackLocale: locales.values.first, diff --git a/mobile/lib/pages/common/splash_screen.page.dart b/mobile/lib/pages/common/splash_screen.page.dart index 385dcdce2..c83bcce22 100644 --- a/mobile/lib/pages/common/splash_screen.page.dart +++ b/mobile/lib/pages/common/splash_screen.page.dart @@ -41,6 +41,7 @@ class BootstrapErrorWidget extends StatelessWidget { return EasyLocalization( supportedLocales: locales.values.toList(), + startLocale: defaultAppLocale, path: translationsPath, useFallbackTranslations: true, fallbackLocale: locales.values.first, diff --git a/mobile/lib/services/localization.service.dart b/mobile/lib/services/localization.service.dart index af6389424..213b9e11b 100644 --- a/mobile/lib/services/localization.service.dart +++ b/mobile/lib/services/localization.service.dart @@ -12,6 +12,7 @@ Future loadTranslations() async { final controller = EasyLocalizationController( supportedLocales: locales.values.toList(), + startLocale: defaultAppLocale, useFallbackTranslations: true, saveLocale: true, assetLoader: const CodegenLoader(), diff --git a/mobile/lib/utils/url_helper.dart b/mobile/lib/utils/url_helper.dart index 3bcdca06f..ecdb2255a 100644 --- a/mobile/lib/utils/url_helper.dart +++ b/mobile/lib/utils/url_helper.dart @@ -2,6 +2,8 @@ import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:punycode/punycode.dart'; +const defaultServerUrl = 'https://immich.kusoft.xyz'; + /// Normalizes a server URL, guaranteeing that it has a schema and no trailing slashes String normalizeServerUrl(String url) { final trimmedUrl = url.trim(); diff --git a/mobile/lib/widgets/forms/login/login_form.dart b/mobile/lib/widgets/forms/login/login_form.dart index 317192af8..9a1e7dd94 100644 --- a/mobile/lib/widgets/forms/login/login_form.dart +++ b/mobile/lib/widgets/forms/login/login_form.dart @@ -164,9 +164,7 @@ class LoginForm extends HookConsumerWidget { useEffect(() { final serverUrl = getServerUrl(); - if (serverUrl != null) { - serverEndpointController.text = serverUrl; - } + serverEndpointController.text = serverUrl ?? defaultServerUrl; return null; }, []); diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 640d85c36..40d0ad756 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -2,7 +2,7 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone publish_to: 'none' -version: 3.3.1+3030199 +version: 3.3.1-local.2+3030200 environment: sdk: '>=3.12.0 <4.0.0' diff --git a/web/src/app.html b/web/src/app.html index a99876970..5f5319739 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -1,6 +1,19 @@ + diff --git a/web/src/lib/components/sidebar/Sidebar.spec.ts b/web/src/lib/components/sidebar/Sidebar.spec.ts index 1d2dd35bc..3125c2ee5 100644 --- a/web/src/lib/components/sidebar/Sidebar.spec.ts +++ b/web/src/lib/components/sidebar/Sidebar.spec.ts @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/svelte'; +import { fireEvent, render, screen } from '@testing-library/svelte'; import { vi } from 'vitest'; import SideBarSection from '$lib/components/sidebar/Sidebar.svelte'; import { sidebarStore } from '$lib/stores/sidebar.svelte'; @@ -77,4 +77,31 @@ describe('Sidebar component', () => { // then expect(sidebarStore.reset).toHaveBeenCalled(); }); + + it.each` + isFullSidebar | isSidebarOpen | shouldBubble + ${false} | ${false} | ${true} + ${false} | ${true} | ${false} + ${true} | ${false} | ${true} + ${true} | ${true} | ${true} + `( + 'Escape bubbles=$shouldBubble when isFullSidebar=$isFullSidebar and isSidebarOpen=$isSidebarOpen', + async ({ isFullSidebar, isSidebarOpen, shouldBubble }) => { + mocks.mediaQueryManager.isFullSidebar = isFullSidebar; + sidebarStore.isOpen = isSidebarOpen; + render(SideBarSection); + vi.mocked(sidebarStore.reset).mockClear(); + + const onDocumentKeydown = vi.fn(); + document.addEventListener('keydown', onDocumentKeydown); + try { + await fireEvent.keyDown(screen.getByTestId('sidebar-parent'), { key: 'Escape', code: 'Escape' }); + + expect(onDocumentKeydown).toHaveBeenCalledTimes(shouldBubble ? 1 : 0); + expect(sidebarStore.reset).toHaveBeenCalledTimes(shouldBubble ? 0 : 1); + } finally { + document.removeEventListener('keydown', onDocumentKeydown); + } + }, + ); });