diff --git a/ui/flutter/lib/features/settings/application/settings_controller.dart b/ui/flutter/lib/features/settings/application/settings_controller.dart index 311be7be..fdc33f19 100644 --- a/ui/flutter/lib/features/settings/application/settings_controller.dart +++ b/ui/flutter/lib/features/settings/application/settings_controller.dart @@ -19,6 +19,12 @@ class SettingsState { } } +class SettingsSaveResult { + const SettingsSaveResult({required this.btRestartRequired}); + + final bool btRestartRequired; +} + class SettingsController extends AsyncNotifier { Future _saveTail = Future.value(); int _saveRevision = 0; @@ -36,7 +42,7 @@ class SettingsController extends AsyncNotifier { state = AsyncValue.data(SettingsState(config: config)); } - Future save(DownloaderConfig config) { + Future save(DownloaderConfig config) { final snapshot = DownloaderConfig.fromJson(config.toJson()); final revision = ++_saveRevision; state = AsyncValue.data(SettingsState(config: config, saving: true)); @@ -47,10 +53,15 @@ class SettingsController extends AsyncNotifier { return result; } - Future _save(DownloaderConfig config, int revision) async { + Future _save(DownloaderConfig config, int revision) async { try { final service = ref.read(gopeedServiceProvider); final latest = await service.getConfig(); + final previousBt = ( + latest.protocolConfig.bt.listenPort, + latest.protocolConfig.bt.disableDht, + latest.protocolConfig.bt.disablePex, + ); config.extra ..windowState = latest.extra.windowState ..bookmarks = latest.extra.bookmarks @@ -64,6 +75,12 @@ class SettingsController extends AsyncNotifier { ref.read(appRuntimeControllerProvider.notifier).replaceDownloaderConfig(saved); if (revision == _saveRevision) state = AsyncValue.data(SettingsState(config: saved)); } + final savedBt = ( + saved.protocolConfig.bt.listenPort, + saved.protocolConfig.bt.disableDht, + saved.protocolConfig.bt.disablePex, + ); + return SettingsSaveResult(btRestartRequired: previousBt != savedBt); } finally { if (ref.mounted && revision == _saveRevision && state.value?.saving == true) { state = AsyncValue.data(state.requireValue.copyWith(saving: false)); diff --git a/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart b/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart index c48a031e..0f90b6b7 100644 --- a/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart +++ b/ui/flutter/lib/features/settings/presentation/pages/settings_page.dart @@ -625,7 +625,6 @@ class _SettingsPageState extends ConsumerState { ), SettingsItem( title: context.l10n.enableDht, - subtitle: context.l10n.restartRequired, child: shad.Switch( value: !config.protocolConfig.bt.disableDht, onChanged: (value) => _mutateConfig((next) => next.protocolConfig.bt.disableDht = !value), @@ -633,7 +632,6 @@ class _SettingsPageState extends ConsumerState { ), SettingsItem( title: context.l10n.enablePex, - subtitle: context.l10n.restartRequired, child: shad.Switch( value: !config.protocolConfig.bt.disablePex, onChanged: (value) => _mutateConfig((next) => next.protocolConfig.bt.disablePex = !value), @@ -1204,7 +1202,10 @@ class _SettingsPageState extends ConsumerState { final snapshot = DownloaderConfig.fromJson(config.toJson()); _loadedSignature = _signature(snapshot); try { - await ref.read(settingsControllerProvider.notifier).save(snapshot); + final result = await ref.read(settingsControllerProvider.notifier).save(snapshot); + if (mounted && result.btRestartRequired) { + _toast(context.l10n.restartRequired, type: AppToastType.info); + } return true; } catch (error) { if (mounted) _toast(error.toString()); diff --git a/ui/flutter/lib/l10n/app_ar.arb b/ui/flutter/lib/l10n/app_ar.arb index 6123f256..4b84f11e 100644 --- a/ui/flutter/lib/l10n/app_ar.arb +++ b/ui/flutter/lib/l10n/app_ar.arb @@ -208,7 +208,7 @@ "categoryName": "اسم الفئة", "categoryPath": "مسار الفئة", "autoCategorizeByExtension": "تصنيف تلقائي حسب نوع الملف", - "autoCategorizeByExtensionDescription": "توجيه التنزيلات إلى مجلد الفئة تلقائيًا حسب امتداد الملف عند الحفظ في مجلد التنزيل الافتراضي.", + "autoCategorizeByExtensionDescription": "توجيه التنزيلات إلى مجلد الفئة تلقائيًا حسب امتداد الملف عند الحفظ في مجلد التنزيل الافتراضي", "categoryExtensions": "امتدادات الملفات", "categoryExtensionsUsageHint": "افصل الامتدادات بفواصل أو مسافات ثم اضغط Enter.", "categoryExtensionsEmptyHint": "بدون الامتدادات، لن تُحفظ الملفات في هذا التصنيف تلقائيًا.", diff --git a/ui/flutter/lib/l10n/app_az.arb b/ui/flutter/lib/l10n/app_az.arb index 577b1937..5bbbec9b 100644 --- a/ui/flutter/lib/l10n/app_az.arb +++ b/ui/flutter/lib/l10n/app_az.arb @@ -215,7 +215,7 @@ "categoryName": "Kateqoriyanın Adı", "categoryPath": "Kateqoriyanın Yolu", "autoCategorizeByExtension": "Fayl tipinə görə avtomatik kateqoriyalaşdırma", - "autoCategorizeByExtensionDescription": "Standart yükləmə qovluğuna yadda saxlanarkən yükləmələr fayl uzantısına görə avtomatik olaraq kateqoriya qovluğuna yönləndirilir.", + "autoCategorizeByExtensionDescription": "Standart yükləmə qovluğuna yadda saxlanarkən yükləmələr fayl uzantısına görə avtomatik olaraq kateqoriya qovluğuna yönləndirilir", "categoryExtensions": "Fayl uzantıları", "categoryExtensionsUsageHint": "Uzantıları vergül və ya boşluqla ayırın, sonra Enter-a basın.", "categoryExtensionsEmptyHint": "Uzantı yoxdursa, fayllar bu kateqoriyaya avtomatik olaraq saxlanmır.", diff --git a/ui/flutter/lib/l10n/app_ca.arb b/ui/flutter/lib/l10n/app_ca.arb index 4e8fd62e..3cfb47fe 100644 --- a/ui/flutter/lib/l10n/app_ca.arb +++ b/ui/flutter/lib/l10n/app_ca.arb @@ -208,7 +208,7 @@ "categoryName": "Nom de la categoria", "categoryPath": "Ruta de la categoria", "autoCategorizeByExtension": "Categoritza automàticament segons el tipus de fitxer", - "autoCategorizeByExtensionDescription": "Les baixades es desen a la carpeta de categoria segons l'extensió del fitxer en utilitzar la carpeta de baixades predeterminada.", + "autoCategorizeByExtensionDescription": "Les baixades es desen a la carpeta de categoria segons l'extensió del fitxer en utilitzar la carpeta de baixades predeterminada", "categoryExtensions": "Extensions de fitxer", "categoryExtensionsUsageHint": "Separa les extensions amb comes o espais i prem Retorn.", "categoryExtensionsEmptyHint": "Sense extensions, els fitxers no es desaran aquí automàticament.", diff --git a/ui/flutter/lib/l10n/app_de.arb b/ui/flutter/lib/l10n/app_de.arb index 8e46d196..d05ccf6d 100644 --- a/ui/flutter/lib/l10n/app_de.arb +++ b/ui/flutter/lib/l10n/app_de.arb @@ -208,7 +208,7 @@ "categoryName": "Kategoriename", "categoryPath": "Kategoriepfad", "autoCategorizeByExtension": "Nach Dateityp automatisch kategorisieren", - "autoCategorizeByExtensionDescription": "Downloads werden beim Speichern im Standard-Download-Ordner anhand der Dateiendung automatisch einem Kategorieordner zugeordnet.", + "autoCategorizeByExtensionDescription": "Downloads werden beim Speichern im Standard-Download-Ordner anhand der Dateiendung automatisch einem Kategorieordner zugeordnet", "categoryExtensions": "Dateiendungen", "categoryExtensionsUsageHint": "Trenne Endungen mit Kommas oder Leerzeichen und drücke Enter.", "categoryExtensionsEmptyHint": "Ohne Endungen werden Dateien nicht automatisch dieser Kategorie zugeordnet.", diff --git a/ui/flutter/lib/l10n/app_en.arb b/ui/flutter/lib/l10n/app_en.arb index 3816a3fc..44ed0382 100644 --- a/ui/flutter/lib/l10n/app_en.arb +++ b/ui/flutter/lib/l10n/app_en.arb @@ -222,7 +222,7 @@ "categoryName": "Category Name", "categoryPath": "Category Path", "autoCategorizeByExtension": "Auto-categorize by file type", - "autoCategorizeByExtensionDescription": "Automatically route downloads into a category folder based on the file name when saving to the default download folder.", + "autoCategorizeByExtensionDescription": "Automatically route downloads into a category folder based on the file name when saving to the default download folder", "categoryExtensions": "Associated Extensions", "categoryExtensionsUsageHint": "Separate suffixes with commas or spaces, then press Enter.", "categoryExtensionsEmptyHint": "Without extensions, files won't be saved into this category automatically.", diff --git a/ui/flutter/lib/l10n/app_es.arb b/ui/flutter/lib/l10n/app_es.arb index d2daef8c..5a1110b7 100644 --- a/ui/flutter/lib/l10n/app_es.arb +++ b/ui/flutter/lib/l10n/app_es.arb @@ -208,7 +208,7 @@ "categoryName": "Nombre de categoría", "categoryPath": "Ruta de categoría", "autoCategorizeByExtension": "Categorizar automáticamente por tipo de archivo", - "autoCategorizeByExtensionDescription": "Las descargas se guardan automáticamente en la carpeta de categoría según la extensión del archivo al usar la carpeta de descargas predeterminada.", + "autoCategorizeByExtensionDescription": "Las descargas se guardan automáticamente en la carpeta de categoría según la extensión del archivo al usar la carpeta de descargas predeterminada", "categoryExtensions": "Extensiones de archivo", "categoryExtensionsUsageHint": "Separa las extensiones con comas o espacios y pulsa Intro.", "categoryExtensionsEmptyHint": "Sin extensiones, los archivos no se guardarán automáticamente en esta categoría.", diff --git a/ui/flutter/lib/l10n/app_fa.arb b/ui/flutter/lib/l10n/app_fa.arb index 97478f13..3459113a 100644 --- a/ui/flutter/lib/l10n/app_fa.arb +++ b/ui/flutter/lib/l10n/app_fa.arb @@ -208,7 +208,7 @@ "categoryName": "نام دسته‌بندی", "categoryPath": "مسیر دسته‌بندی", "autoCategorizeByExtension": "دسته‌بندی خودکار بر اساس نوع فایل", - "autoCategorizeByExtensionDescription": "هنگام ذخیره در پوشه پیش‌فرض دانلود، دانلودها بر اساس پسوند فایل به پوشه دسته مربوطه منتقل می‌شوند.", + "autoCategorizeByExtensionDescription": "هنگام ذخیره در پوشه پیش‌فرض دانلود، دانلودها بر اساس پسوند فایل به پوشه دسته مربوطه منتقل می‌شوند", "categoryExtensions": "پسوندهای فایل", "categoryExtensionsUsageHint": "پسوندها را با ویرگول یا فاصله جدا کنید و Enter را بزنید.", "categoryExtensionsEmptyHint": "بدون پسوندها، فایل‌ها به‌صورت خودکار در این دسته ذخیره نمی‌شوند.", diff --git a/ui/flutter/lib/l10n/app_fr.arb b/ui/flutter/lib/l10n/app_fr.arb index 23566819..e3978284 100644 --- a/ui/flutter/lib/l10n/app_fr.arb +++ b/ui/flutter/lib/l10n/app_fr.arb @@ -208,7 +208,7 @@ "categoryName": "Nom de la catégorie", "categoryPath": "Chemin de la catégorie", "autoCategorizeByExtension": "Catégoriser automatiquement selon le type de fichier", - "autoCategorizeByExtensionDescription": "Les téléchargements sont placés dans un dossier de catégorie selon l'extension du fichier lors de l'enregistrement dans le dossier de téléchargement par défaut.", + "autoCategorizeByExtensionDescription": "Les téléchargements sont placés dans un dossier de catégorie selon l'extension du fichier lors de l'enregistrement dans le dossier de téléchargement par défaut", "categoryExtensions": "Extensions de fichier", "categoryExtensionsUsageHint": "Séparez les extensions par virgules ou espaces, puis appuyez sur Entrée.", "categoryExtensionsEmptyHint": "Sans extensions, les fichiers ne seront pas enregistrés ici automatiquement.", diff --git a/ui/flutter/lib/l10n/app_hu.arb b/ui/flutter/lib/l10n/app_hu.arb index d2e3cbc2..2df11da3 100644 --- a/ui/flutter/lib/l10n/app_hu.arb +++ b/ui/flutter/lib/l10n/app_hu.arb @@ -208,7 +208,7 @@ "categoryName": "Kategória neve", "categoryPath": "Kategória útvonala", "autoCategorizeByExtension": "Automatikus kategorizálás fájltípus szerint", - "autoCategorizeByExtensionDescription": "Az alapértelmezett letöltési mappa használatakor a letöltések a fájl kiterjesztése alapján automatikusan a kategória mappájába kerülnek.", + "autoCategorizeByExtensionDescription": "Az alapértelmezett letöltési mappa használatakor a letöltések a fájl kiterjesztése alapján automatikusan a kategória mappájába kerülnek", "categoryExtensions": "Fájlkiterjesztések", "categoryExtensionsUsageHint": "A kiterjesztéseket vesszővel vagy szóközzel válaszd el, majd nyomd le az Enter billentyűt.", "categoryExtensionsEmptyHint": "Kiterjesztések nélkül a fájlok nem kerülnek automatikusan ebbe a kategóriába.", diff --git a/ui/flutter/lib/l10n/app_id.arb b/ui/flutter/lib/l10n/app_id.arb index a2383e10..b264ee12 100644 --- a/ui/flutter/lib/l10n/app_id.arb +++ b/ui/flutter/lib/l10n/app_id.arb @@ -208,7 +208,7 @@ "categoryName": "Nama Kategori", "categoryPath": "Path Kategori", "autoCategorizeByExtension": "Kategorikan otomatis berdasarkan jenis file", - "autoCategorizeByExtensionDescription": "Unduhan dialihkan ke folder kategori berdasarkan ekstensi file saat disimpan ke folder unduhan bawaan.", + "autoCategorizeByExtensionDescription": "Unduhan dialihkan ke folder kategori berdasarkan ekstensi file saat disimpan ke folder unduhan bawaan", "categoryExtensions": "Ekstensi file", "categoryExtensionsUsageHint": "Pisahkan ekstensi dengan koma atau spasi, lalu tekan Enter.", "categoryExtensionsEmptyHint": "Tanpa ekstensi, file tidak akan otomatis disimpan ke kategori ini.", diff --git a/ui/flutter/lib/l10n/app_it.arb b/ui/flutter/lib/l10n/app_it.arb index 1a8df506..8f4afd36 100644 --- a/ui/flutter/lib/l10n/app_it.arb +++ b/ui/flutter/lib/l10n/app_it.arb @@ -208,7 +208,7 @@ "categoryName": "Nome categoria", "categoryPath": "Percorso categoria", "autoCategorizeByExtension": "Categorizza automaticamente per tipo di file", - "autoCategorizeByExtensionDescription": "Il download viene instradato automaticamente nella cartella della categoria in base all'estensione quando si salva nella cartella di download predefinita.", + "autoCategorizeByExtensionDescription": "Il download viene instradato automaticamente nella cartella della categoria in base all'estensione quando si salva nella cartella di download predefinita", "categoryExtensions": "Estensioni file", "categoryExtensionsUsageHint": "Separa le estensioni con virgole o spazi e premi Invio.", "categoryExtensionsEmptyHint": "Senza estensioni, i file non verranno salvati qui automaticamente.", diff --git a/ui/flutter/lib/l10n/app_ja.arb b/ui/flutter/lib/l10n/app_ja.arb index 2ffb0d45..68f60558 100644 --- a/ui/flutter/lib/l10n/app_ja.arb +++ b/ui/flutter/lib/l10n/app_ja.arb @@ -208,7 +208,7 @@ "categoryName": "カテゴリ名", "categoryPath": "カテゴリパス", "autoCategorizeByExtension": "ファイル種別で自動分類", - "autoCategorizeByExtensionDescription": "既定のダウンロードフォルダーに保存する際、拡張子に基づいて分類フォルダーへ自動的に振り分けます。", + "autoCategorizeByExtensionDescription": "既定のダウンロードフォルダーに保存する際、拡張子に基づいて分類フォルダーへ自動的に振り分けます", "categoryExtensions": "ファイル拡張子", "categoryExtensionsUsageHint": "カンマやスペースで拡張子を区切り、Enterで追加します。", "categoryExtensionsEmptyHint": "拡張子が未設定の場合、ファイルは自動的にこの分類へ保存されません。", diff --git a/ui/flutter/lib/l10n/app_ko.arb b/ui/flutter/lib/l10n/app_ko.arb index 1973cbd0..181a31a1 100644 --- a/ui/flutter/lib/l10n/app_ko.arb +++ b/ui/flutter/lib/l10n/app_ko.arb @@ -208,7 +208,7 @@ "categoryName": "카테고리 이름", "categoryPath": "카테고리 경로", "autoCategorizeByExtension": "파일 형식별 자동 분류", - "autoCategorizeByExtensionDescription": "기본 다운로드 폴더에 저장할 때 확장자에 따라 분류 폴더로 자동 이동합니다.", + "autoCategorizeByExtensionDescription": "기본 다운로드 폴더에 저장할 때 확장자에 따라 분류 폴더로 자동 이동합니다", "categoryExtensions": "파일 확장자", "categoryExtensionsUsageHint": "쉼표나 공백으로 확장자를 구분하고 Enter를 눌러 추가하세요.", "categoryExtensionsEmptyHint": "확장자가 없으면 파일이 이 분류로 자동 저장되지 않습니다.", diff --git a/ui/flutter/lib/l10n/app_pl.arb b/ui/flutter/lib/l10n/app_pl.arb index d953dbaa..9d467855 100644 --- a/ui/flutter/lib/l10n/app_pl.arb +++ b/ui/flutter/lib/l10n/app_pl.arb @@ -208,7 +208,7 @@ "categoryName": "Nazwa kategorii", "categoryPath": "Ścieżka kategorii", "autoCategorizeByExtension": "Automatyczna kategorizacja według typu pliku", - "autoCategorizeByExtensionDescription": "Pobierane pliki są automatycznie zapisywane w folderze kategorii na podstawie rozszerzenia, gdy używany jest domyślny folder pobierania.", + "autoCategorizeByExtensionDescription": "Pobierane pliki są automatycznie zapisywane w folderze kategorii na podstawie rozszerzenia, gdy używany jest domyślny folder pobierania", "categoryExtensions": "Rozszerzenia plików", "categoryExtensionsUsageHint": "Rozdzielaj rozszerzenia przecinkami lub spacjami i naciskaj Enter.", "categoryExtensionsEmptyHint": "Bez rozszerzeń pliki nie będą automatycznie zapisywane w tej kategorii.", diff --git a/ui/flutter/lib/l10n/app_pt.arb b/ui/flutter/lib/l10n/app_pt.arb index 464e7960..2ee1a4f7 100644 --- a/ui/flutter/lib/l10n/app_pt.arb +++ b/ui/flutter/lib/l10n/app_pt.arb @@ -208,7 +208,7 @@ "categoryName": "Nome da Categoria", "categoryPath": "Caminho da Categoria", "autoCategorizeByExtension": "Categorizar automaticamente por tipo de arquivo", - "autoCategorizeByExtensionDescription": "Envia os downloads para a pasta da categoria com base na extensão ao salvar na pasta de download padrão.", + "autoCategorizeByExtensionDescription": "Envia os downloads para a pasta da categoria com base na extensão ao salvar na pasta de download padrão", "categoryExtensions": "Extensões de arquivo", "categoryExtensionsUsageHint": "Separe as extensões com vírgulas ou espaços e prima Enter.", "categoryExtensionsEmptyHint": "Sem extensões, os ficheiros não serão guardados aqui automaticamente.", diff --git a/ui/flutter/lib/l10n/app_ru.arb b/ui/flutter/lib/l10n/app_ru.arb index fd9abe4a..4e6bd7cc 100644 --- a/ui/flutter/lib/l10n/app_ru.arb +++ b/ui/flutter/lib/l10n/app_ru.arb @@ -208,7 +208,7 @@ "categoryName": "Название категории", "categoryPath": "Путь категории", "autoCategorizeByExtension": "Автокатегоризация по типу файла", - "autoCategorizeByExtensionDescription": "Загрузки автоматически сохраняются в папку категории по расширению файла, если выбрана папка загрузки по умолчанию.", + "autoCategorizeByExtensionDescription": "Загрузки автоматически сохраняются в папку категории по расширению файла, если выбрана папка загрузки по умолчанию", "categoryExtensions": "Расширения файлов", "categoryExtensionsUsageHint": "Разделяйте расширения запятыми или пробелами и нажимайте Enter.", "categoryExtensionsEmptyHint": "Без расширений файлы не будут автоматически сохранены в эту категорию.", diff --git a/ui/flutter/lib/l10n/app_sk.arb b/ui/flutter/lib/l10n/app_sk.arb index afdf6695..4e9d3c16 100644 --- a/ui/flutter/lib/l10n/app_sk.arb +++ b/ui/flutter/lib/l10n/app_sk.arb @@ -222,7 +222,7 @@ "categoryName": "Názov kategórie", "categoryPath": "Cesta kategórie", "autoCategorizeByExtension": "Automatická kategorizácia podľa typu súboru", - "autoCategorizeByExtensionDescription": "Sťahovania sa pri ukladaní do predvoleného priečinka sťahovania automaticky presúvajú do priečinka kategórie podľa prípony súboru.", + "autoCategorizeByExtensionDescription": "Sťahovania sa pri ukladaní do predvoleného priečinka sťahovania automaticky presúvajú do priečinka kategórie podľa prípony súboru", "categoryExtensions": "Prípony súborov", "categoryExtensionsUsageHint": "Oddeľujte prípony čiarkami alebo medzerami a stlačte Enter.", "categoryExtensionsEmptyHint": "Bez prípon sa súbory automaticky neuložia do tejto kategórie.", diff --git a/ui/flutter/lib/l10n/app_ta.arb b/ui/flutter/lib/l10n/app_ta.arb index 44acf778..d2adc8b3 100644 --- a/ui/flutter/lib/l10n/app_ta.arb +++ b/ui/flutter/lib/l10n/app_ta.arb @@ -208,7 +208,7 @@ "categoryName": "வகை பெயர்", "categoryPath": "வகை பாதை", "autoCategorizeByExtension": "கோப்பு வகை வாரியாக தானாக வகைப்படுத்து", - "autoCategorizeByExtensionDescription": "இயல்புநிலை பதிவிறக்கக் கோப்புறையில் சேமிக்கும்போது, கோப்பு நீட்டிப்பின் அடிப்படையில் வகைக் கோப்புறைக்கு தானாக அனுப்பப்படும்.", + "autoCategorizeByExtensionDescription": "இயல்புநிலை பதிவிறக்கக் கோப்புறையில் சேமிக்கும்போது, கோப்பு நீட்டிப்பின் அடிப்படையில் வகைக் கோப்புறைக்கு தானாக அனுப்பப்படும்", "categoryExtensions": "கோப்பு நீட்டிப்புகள்", "categoryExtensionsUsageHint": "நீட்டிப்புகளை காற்புள்ளிகள் அல்லது இடைவெளிகளால் பிரித்து Enter அழுத்தவும்.", "categoryExtensionsEmptyHint": "நீட்டிப்புகள் இல்லாததால், கோப்புகள் இந்த வகைப்பாட்டில் தானாகச் சேமிக்கப்படாது.", diff --git a/ui/flutter/lib/l10n/app_tr.arb b/ui/flutter/lib/l10n/app_tr.arb index 7fe573c7..3d24bba7 100644 --- a/ui/flutter/lib/l10n/app_tr.arb +++ b/ui/flutter/lib/l10n/app_tr.arb @@ -208,7 +208,7 @@ "categoryName": "Kategori Adı", "categoryPath": "Kategori Yolu", "autoCategorizeByExtension": "Dosya tipine göre otomatik sınıflandır", - "autoCategorizeByExtensionDescription": "Varsayılan indirme klasörüne kaydedilirken dosya uzantısına göre ilgili klasöre otomatik yönlendirir.", + "autoCategorizeByExtensionDescription": "Varsayılan indirme klasörüne kaydedilirken dosya uzantısına göre ilgili klasöre otomatik yönlendirir", "categoryExtensions": "Dosya uzantıları", "categoryExtensionsUsageHint": "Sonekleri virgül veya boşlukla ayırıp Enter'a basın.", "categoryExtensionsEmptyHint": "Uzantı yoksa dosyalar bu kategoriye otomatik olarak kaydedilmez.", diff --git a/ui/flutter/lib/l10n/app_uk.arb b/ui/flutter/lib/l10n/app_uk.arb index 8dc51080..e41f7f83 100644 --- a/ui/flutter/lib/l10n/app_uk.arb +++ b/ui/flutter/lib/l10n/app_uk.arb @@ -208,7 +208,7 @@ "categoryName": "Назва категорії", "categoryPath": "Шлях категорії", "autoCategorizeByExtension": "Автокатегоризація за типом файлу", - "autoCategorizeByExtensionDescription": "Завантаження автоматично зберігаються в папку категорії за розширенням файлу, якщо вибрано папку завантаження за замовчуванням.", + "autoCategorizeByExtensionDescription": "Завантаження автоматично зберігаються в папку категорії за розширенням файлу, якщо вибрано папку завантаження за замовчуванням", "categoryExtensions": "Розширення файлів", "categoryExtensionsUsageHint": "Розділяйте розширення комами або пробілами та натискайте Enter.", "categoryExtensionsEmptyHint": "Без розширень файли не зберігатимуться в цю категорію автоматично.", diff --git a/ui/flutter/lib/l10n/app_vi.arb b/ui/flutter/lib/l10n/app_vi.arb index 91d7cf89..5baa7d08 100644 --- a/ui/flutter/lib/l10n/app_vi.arb +++ b/ui/flutter/lib/l10n/app_vi.arb @@ -208,7 +208,7 @@ "categoryName": "Tên danh mục", "categoryPath": "Đường dẫn danh mục", "autoCategorizeByExtension": "Tự động phân loại theo loại tệp", - "autoCategorizeByExtensionDescription": "Tải xuống sẽ được chuyển vào thư mục danh mục dựa trên phần mở rộng tệp khi lưu vào thư mục tải xuống mặc định.", + "autoCategorizeByExtensionDescription": "Tải xuống sẽ được chuyển vào thư mục danh mục dựa trên phần mở rộng tệp khi lưu vào thư mục tải xuống mặc định", "categoryExtensions": "Phần mở rộng tệp", "categoryExtensionsUsageHint": "Phân tách phần mở rộng bằng dấu phẩy hoặc khoảng trắng rồi nhấn Enter.", "categoryExtensionsEmptyHint": "Không có phần mở rộng, tệp sẽ không tự động được lưu vào danh mục này.", diff --git a/ui/flutter/lib/l10n/app_zh.arb b/ui/flutter/lib/l10n/app_zh.arb index 56eab1d9..9b0ea544 100644 --- a/ui/flutter/lib/l10n/app_zh.arb +++ b/ui/flutter/lib/l10n/app_zh.arb @@ -208,7 +208,7 @@ "categoryName": "分类名称", "categoryPath": "分类路径", "autoCategorizeByExtension": "按文件类型自动分类", - "autoCategorizeByExtensionDescription": "保存到默认下载目录时,根据文件后缀自动归入对应分类文件夹。", + "autoCategorizeByExtensionDescription": "保存到默认下载目录时,根据文件后缀自动归入对应分类文件夹", "categoryExtensions": "文件后缀关联", "categoryExtensionsUsageHint": "支持逗号/空格分隔后缀,按回车添加。", "categoryExtensionsEmptyHint": "未设置后缀,文件不会自动归入此分类。", diff --git a/ui/flutter/lib/l10n/app_zh_TW.arb b/ui/flutter/lib/l10n/app_zh_TW.arb index 0b36e96c..8eb05b56 100644 --- a/ui/flutter/lib/l10n/app_zh_TW.arb +++ b/ui/flutter/lib/l10n/app_zh_TW.arb @@ -208,7 +208,7 @@ "categoryName": "分類名稱", "categoryPath": "分類路徑", "autoCategorizeByExtension": "按檔案類型自動分類", - "autoCategorizeByExtensionDescription": "儲存至預設下載目錄時,根據檔案副檔名自動歸入對應分類資料夾。", + "autoCategorizeByExtensionDescription": "儲存至預設下載目錄時,根據檔案副檔名自動歸入對應分類資料夾", "categoryExtensions": "檔案副檔名", "categoryExtensionsUsageHint": "支援逗號/空白分隔後綴,按回車新增。", "categoryExtensionsEmptyHint": "未設定後綴,檔案不會自動歸入此分類。", diff --git a/ui/flutter/test/features/settings/application/settings_controller_test.dart b/ui/flutter/test/features/settings/application/settings_controller_test.dart index 0d6816f7..133160dc 100644 --- a/ui/flutter/test/features/settings/application/settings_controller_test.dart +++ b/ui/flutter/test/features/settings/application/settings_controller_test.dart @@ -99,6 +99,43 @@ void main() { expect(saved.saving, isFalse); }); + for (final field in ['port', 'DHT', 'PEX']) { + test('$field restart notice follows successful persisted changes only', () async { + var backend = DownloaderConfig(); + var failNextSave = false; + final registry = CapabilityRegistry(createAppCapabilityCodecs()) + ..bind(GopeedMethods.getConfig, (_) => DownloaderConfig.fromJson(backend.toJson())) + ..bind(GopeedMethods.putConfig, (config) { + if (failNextSave) { + failNextSave = false; + throw StateError('offline'); + } + backend = DownloaderConfig.fromJson(config.toJson()); + return const RpcUnit(); + }); + final container = _settingsContainer(registry); + addTearDown(container.dispose); + final initial = await container.read(settingsControllerProvider.future); + final controller = container.read(settingsControllerProvider.notifier); + final draft = DownloaderConfig.fromJson(initial.config.toJson()); + switch (field) { + case 'port': + draft.protocolConfig.bt.listenPort = 6881; + case 'DHT': + draft.protocolConfig.bt.disableDht = true; + case 'PEX': + draft.protocolConfig.bt.disablePex = true; + } + failNextSave = true; + await expectLater(controller.save(draft), throwsStateError); + expect((await controller.save(draft)).btRestartRequired, isTrue); + expect((await controller.save(draft)).btRestartRequired, isFalse); + draft.protocolConfig.bt.seedRatio = 2; + expect((await controller.save(draft)).btRestartRequired, isFalse); + expect((await controller.save(initial.config)).btRestartRequired, isTrue); + }); + } + test('rapid full config saves run in order and keep the latest user edits', () async { final backend = DownloaderConfig(); final entered = Completer(); @@ -127,7 +164,8 @@ void main() { final savingSecond = controller.save(second); expect(puts.length, 1); release.complete(); - await Future.wait([savingFirst, savingSecond]); + final results = await Future.wait([savingFirst, savingSecond]); + expect(results.map((result) => result.btRestartRequired), [true, false]); expect(puts, hasLength(2)); expect(puts[0].protocolConfig.bt.listenPort, 6881); expect(puts[1].protocolConfig.bt.listenPort, 6881); diff --git a/ui/flutter/test/widget_test.dart b/ui/flutter/test/widget_test.dart index 34bc10d9..882e391c 100644 --- a/ui/flutter/test/widget_test.dart +++ b/ui/flutter/test/widget_test.dart @@ -1636,6 +1636,46 @@ void main() { expect(tester.takeException(), isNull); }); + testWidgets('BT settings show a restart message only after an affected auto-save', (tester) async { + await _setTestSize(tester, const Size(1024, 900)); + final controller = FakeSettingsController()..btRestartRequired = true; + await tester.pumpWidget( + ProviderScope( + overrides: [ + appRuntimeControllerProvider.overrideWith(FakeRuntimeController.new), + appPlatformControllerProvider.overrideWith(FakePlatformController.new), + settingsControllerProvider.overrideWith(() => controller), + ], + child: const _SettingsTestApp(), + ), + ); + await tester.pumpAndSettle(); + await tester.tap(find.text('Downloads')); + await tester.pumpAndSettle(); + const message = 'This setting takes effect after restarting the app'; + expect(find.text(message), findsNothing); + final port = find.byKey(const ValueKey('bt-listen-port-input')); + await tester.ensureVisible(port); + await tester.pumpAndSettle(); + await tester.enterText(port, '6881'); + await tester.pump(const Duration(milliseconds: 500)); + expect(find.text(message), findsNothing); + await tester.pump(const Duration(milliseconds: 200)); + await tester.pump(const Duration(milliseconds: 300)); + expect(find.text(message), findsOneWidget); + expect(tester.widget(find.byType(AppToastContent)).type, AppToastType.info); + await tester.pump(const Duration(seconds: 6)); + await tester.pumpAndSettle(); + controller.btRestartRequired = false; + final seedRatio = find.byKey(const ValueKey('bt-seed-ratio-input')); + await tester.ensureVisible(seedRatio); + await tester.enterText(seedRatio, '2'); + await tester.pump(const Duration(milliseconds: 700)); + await tester.pumpAndSettle(); + expect(find.text(message), findsNothing); + expect(tester.takeException(), isNull); + }); + testWidgets('settings FTP connections save into the FTP protocol config', (WidgetTester tester) async { await _setTestSize(tester, const Size(1024, 900)); final settingsController = FakeSettingsController(); @@ -6181,12 +6221,15 @@ ApiServerState _testApiServerState({ } class FakeSettingsController extends SettingsController { + bool btRestartRequired = false; + @override Future build() async => SettingsState(config: DownloaderConfig()); @override - Future save(DownloaderConfig config) async { + Future save(DownloaderConfig config) async { state = AsyncValue.data(SettingsState(config: config)); + return SettingsSaveResult(btRestartRequired: btRestartRequired); } }