diff --git a/assets/CHANGELOG.md b/assets/CHANGELOG.md index f468767642..4019ca38de 100644 --- a/assets/CHANGELOG.md +++ b/assets/CHANGELOG.md @@ -1,8 +1,14 @@ ## 1.11.0 (2023-) +- feat: optionally enable HTTPS (encryption) when share via link (@Tienisto) +- feat: use switches instead of dropdowns for settings (@forecaster-cyber) +- feat: text message dialog is multiline only (@Tienisto) +- feat: add option to disable animations (@Tienisto) - feat(desktop): bind "ESC" key to go to the previous page (@RiverTwilight, @Tienisto) - feat(android, ios): open link in new browser tab (@Tienisto) - feat(linux): enable autostart feature (@TheGB0077) +- fix(android, ios): Save GIFs and image metadata (@natsuk4ze) +- fix(desktop): GPU usage when hidden to tray (@Tienisto) ## 1.10.0 (2023-06-02) diff --git a/assets/i18n/_missing_translations_bn.json b/assets/i18n/_missing_translations_bn.json index a0016ab802..9b969995fe 100644 --- a/assets/i18n/_missing_translations_bn.json +++ b/assets/i18n/_missing_translations_bn.json @@ -26,7 +26,8 @@ "colorOptions": { "system": "System" }, - "saveWindowPlacement": "Quit: Save window placement" + "saveWindowPlacement": "Quit: Save window placement", + "animations": "Animations" }, "receive": { "downloads": "(Downloads)" @@ -34,7 +35,8 @@ "network": { "multicastGroup": "Multicast", "multicastGroupWarning": "You might not be detected by other devices because you are using a custom multicast address. (default: {defaultMulticast})" - } + }, + "advancedSettings": "Advanced settings" }, "troubleshootPage": { "title": "Troubleshoot", diff --git a/assets/i18n/_missing_translations_fa.json b/assets/i18n/_missing_translations_fa.json index 68c22596fe..08188eae84 100644 --- a/assets/i18n/_missing_translations_fa.json +++ b/assets/i18n/_missing_translations_fa.json @@ -2,5 +2,11 @@ "@@info": [ "Here are translations that exist in but not in .", "After editing this file, you can run 'dart run slang apply --locale=fa' to quickly apply the newly added translations." - ] + ], + "settingsTab": { + "general": { + "animations": "Animations" + }, + "advancedSettings": "Advanced settings" + } } diff --git a/assets/i18n/_unused_translations.json b/assets/i18n/_unused_translations.json index 06fbf73d25..5aa4230449 100644 --- a/assets/i18n/_unused_translations.json +++ b/assets/i18n/_unused_translations.json @@ -11,6 +11,11 @@ }, "sendTab": { "thisDevice": "This Device" + }, + "dialogs": { + "messageInput": { + "multiline": "Multiline" + } } }, "ar": {}, diff --git a/assets/i18n/strings.i18n.json b/assets/i18n/strings.i18n.json index ff26afe088..ba476c1258 100644 --- a/assets/i18n/strings.i18n.json +++ b/assets/i18n/strings.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Quit: Save window placement", "minimizeToTray": "Quit: Minimize to tray", "launchAtStartup": "Autostart after login", - "launchMinimized": "Autostart: Start hidden" + "launchMinimized": "Autostart: Start hidden", + "animations": "Animations" }, "receive": { "title": "Receive", @@ -114,7 +115,8 @@ "encryption": "Encryption", "multicastGroup": "Multicast", "multicastGroupWarning": "You might not be detected by other devices because you are using a custom multicast address. (default: {defaultMulticast})" - } + }, + "advancedSettings": "Advanced settings" }, "troubleshootPage": { "title": "Troubleshoot", diff --git a/assets/i18n/strings_ar.i18n.json b/assets/i18n/strings_ar.i18n.json index c75350ba88..0870ebe07f 100644 --- a/assets/i18n/strings_ar.i18n.json +++ b/assets/i18n/strings_ar.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "إنهاء: حفظ موقع النافذة", "minimizeToTray": "إنهاء : أخفاء في شريط المهام", "launchAtStartup": "تشغيل تلقائي بعد تسجيل الدخول", - "launchMinimized": "تشغيل تلقائي: ابدأ مخفيًا" + "launchMinimized": "تشغيل تلقائي: ابدأ مخفيًا", + "animations": "الرسوم المتحركة" }, "receive": { "title": "استلم", @@ -114,7 +115,8 @@ "encryption": "التشفير", "multicastGroup": "فرق البث المتعدد", "multicastGroupWarning": "ربما لا يتم الكشف عنك من قبل الأجهزة الأخرى لأنك تستخدم عنوان بث متعدد مخصص. (الافتراضي: {defaultMulticast})" - } + }, + "advancedSettings": "الإعدادات المتقدمة" }, "troubleshootPage": { "title": "حل المشكلات", diff --git a/assets/i18n/strings_ca.i18n.json b/assets/i18n/strings_ca.i18n.json index c878007a89..ce01da7600 100644 --- a/assets/i18n/strings_ca.i18n.json +++ b/assets/i18n/strings_ca.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Surt: desa la ubicació de la finestra", "minimizeToTray": "Surt: Minimitzar a la safata", "launchAtStartup": "Inici automàtic després d'iniciar sessió", - "launchMinimized": "Inici automàtic: Inici minimitzat" + "launchMinimized": "Inici automàtic: Inici minimitzat", + "animations": "Animacions" }, "receive": { "title": "Rebre", @@ -114,7 +115,8 @@ "encryption": "Encriptació", "multicastGroup": "Multicast", "multicastGroupWarning": "Podria no ser detectat per altres dispositius perquè està utilitzant una adreça multicast personalitzada. (per defecte: {defaultMulticast})" - } + }, + "advancedSettings": "Configuració avançada" }, "troubleshootPage": { "title": "Solucionar problemes", diff --git a/assets/i18n/strings_cs.i18n.json b/assets/i18n/strings_cs.i18n.json index cadf6ef8e3..a5c3b03a85 100644 --- a/assets/i18n/strings_cs.i18n.json +++ b/assets/i18n/strings_cs.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Při ukončení uložit umístění okna", "minimizeToTray": "Při ukončení minimalizovat do lišty", "launchAtStartup": "Automatické spuštění po přihlášení", - "launchMinimized": "Automatické spuštění: skrytý start" + "launchMinimized": "Automatické spuštění: skrytý start", + "animations": "Animace" }, "receive": { "title": "Příjmout", @@ -114,7 +115,8 @@ "encryption": "Šifrování", "multicastGroup": "Multicast", "multicastGroupWarning": "Je možné, že vás ostatní zařízení nezjistí, protože používáte vlastní adresu vícesměrového vysílání. (výchozí: {defaultMulticast})" - } + }, + "advancedSettings": "Pokročilá nastavení" }, "troubleshootPage": { "title": "Odstraňování problémů", diff --git a/assets/i18n/strings_de.i18n.json b/assets/i18n/strings_de.i18n.json index a613afdcba..f216a8397b 100644 --- a/assets/i18n/strings_de.i18n.json +++ b/assets/i18n/strings_de.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Schließen: Fensterposition speichern", "minimizeToTray": "Schließen: in Symbolleiste minimieren", "launchAtStartup": "Autostart nach Login", - "launchMinimized": "Autostart: versteckt starten" + "launchMinimized": "Autostart: versteckt starten", + "animations": "Animationen" }, "receive": { "title": "Empfangen", @@ -114,7 +115,8 @@ "encryption": "Verschlüsselung", "multicastGroup": "Multicast", "multicastGroupWarning": "Möglicherweise wirst du von anderen Geräten nicht erkannt, weil du eine benutzerdefinierte Multicast-Adresse verwendest. (Standard: {defaultMulticast})" - } + }, + "advancedSettings": "Erweiterte Einstellungen" }, "troubleshootPage": { "title": "Fehlerbehebung", diff --git a/assets/i18n/strings_es-ES.i18n.json b/assets/i18n/strings_es-ES.i18n.json index b9a8bf3a0c..e4fa9f5a0e 100644 --- a/assets/i18n/strings_es-ES.i18n.json +++ b/assets/i18n/strings_es-ES.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Al salir guardar la ubicación de la ventana", "minimizeToTray": "Cerrar: Minimizar ventana", "launchAtStartup": "Inicio automático", - "launchMinimized": "Inicio automático: Iniciar minimizado" + "launchMinimized": "Inicio automático: Iniciar minimizado", + "animations": "Animaciones" }, "receive": { "title": "Recibir", @@ -114,7 +115,8 @@ "encryption": "Encriptación", "multicastGroup": "Multicast", "multicastGroupWarning": "Es posible que no seas visible para otros dispositivos porque estás utilizando una dirección multicast personalizada. (Dirección multicast por defecto: {defaultMulticast})" - } + }, + "advancedSettings": "Configuración avanzada" }, "troubleshootPage": { "title": "Solucionar problemas", diff --git a/assets/i18n/strings_fr-FR.i18n.json b/assets/i18n/strings_fr-FR.i18n.json index a9a12d31e8..fd5f1f4f04 100644 --- a/assets/i18n/strings_fr-FR.i18n.json +++ b/assets/i18n/strings_fr-FR.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Quitter: Sauvegarder l'emplacement de la fenêtre", "minimizeToTray": "Quitter : Réduire à la barre des tâches", "launchAtStartup": "Démarrage automatique : Après la connexion", - "launchMinimized": "Démarrage automatique : Minimiser" + "launchMinimized": "Démarrage automatique : Minimiser", + "animations": "Animations" }, "receive": { "title": "Reçu", @@ -114,7 +115,8 @@ "encryption": "Chiffrement", "multicastGroup": "Multicast", "multicastGroupWarning": "Il est possible que vous ne soyez pas détecté par d'autres appareils car vous utilisez une adresse multicast différente de celle par défaut. (par défaut: {defaultMulticast})" - } + }, + "advancedSettings": "Paramètres avancés" }, "troubleshootPage": { "title": "Dépannage", diff --git a/assets/i18n/strings_hu.i18n.json b/assets/i18n/strings_hu.i18n.json index c1acbcec2a..f774dd135d 100644 --- a/assets/i18n/strings_hu.i18n.json +++ b/assets/i18n/strings_hu.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Kilépés: Ablak pozíció mentése", "minimizeToTray": "Kilépés: Minimalizálja a tálcára", "launchAtStartup": "Auto. indítás bejelentkezés után", - "launchMinimized": "Auto. indítás: Kis méretben" + "launchMinimized": "Auto. indítás: Kis méretben", + "animations": "Animációk" }, "receive": { "title": "Fogadás", @@ -114,7 +115,8 @@ "encryption": "Titkosítás", "multicastGroup": "Multicast", "multicastGroupWarning": "Előfordulhat, hogy más eszközök nem észlelik eszközét, mert egyéni multicast címet használ. (alapérték: {defaultMulticast})" - } + }, + "advancedSettings": "Haladó beállítások" }, "troubleshootPage": { "title": "Hibaelhárítás", diff --git a/assets/i18n/strings_in.i18n.json b/assets/i18n/strings_in.i18n.json index 7468c0a4d3..2c18239047 100644 --- a/assets/i18n/strings_in.i18n.json +++ b/assets/i18n/strings_in.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Keluar: Simpan posisi jendela", "minimizeToTray": "Keluar: Perkecil ke pojok bawah", "launchAtStartup": "Mulai otomatis setelah masuk", - "launchMinimized": "Mulai otomatis: Berjalan di belakang" + "launchMinimized": "Mulai otomatis: Berjalan di belakang", + "animations": "Animasi" }, "receive": { "title": "Menerima", @@ -114,7 +115,8 @@ "encryption": "Encryption", "multicastGroup": "Multicast", "multicastGroupWarning": "Anda mungkin tidak terdeteksi oleh perangkat lain karena Anda menggunakan alamat multicast khusus. (default: {defaultMulticast})" - } + }, + "advancedSettings": "Pengaturan Lanjutan" }, "troubleshootPage": { "title": "Perbaikan masalah", diff --git a/assets/i18n/strings_it.i18n.json b/assets/i18n/strings_it.i18n.json index a9b23491dd..79b50da0b3 100644 --- a/assets/i18n/strings_it.i18n.json +++ b/assets/i18n/strings_it.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Esci: Salva posizione della finestra", "minimizeToTray": "Esci: Riduci ad icona nel vassoio", "launchAtStartup": "Avvio automatico dopo il login", - "launchMinimized": "Avvio automatico: Avvio nascosto" + "launchMinimized": "Avvio automatico: Avvio nascosto", + "animations": "Animazioni" }, "receive": { "title": "Ricevi", @@ -114,7 +115,8 @@ "encryption": "Crittografia", "multicastGroup": "Multicast", "multicastGroupWarning": "Potresti non essere rilevato dagli altri dispositivi perché stai utilizzando un indirizzo multicast personalizzato. (predefinito: {defaultMulticast})" - } + }, + "advancedSettings": "Impostazioni avanzate" }, "troubleshootPage": { "title": "Risoluzione dei problemi", diff --git a/assets/i18n/strings_iw.i18n.json b/assets/i18n/strings_iw.i18n.json index 1b50a418c2..f8f22bfb71 100644 --- a/assets/i18n/strings_iw.i18n.json +++ b/assets/i18n/strings_iw.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "יציאה: שמירת מיקום החלון", "minimizeToTray": "יציאה: מזעור למגש", "launchAtStartup": "הפעלה אוטומטית לאחר הכניסה", - "launchMinimized": "הפעלה אוטומטית: התחל מוסתר" + "launchMinimized": "הפעלה אוטומטית: התחל מוסתר", + "animations": "הנפשות" }, "receive": { "title": "קבל", @@ -114,7 +115,8 @@ "encryption": "הצפנה", "multicastGroup": "מולטיקאסט", "multicastGroupWarning": "יתכן שלא יזוהו מכשירים אחרים בגלל שאתה משתמש בכתובת מולטיקאסט מותאמת אישית. (ברירת־מחדל: {defaultMulticast})" - } + }, + "advancedSettings": "הגדרות מתקדמות" }, "troubleshootPage": { "title": "פתרון תקלות", diff --git a/assets/i18n/strings_ja.i18n.json b/assets/i18n/strings_ja.i18n.json index b237ad2493..9dba61bd7b 100644 --- a/assets/i18n/strings_ja.i18n.json +++ b/assets/i18n/strings_ja.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "終了時: ウィンドウ配置を記憶", "minimizeToTray": "終了時: トレイに最小化", "launchAtStartup": "ログイン時に自動起動", - "launchMinimized": "自動起動時: 隠れた状態で開始" + "launchMinimized": "自動起動時: 隠れた状態で開始", + "animations": "アニメーション" }, "receive": { "title": "受信", @@ -114,7 +115,8 @@ "encryption": "暗号化", "multicastGroup": "マルチキャスト", "multicastGroupWarning": "カスタムのマルチキャストアドレスを使用しているため、他のデバイスから検出されない場合があります。(デフォルト: {defaultMulticast})" - } + }, + "advancedSettings": "詳細設定" }, "troubleshootPage": { "title": "トラブルシューティング", diff --git a/assets/i18n/strings_ko.i18n.json b/assets/i18n/strings_ko.i18n.json index 2f3e194065..26eddc468e 100644 --- a/assets/i18n/strings_ko.i18n.json +++ b/assets/i18n/strings_ko.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "종료: 화면 위치 저장하기", "minimizeToTray": "종료 시 시스템 트레이로 최소화", "launchAtStartup": "로그인 시 자동으로 시작", - "launchMinimized": "최소화된 상태로 시작" + "launchMinimized": "최소화된 상태로 시작", + "animations": "애니메이션" }, "receive": { "title": "수신", @@ -114,7 +115,8 @@ "encryption": "암호화", "multicastGroup": "멀티캐스트", "multicastGroupWarning": "사용자 지정 멀티캐스트 주소를 사용하고 있기 때문에 다른 기기에서 감지되지 않을 수 있습니다. (기본값: {defaultMulticast})" - } + }, + "advancedSettings": "고급 설정" }, "troubleshootPage": { "title": "문제해결", diff --git a/assets/i18n/strings_ne.i18n.json b/assets/i18n/strings_ne.i18n.json index d4a3d47a68..fd02757009 100644 --- a/assets/i18n/strings_ne.i18n.json +++ b/assets/i18n/strings_ne.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "बंद करें: विंडो स्थानन प्लेसमेंट सहेजें", "minimizeToTray": "छोड्नुहोस्: ट्रेमा न्यूनतम गर्नुहोस्", "launchAtStartup": "लगइन पछि स्वत: सुरु गर्नुहोस्", - "launchMinimized": "स्वतः सुरु गर्नुहोस्: लुकेको सुरु गर्नुहोस्" + "launchMinimized": "स्वतः सुरु गर्नुहोस्: लुकेको सुरु गर्नुहोस्", + "animations": "एनिमेसनहरू" }, "receive": { "title": "प्राप्त गर्नुहोस्", @@ -114,7 +115,8 @@ "encryption": "एनक्रिप्शन", "multicastGroup": "मल्टीकास्ट", "multicastGroupWarning": "आप अन्य उपकर्णों द्वारा पहचाना नहीं जा सकता है क्योंकि आप कस्टम मल्टीकास्ट पता का उपयोग कर रहे हैं। (डिफ़ॉल्ट: {defaultMulticast})" - } + }, + "advancedSettings": "उन्नत सेटिङहरू" }, "troubleshootPage": { "title": "समस्या निवारण करें", diff --git a/assets/i18n/strings_nl.i18n.json b/assets/i18n/strings_nl.i18n.json index 7f6db9db6c..925b9c2c7f 100644 --- a/assets/i18n/strings_nl.i18n.json +++ b/assets/i18n/strings_nl.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Afsluiten: Vensterindeling behouden", "minimizeToTray": "Stoppen: Minimaliseer naar systeemvak", "launchAtStartup": "Autostart na inloggen", - "launchMinimized": "Autostart: Start verborgen" + "launchMinimized": "Autostart: Start verborgen", + "animations": "Animaties" }, "receive": { "title": "Ontvangen", @@ -114,7 +115,8 @@ "encryption": "Encryptie", "multicastGroup": "Multicast", "multicastGroupWarning": "Je wordt mogelijk niet gedetecteerd door andere apparaten omdate je een aangepaste multicast-addres gebruikt. (standaard: {defaultMulticast})" - } + }, + "advancedSettings": "Geavanceerde instellingen" }, "troubleshootPage": { "title": "Probleem oplossen", diff --git a/assets/i18n/strings_pl.i18n.json b/assets/i18n/strings_pl.i18n.json index 21e8df5f17..7f87056c72 100644 --- a/assets/i18n/strings_pl.i18n.json +++ b/assets/i18n/strings_pl.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Zamknij: Zapisz położenie okna", "minimizeToTray": "Quit: Minimize to tray", "launchAtStartup": "Autostart po zalogowaniu", - "launchMinimized": "Autostart: Start ukryty" + "launchMinimized": "Autostart: Start ukryty", + "animations": "Animacje" }, "receive": { "title": "Odbierz", @@ -114,7 +115,8 @@ "encryption": "Szyfrowanie", "multicastGroup": "Multicast", "multicastGroupWarning": "Inne urządzenia mogą nie wykryć Twojego urządzenia, ponieważ używasz niestandardowego adresu multicast. (domyślnie: {defaultMulticast})" - } + }, + "advancedSettings": "Zaawansowane ustawienia" }, "troubleshootPage": { "title": "Rozwiązywanie problemów", diff --git a/assets/i18n/strings_pt-BR.i18n.json b/assets/i18n/strings_pt-BR.i18n.json index b5d91140d3..8f9e74fb21 100644 --- a/assets/i18n/strings_pt-BR.i18n.json +++ b/assets/i18n/strings_pt-BR.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Salvar a posição da janela ao fechar", "minimizeToTray": "Minimizar para a bandeja ao fechar", "launchAtStartup": "Abrir automaticamente após o login", - "launchMinimized": "Início automático: Abrir minimizado" + "launchMinimized": "Início automático: Abrir minimizado", + "animations": "Animações" }, "receive": { "title": "Recebimento", @@ -114,7 +115,8 @@ "encryption": "Criptografia", "multicastGroup": "Multicast", "multicastGroupWarning": "Você pode estar indetectável para outros dispositivos por estar usando um endereço multicast customizado. (Padrão: {defaultMulticast})" - } + }, + "advancedSettings": "Configurações avançadas" }, "troubleshootPage": { "title": "Diagnostique problemas", diff --git a/assets/i18n/strings_ru.i18n.json b/assets/i18n/strings_ru.i18n.json index 5c7caddd00..869817a24f 100644 --- a/assets/i18n/strings_ru.i18n.json +++ b/assets/i18n/strings_ru.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Сохранить расположение окна после закрытия", "minimizeToTray": "Закрыть: свернуть в трей", "launchAtStartup": "Автозагрузка", - "launchMinimized": "Скрытая автозагрузка" + "launchMinimized": "Скрытая автозагрузка", + "animations": "Анимации" }, "receive": { "title": "Получение", @@ -114,7 +115,8 @@ "encryption": "Шифрование", "multicastGroup": "Мультивещание", "multicastGroupWarning": "Другие устройства могут вас не обнаружить, поскольку вы используете пользовательский адрес мультивещания. (default: {defaultMulticast})" - } + }, + "advancedSettings": "Дополнительные настройки" }, "troubleshootPage": { "title": "Устранение неполадок", diff --git a/assets/i18n/strings_sv.i18n.json b/assets/i18n/strings_sv.i18n.json index 0b86d6d7ae..eb420c06f7 100644 --- a/assets/i18n/strings_sv.i18n.json +++ b/assets/i18n/strings_sv.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Avsluta: Spara fönsterplacering", "minimizeToTray": "Lämna: minimera till tray", "launchAtStartup": "Starta automatiskt efter inloggning", - "launchMinimized": "Starta automatiskt: starta gömd" + "launchMinimized": "Starta automatiskt: starta gömd", + "animations": "Animationer" }, "receive": { "title": "Ta emot", @@ -114,7 +115,8 @@ "encryption": "Kryptering", "multicastGroup": "Multicast", "multicastGroupWarning": "Du kanske inte upptäcks av andra enheter eftersom du använder en anpassad multicast-adress. (standard: {defaultMulticast})" - } + }, + "advancedSettings": "Avancerade inställningar" }, "troubleshootPage": { "title": "Felsökning", diff --git a/assets/i18n/strings_tr.i18n.json b/assets/i18n/strings_tr.i18n.json index 33f29b0e1d..16492b4513 100644 --- a/assets/i18n/strings_tr.i18n.json +++ b/assets/i18n/strings_tr.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Çıkış: Burayı Kaydet", "minimizeToTray": "Çıkış: Simge durumuna küçült", "launchAtStartup": "Giriş yapıldıktan sonra otomatik başlat", - "launchMinimized": "Otomatik başlatma: Gizli Başlatma" + "launchMinimized": "Otomatik başlatma: Gizli Başlatma", + "animations": "Animasyonlar" }, "receive": { "title": "Alım", @@ -114,7 +115,8 @@ "encryption": "Şifreleme", "multicastGroup": "Çoklu yayın", "multicastGroupWarning": "Özel çoklu yayın adresini kullandığınız için diğer cihazlar tarafından algılanamayabilirsiniz.(varsayılan: {defaultMulticast})" - } + }, + "advancedSettings": "Gelişmiş ayarlar" }, "troubleshootPage": { "title": "Sorun Giderme", diff --git a/assets/i18n/strings_uk.i18n.json b/assets/i18n/strings_uk.i18n.json index c02eccc2f4..dba3f66e64 100644 --- a/assets/i18n/strings_uk.i18n.json +++ b/assets/i18n/strings_uk.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "Зберегти розташування вікна після закриття програми", "minimizeToTray": "Закрити: згорнути в системний трей", "launchAtStartup": "Автозапуск", - "launchMinimized": "Прихований автозапуск" + "launchMinimized": "Прихований автозапуск", + "animations": "Анімації" }, "receive": { "title": "Отримання", @@ -114,7 +115,8 @@ "encryption": "Шифрування", "multicastGroup": "Групова передача", "multicastGroupWarning": "Інші пристрої можуть вас не виявити, оскільки ви використовуєте іншу, власну групову адресу. (default: {defaultMulticast})" - } + }, + "advancedSettings": "Розширені налаштування" }, "troubleshootPage": { "title": "Усунення несправностей", diff --git a/assets/i18n/strings_ur.i18n.json b/assets/i18n/strings_ur.i18n.json index 7b20604b56..13e9c3ea90 100644 --- a/assets/i18n/strings_ur.i18n.json +++ b/assets/i18n/strings_ur.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "چھوڑیں: ونڈو کی جگہ کو محفوظ کریں۔", "minimizeToTray": "چھوڑیں: ٹرے میں چھوٹا کریں۔", "launchAtStartup": "لاگ ان کے بعد آٹو اسٹارٹ", - "launchMinimized": "آٹو سٹارٹ: سٹارٹ پوشیدہ" + "launchMinimized": "آٹو سٹارٹ: سٹارٹ پوشیدہ", + "animations": "تحریکات" }, "receive": { "title": "وصول کریں", @@ -114,7 +115,8 @@ "encryption": "خفیہ کاری", "multicastGroup": "ملٹی کاسٹ", "multicastGroupWarning": "ہو سکتا ہے آپ کو دوسرے آلات سے پتہ نہ لگے کیونکہ آپ حسب ضرورت ملٹی کاسٹ ایڈریس استعمال کر رہے ہیں۔ (پہلے سے طے شدہ: {defaultMulticast})" - } + }, + "advancedSettings": "تجاویز شھر کی ترتیبات" }, "troubleshootPage": { "title": "خرابی کا سراغ لگانا", diff --git a/assets/i18n/strings_zh-CN.i18n.json b/assets/i18n/strings_zh-CN.i18n.json index fd27c77112..e009517ef2 100644 --- a/assets/i18n/strings_zh-CN.i18n.json +++ b/assets/i18n/strings_zh-CN.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "关闭时:保存窗口位置", "minimizeToTray": "关闭时:最小化到系统托盘", "launchAtStartup": "登录系统后自动启动程序", - "launchMinimized": "静默自启:只启动托盘服务" + "launchMinimized": "静默自启:只启动托盘服务", + "animations": "动画效果" }, "receive": { "title": "接收", @@ -114,7 +115,8 @@ "encryption": "加密", "multicastGroup": "多播", "multicastGroupWarning": "由于正在使用自定义多播地址,你可能不会被其他设备检测到。(默认地址:{defaultMulticast})" - } + }, + "advancedSettings": "高级设置" }, "troubleshootPage": { "title": "故障排除", diff --git a/assets/i18n/strings_zh-HK.i18n.json b/assets/i18n/strings_zh-HK.i18n.json index 0308a22328..f51e4e4bc7 100644 --- a/assets/i18n/strings_zh-HK.i18n.json +++ b/assets/i18n/strings_zh-HK.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "退出嗰陣記低視窗位置", "minimizeToTray": "退出嗰陣縮細做通知圖示", "launchAtStartup": "開機自動啟動", - "launchMinimized": "自動啟動成通知圖示" + "launchMinimized": "自動啟動成通知圖示", + "animations": "動畫" }, "receive": { "title": "接收", @@ -114,7 +115,8 @@ "encryption": "加密傳送", "multicastGroup": "多播 IP 地址", "multicastGroupWarning": "用自訂多播地址嘅話其他裝置有機會偵測唔到你。(預設:{defaultMulticast})" - } + }, + "advancedSettings": "進階設定" }, "troubleshootPage": { "title": "疑難排解", diff --git a/assets/i18n/strings_zh-TW.i18n.json b/assets/i18n/strings_zh-TW.i18n.json index b703b228b7..3de68cef9b 100644 --- a/assets/i18n/strings_zh-TW.i18n.json +++ b/assets/i18n/strings_zh-TW.i18n.json @@ -95,7 +95,8 @@ "saveWindowPlacement": "離開:儲存視窗位置", "minimizeToTray": "離開:最小化至系統匣", "launchAtStartup": "登入後自動啟動", - "launchMinimized": "自動啟動至系統匣" + "launchMinimized": "自動啟動至系統匣", + "animations": "動畫效果" }, "receive": { "title": "接收", @@ -114,7 +115,8 @@ "encryption": "加密", "multicastGroup": "多點傳送", "multicastGroupWarning": "您可能無法被其他裝置偵測,因為您正在使用自訂多點傳送位址。(預設:{defaultMulticast})" - } + }, + "advancedSettings": "進階設定" }, "troubleshootPage": { "title": "疑難排解", diff --git a/lib/init.dart b/lib/init.dart index 19a77d8038..f8917d1ca5 100644 --- a/lib/init.dart +++ b/lib/init.dart @@ -5,6 +5,7 @@ import 'package:flutter/widgets.dart'; import 'package:localsend_app/constants.dart'; import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/pages/home_page.dart'; +import 'package:localsend_app/provider/animation_provider.dart'; import 'package:localsend_app/provider/dio_provider.dart'; import 'package:localsend_app/provider/network/nearby_devices_provider.dart'; import 'package:localsend_app/provider/network/server/server_provider.dart'; @@ -19,7 +20,6 @@ import 'package:localsend_app/util/native/tray_helper.dart'; import 'package:localsend_app/util/ui/snackbar.dart'; import 'package:logging/logging.dart'; import 'package:riverpie_flutter/riverpie_flutter.dart'; -import 'package:routerino/routerino.dart'; import 'package:share_handler/share_handler.dart'; import 'package:window_manager/window_manager.dart'; @@ -28,7 +28,7 @@ const launchAtStartupArg = 'autostart'; final _logger = Logger('Init'); /// Will be called before the MaterialApp started -Future preInit(List args) async { +Future<(PersistenceService, bool)> preInit(List args) async { // Init logger Logger.root.level = args.contains('-v') || args.contains('--verbose') ? Level.ALL : Level.INFO; Logger.root.onRecord.listen((record) { @@ -61,6 +61,7 @@ Future preInit(List args) async { ); } + bool startHidden = false; if (checkPlatformIsDesktop()) { // Check if this app is already open and let it "show up". // If this is the case, then exit the current instance. @@ -82,9 +83,6 @@ Future preInit(List args) async { exit(0); // Another instance does exist because no error is thrown } catch (_) {} - // use the "slide" transition for desktop - Routerino.transition = RouterinoTransition.cupertino; - // initialize tray AFTER i18n has been initialized try { await initTray(); @@ -99,10 +97,15 @@ Future preInit(List args) async { // We show this app, when (1) app started manually, (2) app should not start minimized // In other words: only start minimized when launched on startup and "launchMinimized" is configured await WindowManager.instance.show(); + } else { + // keep this app hidden + startHidden = true; } } - return persistenceService; + setDefaultRouteTransition(); + + return (persistenceService, startHidden); } StreamSubscription? _sharedMediaSubscription; diff --git a/lib/main.dart b/lib/main.dart index 829ac2b55a..14c97dc6f2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:localsend_app/gen/strings.g.dart'; import 'package:localsend_app/init.dart'; import 'package:localsend_app/model/persistence/color_mode.dart'; import 'package:localsend_app/pages/home_page.dart'; +import 'package:localsend_app/provider/animation_provider.dart'; import 'package:localsend_app/provider/app_arguments_provider.dart'; import 'package:localsend_app/provider/device_info_provider.dart'; import 'package:localsend_app/provider/network_info_provider.dart'; @@ -24,14 +25,16 @@ import 'package:routerino/routerino.dart'; Future main(List args) async { WidgetsFlutterBinding.ensureInitialized(); + final (persistenceService, startHidden) = await preInit(args); final scope = RiverpieScope( observer: kDebugMode ? CustomRiverpieDebugObserver() : null, overrides: [ - persistenceProvider.overrideWithValue(await preInit(args)), + persistenceProvider.overrideWithValue(persistenceService), deviceRawInfoProvider.overrideWithValue(await getDeviceInfo()), appArgumentsProvider.overrideWithValue(args), tvProvider.overrideWithValue(await checkIfTv()), dynamicColorsProvider.overrideWithValue(await getDynamicColors()), + sleepProvider.overrideWithInitialState((ref) => startHidden), ], child: TranslationProvider( child: const LocalSendApp(), diff --git a/lib/model/state/settings_state.dart b/lib/model/state/settings_state.dart index d07d3d276d..5c1479308a 100644 --- a/lib/model/state/settings_state.dart +++ b/lib/model/state/settings_state.dart @@ -25,5 +25,6 @@ class SettingsState with _$SettingsState { required bool https, required SendMode sendMode, required bool saveWindowPlacement, + required bool enableAnimations, }) = _SettingsState; } diff --git a/lib/pages/tabs/send_tab.dart b/lib/pages/tabs/send_tab.dart index 3f1d0b1500..30622f0bb1 100644 --- a/lib/pages/tabs/send_tab.dart +++ b/lib/pages/tabs/send_tab.dart @@ -17,6 +17,7 @@ import 'package:localsend_app/provider/network_info_provider.dart'; import 'package:localsend_app/provider/progress_provider.dart'; import 'package:localsend_app/provider/selection/selected_sending_files_provider.dart'; import 'package:localsend_app/provider/settings_provider.dart'; +import 'package:localsend_app/theme.dart'; import 'package:localsend_app/util/file_size_helper.dart'; import 'package:localsend_app/util/native/file_picker.dart'; import 'package:localsend_app/util/native/ios_network_permission_helper.dart'; @@ -355,15 +356,19 @@ class _ScanButton extends StatelessWidget { @override Widget build(BuildContext context) { final scanningIps = context.ref.watch(nearbyDevicesProvider.select((s) => s.runningIps)); + final animations = context.ref.watch(animationProvider); + + final spinning = scanningIps.isNotEmpty && animations; + final iconColor = !animations && scanningIps.isNotEmpty ? Theme.of(context).colorScheme.warning : null; if (ips.length <= ScanFacade.maxInterfaces) { return RotatingWidget( duration: const Duration(seconds: 2), - spinning: scanningIps.isNotEmpty, + spinning: spinning, reverse: true, child: CustomIconButton( onPressed: () async => await context.ref.read(scanProvider).startSmartScan(forceLegacy: true), - child: const Icon(Icons.sync), + child: Icon(Icons.sync, color: iconColor), ), ); } @@ -391,11 +396,11 @@ class _ScanButton extends StatelessWidget { }, child: RotatingWidget( duration: const Duration(seconds: 2), - spinning: scanningIps.isNotEmpty, + spinning: spinning, reverse: true, - child: const Padding( - padding: EdgeInsets.all(8), - child: Icon(Icons.sync), + child: Padding( + padding: const EdgeInsets.all(8), + child: Icon(Icons.sync, color: iconColor), ), ), ); diff --git a/lib/pages/tabs/settings_tab.dart b/lib/pages/tabs/settings_tab.dart index 981e01e879..144552c52a 100644 --- a/lib/pages/tabs/settings_tab.dart +++ b/lib/pages/tabs/settings_tab.dart @@ -18,6 +18,7 @@ import 'package:localsend_app/widget/custom_dropdown_button.dart'; import 'package:localsend_app/widget/dialogs/encryption_disabled_notice.dart'; import 'package:localsend_app/widget/dialogs/quick_save_notice.dart'; import 'package:localsend_app/widget/dialogs/text_field_tv.dart'; +import 'package:localsend_app/widget/labeled_checkbox.dart'; import 'package:localsend_app/widget/local_send_logo.dart'; import 'package:localsend_app/widget/responsive_list_view.dart'; import 'package:riverpie_flutter/riverpie_flutter.dart'; @@ -36,6 +37,7 @@ class _SettingsTabState extends State with Riverpie { final _aliasController = TextEditingController(); final _portController = TextEditingController(); final _multicastController = TextEditingController(); + bool _advanced = false; @override void initState() { @@ -126,7 +128,7 @@ class _SettingsTabState extends State with Riverpie { ), if (checkPlatformIsDesktop()) ...[ /// Wayland does window position handling, so there's no need for it. See [https://github.com/localsend/localsend/issues/544] - if (checkPlatformIsNotWaylandDesktop()) + if (_advanced && checkPlatformIsNotWaylandDesktop()) _BooleanEntry( label: t.settingsTab.general.saveWindowPlacement, value: settings.saveWindowPlacement, @@ -197,7 +199,15 @@ class _SettingsTabState extends State with Riverpie { await initEnableAutoStartAndOpenSettings(settings, _isWindows); }, ), - )) + )), + if (_advanced) + _BooleanEntry( + label: t.settingsTab.general.animations, + value: settings.enableAnimations, + onChanged: (b) async { + await ref.notifier(settingsProvider).setEnableAnimations(b); + }, + ), ], ], ), @@ -345,40 +355,43 @@ class _SettingsTabState extends State with Riverpie { }, ), ), - _SettingsEntry( - label: t.settingsTab.network.port, - child: TextFieldTv( - name: t.settingsTab.network.port, - controller: _portController, - onChanged: (s) async { - final port = int.tryParse(s); - if (port != null) { - await ref.notifier(settingsProvider).setPort(port); + if (_advanced) + _SettingsEntry( + label: t.settingsTab.network.port, + child: TextFieldTv( + name: t.settingsTab.network.port, + controller: _portController, + onChanged: (s) async { + final port = int.tryParse(s); + if (port != null) { + await ref.notifier(settingsProvider).setPort(port); + } + }, + ), + ), + if (_advanced) + _BooleanEntry( + label: t.settingsTab.network.encryption, + value: settings.https, + onChanged: (b) async { + final old = settings.https; + await ref.notifier(settingsProvider).setHttps(b); + if (old && !b && mounted) { + await EncryptionDisabledNotice.open(context); } }, ), - ), - _BooleanEntry( - label: t.settingsTab.network.encryption, - value: settings.https, - onChanged: (b) async { - final old = settings.https; - await ref.notifier(settingsProvider).setHttps(b); - if (old && !b && mounted) { - await EncryptionDisabledNotice.open(context); - } - }, - ), - _SettingsEntry( - label: t.settingsTab.network.multicastGroup, - child: TextFieldTv( - name: t.settingsTab.network.multicastGroup, - controller: _multicastController, - onChanged: (s) async { - await ref.notifier(settingsProvider).setMulticastGroup(s); - }, + if (_advanced) + _SettingsEntry( + label: t.settingsTab.network.multicastGroup, + child: TextFieldTv( + name: t.settingsTab.network.multicastGroup, + controller: _multicastController, + onChanged: (s) async { + await ref.notifier(settingsProvider).setMulticastGroup(s); + }, + ), ), - ), AnimatedCrossFade( crossFadeState: settings.port != defaultPort ? CrossFadeState.showSecond : CrossFadeState.showFirst, duration: const Duration(milliseconds: 200), @@ -407,6 +420,35 @@ class _SettingsTabState extends State with Riverpie { ), ], ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + LabeledCheckbox( + label: t.settingsTab.advancedSettings, + value: _advanced, + labelFirst: true, + onChanged: (b) { + setState(() => _advanced = b == true); + }, + ), + const SizedBox(width: 10), + ], + ), + const SizedBox(height: 20), + const LocalSendLogo(withText: true), + const SizedBox(height: 5), + ref.watch(versionProvider).maybeWhen( + data: (version) => Text( + 'Version: $version', + textAlign: TextAlign.center, + ), + orElse: () => Container(), + ), + Text( + '© ${DateTime.now().year} Tien Do Nam', + textAlign: TextAlign.center, + ), + const SizedBox(height: 30), Theme( data: Theme.of(context).copyWith( textButtonTheme: TextButtonThemeData( @@ -416,7 +458,7 @@ class _SettingsTabState extends State with Riverpie { ), ), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ TextButton.icon( onPressed: () async { @@ -425,6 +467,7 @@ class _SettingsTabState extends State with Riverpie { icon: const Icon(Icons.info), label: Text(t.aboutPage.title), ), + const SizedBox(height: 5), TextButton.icon( onPressed: () async { await context.push(() => const ChangelogPage()); @@ -435,20 +478,6 @@ class _SettingsTabState extends State with Riverpie { ], ), ), - const SizedBox(height: 40), - const LocalSendLogo(withText: true), - const SizedBox(height: 5), - ref.watch(versionProvider).maybeWhen( - data: (version) => Text( - 'Version: $version', - textAlign: TextAlign.center, - ), - orElse: () => Container(), - ), - Text( - '© ${DateTime.now().year} Tien Do Nam', - textAlign: TextAlign.center, - ), const SizedBox(height: 80), ], ); diff --git a/lib/provider/animation_provider.dart b/lib/provider/animation_provider.dart index 28d3380896..f4ccc010bf 100644 --- a/lib/provider/animation_provider.dart +++ b/lib/provider/animation_provider.dart @@ -1,6 +1,36 @@ +import 'package:flutter/scheduler.dart'; +import 'package:localsend_app/provider/settings_provider.dart'; +import 'package:localsend_app/util/native/platform_check.dart'; import 'package:riverpie_flutter/riverpie_flutter.dart'; +import 'package:routerino/routerino.dart'; + +/// If true, then animations are disabled. +/// Used when the app is in the background. +final sleepProvider = StateProvider((ref) { + return false; +}, debugLabel: 'sleepProvider'); /// If false, then animations are disabled. -final animationProvider = StateProvider((ref) { - return true; +final animationProvider = ViewProvider((ref) { + final sleeping = ref.watch(sleepProvider); + final enableAnimations = ref.watch(settingsProvider.select((s) => s.enableAnimations)); + final animations = enableAnimations && !sleeping; + + timeDilation = animations ? 1.0 : 0.00001; + if (animations) { + setDefaultRouteTransition(); + } else { + Routerino.transition = RouterinoTransition.noTransition; + } + + return animations; }); + +void setDefaultRouteTransition() { + // use the "slide" transition for desktop + if (checkPlatformIsDesktop()) { + Routerino.transition = RouterinoTransition.cupertino; + } else { + Routerino.transition = RouterinoTransition.material; + } +} diff --git a/lib/provider/persistence_provider.dart b/lib/provider/persistence_provider.dart index 5203698073..4487e0fcb4 100644 --- a/lib/provider/persistence_provider.dart +++ b/lib/provider/persistence_provider.dart @@ -54,6 +54,7 @@ const _launchAtStartup = 'ls_launch_at_startup'; const _autoStartLaunchMinimized = 'ls_auto_start_launch_minimized'; const _https = 'ls_https'; const _sendMode = 'ls_send_mode'; +const _enableAnimations = 'ls_enable_animations'; final persistenceProvider = Provider((ref) { throw Exception('persistenceProvider not initialized'); @@ -306,4 +307,12 @@ class PersistenceService { if (!checkPlatformIsNotWaylandDesktop()) return false; return _prefs.getBool(_saveWindowPlacement) ?? true; } + + Future setEnableAnimations(bool enableAnimations) async { + await _prefs.setBool(_enableAnimations, enableAnimations); + } + + bool getEnableAnimations() { + return _prefs.getBool(_enableAnimations) ?? true; + } } diff --git a/lib/provider/settings_provider.dart b/lib/provider/settings_provider.dart index cc0cad2e7f..f8d4cd08d0 100644 --- a/lib/provider/settings_provider.dart +++ b/lib/provider/settings_provider.dart @@ -35,6 +35,7 @@ class SettingsNotifier extends Notifier { https: _service.isHttps(), sendMode: _service.getSendMode(), saveWindowPlacement: _service.getSaveWindowPlacement(), + enableAnimations: _service.getEnableAnimations(), ); } @@ -142,4 +143,11 @@ class SettingsNotifier extends Notifier { saveWindowPlacement: savePlacement, ); } + + Future setEnableAnimations(bool enableAnimations) async { + await _service.setEnableAnimations(enableAnimations); + state = state.copyWith( + enableAnimations: enableAnimations, + ); + } } diff --git a/lib/util/native/tray_helper.dart b/lib/util/native/tray_helper.dart index a5a5dbfb60..c1af3da857 100644 --- a/lib/util/native/tray_helper.dart +++ b/lib/util/native/tray_helper.dart @@ -90,7 +90,7 @@ Future hideToTray() async { } // Disable animations - RiverpieScope.defaultRef.notifier(animationProvider).setState((_) => false); + RiverpieScope.defaultRef.notifier(sleepProvider).setState((_) => true); } Future showFromTray() async { @@ -103,5 +103,5 @@ Future showFromTray() async { } // Enable animations - RiverpieScope.defaultRef.notifier(animationProvider).setState((_) => true); + RiverpieScope.defaultRef.notifier(sleepProvider).setState((_) => false); } diff --git a/lib/widget/labeled_checkbox.dart b/lib/widget/labeled_checkbox.dart index f9ef88b4c9..bcc09b05c4 100644 --- a/lib/widget/labeled_checkbox.dart +++ b/lib/widget/labeled_checkbox.dart @@ -4,23 +4,35 @@ class LabeledCheckbox extends StatelessWidget { final String label; final bool value; final ValueChanged onChanged; + final bool labelFirst; + const LabeledCheckbox({ required this.label, required this.value, required this.onChanged, + this.labelFirst = false, }); @override Widget build(BuildContext context) { return Row( - children: [ - Checkbox( - value: value, - onChanged: onChanged, - ), - const SizedBox(width: 5), - Text(label), - ], + children: labelFirst + ? [ + Text(label), + const SizedBox(width: 5), + Checkbox( + value: value, + onChanged: onChanged, + ), + ] + : [ + Checkbox( + value: value, + onChanged: onChanged, + ), + const SizedBox(width: 5), + Text(label), + ], ); } }