From 70ca059e0f7694e7e170f0df29ccf43c35c2969d Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 12 Mar 2025 00:48:40 +0100 Subject: [PATCH 001/150] New translations strings.xml (Portuguese, Brazilian) --- src/keepass2android-app/Resources/values-pt-rBR/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml index fcf41272..4de49320 100644 --- a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml @@ -548,6 +548,7 @@ Dropbox (pasta KP2A) Se você não quiser dar acesso KP2A para o seu Dropbox completo, você pode selecionar esta opção. Ele irá solicitar somente acesso para a pasta Apps/Keepass2Android. Isto é especialmente adequado ao criar um novo banco de dados. Se você já tiver um banco de dados, clique nesta opção para criar a pasta, em seguida, colocar o arquivo dentro da pasta (a partir de seu PC) e em seguida, selecione esta opção novamente para abrir o arquivo. Google Drive + Observação: o Google está restringindo o acesso ao Google Drive a partir de aplicativos para cada vez mais usuários. Se a implementação integrada do Google Drive não funcionar, use o seletor de arquivos do sistema e selecione o Google Drive lá! Google Drive (Arquivos KP2A) Se você não quiser dar acesso KP2A ao seu Google Drive completo, você pode selecionar esta opção. Observe que você precisa criar um arquivo de banco de dados primeiro, os arquivos existentes não são visíveis para o aplicativo. Escolha esta opção na tela Criar banco de dados ou, se você já abriu um banco de dados, exportando o banco de dados escolhendo esta opção. PCloud (Pasta KP2A) @@ -1199,5 +1200,6 @@ Aceitar sempre em \"%1$s\" Voltar quando terminar Voltar ao pressionar enviar/ir/concluído + A leitura de código QR requer o Google Play Services. Instale ou atualize o Google Play Services no seu dispositivo. Configurações do teclado Android From 11ce68902c64d9741342cfa7ba54fde56b7b816c Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 13 Mar 2025 08:11:38 +0100 Subject: [PATCH 002/150] New translations strings.xml (Slovenian) --- src/keepass2android-app/Resources/values-sl/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android-app/Resources/values-sl/strings.xml b/src/keepass2android-app/Resources/values-sl/strings.xml index 2b09e666..2825e61d 100644 --- a/src/keepass2android-app/Resources/values-sl/strings.xml +++ b/src/keepass2android-app/Resources/values-sl/strings.xml @@ -546,6 +546,7 @@ Dropbox (mapa KP2A) Če dostopa KP2A ne želite dati celemu Dropboxu, lahko izberete to možnost. Zahtevala bo samo dostop do mape Apps/Keepass2Android. To je posebej primerno ob ustvarjanju nove podatkovne zbirke. Če jo že imate, tapnite na to možnost, da ustvarite mapo, v njo vstavite svojo datoteko (iz računalnika) in ponovno izberete to možnost, da datoteko odprete. Google Drive + Opomba: Google omejuje dostop do storitve Google Drive iz aplikacij za vse več uporabnikov. Če vgrajena implementacija Googlovega pogona ne deluje, uporabite sistemski izbirnik datotek in tam izberite Googlov pogon! Google Drive (KP2A datoteke) Če KP2A ne želite omogočiti dostopa do celotnega Google Drive, lahko izberete to možnost. Upoštevajte, da morate najprej ustvariti novo datoteko baze podatkov, obstoječe datoteke niso vidne aplikaciji. To možnost izberite na zaslonu Ustvari bazo podatkov ali, če ste že odprli bazo podatkov, izvozite bazo podatkov in izberete to možnost. PCloud (KP2A mapa) @@ -1197,5 +1198,6 @@ Sprejmi vedno v \"%1$s\" Preklopi nazaj, ko je končano Preklopi nazaj, ko pritisnete gumb za pošiljanje/prehajanje/končano + Za optično branje kode QR so potrebne storitve Google Play. V svojo napravo namestite ali posodobite storitve Google Play. Nastavitve tipkovnice Keepass2Android From 6eaba9d3a8abc45236a716b8ad1385d0fcd13b53 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 13 Mar 2025 08:11:39 +0100 Subject: [PATCH 003/150] New translations strings.xml (Chinese Simplified) --- src/keepass2android-app/Resources/values-zh/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android-app/Resources/values-zh/strings.xml b/src/keepass2android-app/Resources/values-zh/strings.xml index 483482aa..1fad3203 100644 --- a/src/keepass2android-app/Resources/values-zh/strings.xml +++ b/src/keepass2android-app/Resources/values-zh/strings.xml @@ -546,6 +546,7 @@ Dropbox(KP2A 文件夹) 如果您不想让 KP2A 访问整个 Dropbox,您可以选中此选项。它将只有访问 Apps/Keepass2Android 文件夹的权限。特别适合创建一个新的数据库。如果您已经有一个数据库,触击此选项将创建该新文件夹,然后将您在电脑上的数据库文件放在此文件夹内,然后再选该选项,以打开该文件。 Google Drive + 请注意:谷歌正在限制越来越多的用户从应用程序访问Google Drive。 如果内置的 Google Drive 实现无法正常工作,请使用系统文件选择器并在那里选择 Google Drive ! Google Drive (KP2A文件) 如果您不想给予KP2A对您Google Drive的完整访问权,您可以选择此选项。 请注意,您需要先创建一个数据库文件,现有文件对本应用不可见。 您可以从“创建数据库”屏幕中选择此选项,或者选择此选项导出数据库,前提是您已经打开了一个数据库。 PCloud (KP2A 文件夹) @@ -1158,5 +1159,6 @@ Initial public release 总是在 \"%1$s 中接受 完成后切换回来 按下发送/转到/完成时切换回来 + 二维码扫描需要 Google Play 服务。请在您的设备上安装或更新 Google Play 服务。 键盘设置 From ad63179484e6d2030b818267ff77b4236fb94e06 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Fri, 14 Mar 2025 07:51:48 +0100 Subject: [PATCH 004/150] New translations strings.xml (Romanian) --- .../Resources/values-ro/strings.xml | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/keepass2android-app/Resources/values-ro/strings.xml b/src/keepass2android-app/Resources/values-ro/strings.xml index a8c24c62..5ade4fc6 100644 --- a/src/keepass2android-app/Resources/values-ro/strings.xml +++ b/src/keepass2android-app/Resources/values-ro/strings.xml @@ -468,6 +468,7 @@ Nu, suprascrie Funcționare doar cu cache intern Sincronizează copia cache cu sursa + Funcționare doar cu cache intern. Sincronizează baza de date din cache… Se încarcă fișierul sursă… Salvează fișierul… @@ -476,6 +477,8 @@ Baza de date s-a sincronizat cu succes! Se verifică baza de date pentru modificări… Fișier sursă actualizat. + Fișierul sursă și cache-ul sunt sincronizate. + S-a actualizat copia internă a cache-ului %1$s. Nu s-au detectat modificări. Se sincronizează fișierul auxiliar OTP… fișier bază de date @@ -502,7 +505,18 @@ Mod autentificare Trimite cheia publică... Selectează cheia privată... + Nume cheie nouă + Conținut cheie nouă + Cheie privată salvată + Salvarea cheii private a eșuat: %1$s + Introduc numele cheii și conținutul pentru a salva Cheie privată ștearsă: %1$s + Ștergerea cheii private a eșuat: %1$s + Salvează cheia privată + Ștergere cheie privată + Selectează cheia privată + [Adaugă nou...] + Frază de acces pentru cheie (opțională) Introdu datele de conectare FTP: Selectaţi tipul de stocare: Fişier local @@ -517,12 +531,14 @@ Dropbox (folder KP2A) Dacă nu doriți să dați KP2A acces la Dropbox-ul complet, puteți selecta această opțiune. Va solicita acces doar la directorul Apps/Keepass2Android. Acest lucru este potrivit în special atunci când se creează o bază de date nouă. Dacă aveţi deja o bază de date, selectaţi această opţiune pentru a crea directorul, apoi plasați fișierul în director (de la PC) și apoi selectați din nou această opțiune pentru deschiderea fișierului. Google Drive + PCloud (Acces complet) OneDrive OneDrive Toate fișierele și fișierele partajate Fișierele mele Directorul Keepass2Android App SFTP (SSH File Transfer) + MEGA Selector de fisiere sistem Iniţializare acces fişier Locaţie bază de date @@ -549,6 +565,8 @@ Imposibil de creat cheia OTP! Asigură-te că ai introdus OTP-urile corecte. Eroare în actualizare fișier auxiliar OTP! Se salvează fișierul auxiliar OTP… + Instalează %1$s de pe Google Play. + %1$s nu mai este suportat. Răspunsul la provocare este incorect. Nu se poate încărca fișierul auxiliar de provocare! Vă rugăm să folosiți plugin-ul KeeChallenge în KeePass 2,x (PC) pentru a configura data de baze cu răspunsuri-provocare! @@ -628,8 +646,13 @@ Deschide automat Fișier bază de date Activează pentru %1$s + Notificare despre deblocarea bazei de date QuickUnlock + Notificare despre blocarea bazei de date cu QuickUnlock + Notificări intrare + Notificare pentru simplificarea accesului la intrarea selectată în prezent. Închide baza de date după trei încercări de deblocare biometrică eșuate. + Avertizare! Autentificarea biometrică poate fi invalidată de Android, de ex. după adăugarea unei amprente noi în setările dispozitivului. Asigură-te că știi întotdeauna cum să deblochezi cu parola principală! Added floating action buttons for search and TOTP overview (if TOTP entries are present). Improved display of TOTP fields by adding a timeout indicator and showing it more prominently. @@ -669,8 +692,8 @@ Design Fără criptare (FTP) - Implicit encryption (FTP over TLS, FTPS) - Explicit encryption (FTP over TLS, FTPS) + Criptare implicită (FTP peste TLS, FTPS) + Criptare explicită (FTP prin TLS, FTPS) Nu reține numele utilizator și parola @@ -684,30 +707,45 @@ Parolă + OTP secret (modul de recuperare) Parolă + Challenge-Response Parolă + Challenge-Response secret (modul de recuperare) - Password + Challenge-Response for Keepass XC - Password + Key file + Challenge-Response for Keepass XC + Parolă + provocare-răspuns pentru Keepass XC + Parolă + fișier cheie + provocare-răspuns pentru Keepass XC Parolă - KP2A Private/Public key - Custom Private key + Cheie Privată/Publică KP2A + Cheie privată personalizată Ignoră eșecuri de validare a certificatului Avertizează când validarea eșuează Nu accepta certificate invalide + Asigură-te că aceasta funcționează pe sistemul tău, dacă nu, ia în considerare folosirea tastaturii încorporate. + Descrierea furnizată de plugin: + Keepass2Android suportă caracteristica de completare automată a Android, dar se pare că nu ai activat-o încă. Activare autocompletare + Ne pare rău, se pare că dispozitivul nu acceptă deschiderea setărilor din interiorul aplicației. Accesează manual setările de sistem pentru completare automată pentru a activa serviciul. + Afișează ajutorul pentru completarea automată Completează cu Keepass2Android Dezactivează completarea automată pentru %1$s Activează completare automată pentru %1$s + Domeniul web %1$s nu a putut fi asociat cu aplicația %2$s Keepass2Android a detectat dispozitive biometrice. Doriţi să activaţi deblocarea biometrică pentru această bază de date? Permite notificări + Keepass2Android poate afișa notificări cu butoane pentru a copia valori cum ar fi parole și coduri TOTP în clipboard, sau pentru a aduce tastatura integrată. Acest lucru este util pentru a transfera valori în alte aplicații fără a trece la Keepass2Android în mod repetat. Doriești să activezi astfel de notificări? Permite notificări + Dezactivează această caracteristică Nu acum Am înțeles Nu mai afișa + Îți amintești parola principală? + Reține că nu vei putea deschide baza de date fără cheia principală. Nu există nici o modalitate de a \"reseta\" parola principală. De asemenea, rețineți că Deblocarea biometrică funcționează prin stocarea cheii principale în spațiul de stocare securizat Android. Această stocare poate fi ștearsă de Android în orice moment, de ex. dacă adăugați o nouă amprentă în setările sistemului. Așa că nu vă bazați pe deblocarea biometrică ci retineți parola principală, vă rog! + S-a creat o copie de rezervă pentru baza de date? + Keepass2Android stochează parolele într-un fișier într-o locație la alegerea ta. Ești sigur că încă poți accesa acest fișier atunci când telefonul este pierdut sau furat sau când fișierul este distrus sau șters? Asigură-te că ai întotdeauna o copie de rezervă actualizată într-un loc sigur! + Pentru a crea o copie de rezervă acum, accesează %1$s > %2$s > %3$s. + Ești pregătit pentru cazuri de urgență? + Te-ai gândit vreodată ce se întâmplă dacă nu mai poți accesa baza de date a parolelor? Ce se întâmplă dacă ai un accident? Este o bună practică să transmiți cheia principală unei persoane de încredere pentru cazuri de urgență. În caz contrar, nimeni nu va avea acces la parole. Dezactivează acest mesaj Activează tastatura Keepass2Android. Reîncercați From 90059c5ae64a9b06a4785891d4cf1dc4fd0e9e13 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Fri, 14 Mar 2025 09:08:27 +0100 Subject: [PATCH 005/150] New translations strings.xml (Romanian) --- src/keepass2android-app/Resources/values-ro/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android-app/Resources/values-ro/strings.xml b/src/keepass2android-app/Resources/values-ro/strings.xml index 5ade4fc6..e55f21f0 100644 --- a/src/keepass2android-app/Resources/values-ro/strings.xml +++ b/src/keepass2android-app/Resources/values-ro/strings.xml @@ -746,6 +746,7 @@ Pentru a crea o copie de rezervă acum, accesează %1$s > %2$s > %3$s. Ești pregătit pentru cazuri de urgență? Te-ai gândit vreodată ce se întâmplă dacă nu mai poți accesa baza de date a parolelor? Ce se întâmplă dacă ai un accident? Este o bună practică să transmiți cheia principală unei persoane de încredere pentru cazuri de urgență. În caz contrar, nimeni nu va avea acces la parole. + Afișajul valabil în prezent nu este marcat ca fiind sigur. Aceasta înseamnă că capturile de ecran ar putea fi luate de alte aplicații. Keepass2Android este configurat pentru a afișa informații sensibile doar pe afișaje securizate. Schimbă la un afișaj securizat (de exemplu, detașând un monitor HDMI) sau modifică setările aplicației. Dezactivează acest mesaj Activează tastatura Keepass2Android. Reîncercați @@ -755,5 +756,6 @@ Acceptați întotdeauna în \"%1$s\" Comută înapoi când ai terminat Comută înapoi după apăsarea trimitere/înainte/terminat + Scanarea codului QR necesită servicii Google Play. Instalează sau actualizează serviciile Google Play de pe dispozitiv. Setările tastaturii Keepass2Android From 39a7a1298a5658245adce354e546988812582133 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Fri, 14 Mar 2025 09:08:28 +0100 Subject: [PATCH 006/150] New translations strings.xml (Romanian) --- .../app/src/main/res/values-ro/strings.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml b/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml index 2754b206..a1979ed2 100644 --- a/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml +++ b/src/java/android-filechooser-AS/app/src/main/res/values-ro/strings.xml @@ -55,4 +55,19 @@ Dimensiune Sortează după… Ieri + + Alege dosarul… + Alege dosarele… + Alege dosarele… + + + Alege fișierul… + Alege fișierele… + Alege fișierele… + + + Alege fișierul/dosarul… + Alege fișierele/dosarele… + Alege fișierele/dosarele… + From 55887e1a8938db870df55f468a377cd47dde00c6 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Mon, 17 Mar 2025 18:31:07 +0100 Subject: [PATCH 007/150] New translations strings.xml (Slovak) --- src/keepass2android-app/Resources/values-sk/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keepass2android-app/Resources/values-sk/strings.xml b/src/keepass2android-app/Resources/values-sk/strings.xml index ab1df0b3..ba4527b6 100644 --- a/src/keepass2android-app/Resources/values-sk/strings.xml +++ b/src/keepass2android-app/Resources/values-sk/strings.xml @@ -546,6 +546,7 @@ Dropbox (priečinok KP2A) Túto voľbu môžete aktivovať ak udelíte KP2A prístup do celého Dropboxu. Vyžaduje sa prístup iba do priečinka Apps/Keepass2Android. Je to osobitne vhodné pri vytváraní novej databázy. Ak už máte databázu, tak aktivovaním tejto voľby vytvoríte priečinok, potom premiestnite súbor do priečinka (zo svojho PC) a potom znovu aktivujte voľbu, pre otvorenie súboru. Google Drive + Pamätajte na to, že: Google čoraz viac obmedzuje prístup ku Google Drive z aplikácií. Ak vám nefunguje zabudovaná integrácia s Google Drive, použite výber súboru priamo v systéme a vyberte Google Drive tam! Google Drive (súbory KP2A) Ak nechcete poskytnúť KP2A prístup k celému úložisku Google Drive, môžete vybrať túto možnosť. Pamätajte na to, že najskôr musíte vytvoriť súbor s databázou, existujúce súbory aplikácia neuvidí. Buď vyberte takúto možnosť z obrazovky pre vytvorenie databázy, alebo už otvorenú databázu exportujte vybratím tejto možnosti. PCloud (priečinok KP2A) @@ -1199,5 +1200,6 @@ Vždy súhlasiť v \"%1$s\" Po dokončení prepnúť späť Po stlačení Odoslať/Prejsť/Hotovo prejsť späť + Na skenovanie QR kódov sú potrebné služby Google Play. Nainštalujte alebo aktualizujte si ich vo vašom zariadení. Nastavenia klávesnice Keepass2Android From 585b7476126b8af6a950d21c6795b6648db454c3 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Tue, 18 Mar 2025 11:35:13 +0100 Subject: [PATCH 008/150] New translations strings.xml (Hungarian) --- src/keepass2android-app/Resources/values-hu/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/keepass2android-app/Resources/values-hu/strings.xml b/src/keepass2android-app/Resources/values-hu/strings.xml index 1a9a93b0..1ddbe4e5 100644 --- a/src/keepass2android-app/Resources/values-hu/strings.xml +++ b/src/keepass2android-app/Resources/values-hu/strings.xml @@ -500,9 +500,14 @@ szerver (pl. 192.168.0.1) port Kezdőkönyvtár (opcionális): + Kapcsolódás időkorlátja, másodpercben (opcionális) SFTP tárhely adatai: Hitelesítési mód A nyilvános kulcs küldése... + Kulcscsere (KEX) algoritmus (opcionális) + Nevek/specifikációk, vesszővel elválasztva + Szerverazonosításhoz használt kulcs algoritmusa(i) (opcionális) + Nevek/specifikációk, vesszővel elválasztva Adja meg az FTP bejelentkezési adatait: Adja meg a MEGA fiókjának belépési adatait: Tárolási típus kiválasztása: From 6d7b4810da5dde761749da06ccbcac87dd02b04b Mon Sep 17 00:00:00 2001 From: PhilippC Date: Tue, 18 Mar 2025 13:16:38 +0100 Subject: [PATCH 009/150] New translations strings.xml (Hungarian) --- .../Resources/values-hu/strings.xml | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/keepass2android-app/Resources/values-hu/strings.xml b/src/keepass2android-app/Resources/values-hu/strings.xml index 1ddbe4e5..243ac94a 100644 --- a/src/keepass2android-app/Resources/values-hu/strings.xml +++ b/src/keepass2android-app/Resources/values-hu/strings.xml @@ -151,6 +151,7 @@ kulcsfájl hosszúság jelszó + SSH privátkulcs elérési útvonala Jelszó név URL @@ -400,6 +401,14 @@ Külön értesítés jelenjen meg a felhasználónév és a jelszó vágólapra másolásáról és a billentyűzet aktiválásáról. Automatikus kitöltés akadálymentesítési szolgáltatás Automatikus kitöltés szolgáltatás + Egy bejegyzés TOTP-vel való kitöltésekor értesítés megjelenítése, TOTP másolása gombbal + Értesítés megjelenítése + Automatikus kitöltés TOTP bejegyzésekhez + TOTP másolása a vágólapra + Egy bejegyzés TOTP-vel való kitöltésekor a TOTP másolása a vágólapra + Egy bejegyzés TOTP-vel való kitöltésekor aktiválódjon a beépített billentyűzet + A beépített billentyűzet aktiválása + TOTP a vágólapra másolva KP2A billentyűzet A teljes bejegyzés elérhetővé tétele a KP2A billentyűzet segítségével (ajánlott). Billentyűzetváltás @@ -416,6 +425,7 @@ Egy értesítési ikon megjelenítése, amíg az adatbázis hozzáférhető. Az Android 8 bevezetett egy új működési módot az értesítésekhez. Ha el akarja rejteni a Keepass2Android értesítési ikonját, kérjük, ezt a rendszerbeállításokban tegye meg. Állítsa az értesítési kategória fontosságát minimumra. Beállítások megnyitása + A Keepass2Android képes rendszerértesítést megjeleníteni, amíg az adatbázis nincs lezárva. Hogy ez működjön, kérjük, adja meg az engedélyt. Nem érdekel A fájl már nem elérhető a Keepass2Android által. Vagy el lett távolítva, vagy a hozzáférési jogosultságok vissza lettek vonva. Kérjük használja a Fájl újra megnyitását, pl. az adatbázis-váltást használva. Adatbázisok előrehozott betöltése @@ -504,6 +514,19 @@ SFTP tárhely adatai: Hitelesítési mód A nyilvános kulcs küldése... + Privátkulcs kiválasztása + Új kulcs neve + Új kulcs tartalma + Privátkulcs elmentve + A privátkulcs mentése nem sikerült: %1$s + Adja meg az elmentendő kulcs nevét és tartalmát + A privát kulcs törölve: %1$s + A privát kulcs törlése sikertelen: %1$s + Privát kulcs mentése + Privát kulcs törlése + Privát kulcs kiválasztása + [Új hozzáadása...] + Kulcshoz tartozó jelmondata Kulcscsere (KEX) algoritmus (opcionális) Nevek/specifikációk, vesszővel elválasztva Szerverazonosításhoz használt kulcs algoritmusa(i) (opcionális) @@ -523,9 +546,12 @@ Dropbox (KPA2 mappa) Válassza ezt az opciót, ha nem akarja, hogy a KP2A a teljes Dropbox tárhelyhez hozzáférjen. A KP2A csak az Apps/Keepass2Android könyvtárhoz fog hozzáférést igényelni. Ha már meglévő, de máshol tárolt adatbázist kíván ilyen módon elérni, akkor válassza ezt az opciót a könyvtár létrehozásához, majd helyezze át az adatbázisfájlt a létrehozott könyvtárba (például egy PC-ről), majd válassza még egyszer ezt az opciót a fájl megnyitásához. Google Drive + Figyelem! A Google egyre több felhasználó számára korlátozza a Google Drive-hoz való hozzáférést az alkalmazásokból. Ha a beépített Google Drive implementáció nem működik, kérjük, használja helyette a Alapértelmezett fájlválasztót és válassza ott a Google Drive-ot! Google Drive (KP2A fájlok) Válassza ezt az opciót, ha nem akarja, hogy a KP2A a teljes Google Drive-hoz hozzáférjen. Fontos, hogy először egy új adatbázist kell létrehoznia, a korábban létrehozott fájlokat az alkalmazás nem fogja látni. Vagy válassza ezt az opciót az Új adatbázis létrehozása képernyőn, vagy, ha már létezik az opció, exportálja azt ennek ezzel az opcióval. + PCloud (KP2A folder) Ez a tárhelytípus csak az \"Applications/Keepass2Android\" mappához igényel hozzáférést. Ahhoz, hogy a PCloud tárhelyed egy meglévő adatbázisát használd, azt ebben az mappában kell elhelyezned. + PCloud (teljes hozzáférés) OneDrive OneDrive Az összes fájl és a megosztott fájlok @@ -572,12 +598,14 @@ Kérjük, konfigurálja az adatbázist hitelesítő kérdés-válasszal való használthoz a KeePass 2.x (PC-s verzió) KeeChallenge beépülő modulja segítségével. OTP kiegészítő fájl frissítése közben hiba történt! TOTP mezőnév + Idő alapú egyszer használatos jelszó (TOTP) Ha a \"TrayTotp\" beépülő-modult nem alapértelmezett beállításokkal használja, adja meg annak a mezőnek a nevét, amit a jelszógenerálásnál használni kell (megegyezően a PC-n használt beállítással). TOTP beállítások mező Adja meg a TrayTotp beállítások mezőjének nevét. TrayTotp Naplófájl a hibakereséshez Naplófájl használata + FTP/SFTP naplózása Az alkalmazás kimenetének egy helyi naplófájlba írása Hibakeresési naplóbejegyzések küldése... Töltés... @@ -646,6 +674,21 @@ Folytatás A megadott URI nem tűnik fájlnévnek. Biztos benne, hogy jó URI-t adott meg? Az összetett kulcs érvénytelen! Próbálkozzon újra. + Az összetett kulcs érvénytelen! Kérjük, próbálja meg a következő lépésekkel feloldani az adatbázisát:\n + + - Győződjön meg róla, hogy helyesen adta meg a jelszót. Használja a szem ikont a beírt jelszó felfedéséhez.\n + - Győződjön meg róla, hogy a megfelelő jelszótípust választotta ki. Győződjön meg róla, hogy ez megegyezik az adatbázis létrehozásakor használt típussal.\n + - Győződjön meg róla, hogy a megfelelő adatbázisfájlt választotta ki. + \n + - Tipp: Ha úgy gondolja, hogy az adatbázis-fájlja sérült lehet, vagy nem emlékszik a főkulcsra (jelszó) a módosítás után, akkor a „%1$s” gombra koppintva és a helyi biztonsági mentést kiválasztva próbálkozhat a fájl utolsó sikeresen megnyitott verziójával. + \n + - Tipp: A Keepass2Android az utolsó sikeresen megnyitott fájlverziót a belső tárhelyen tárolja. Megnyithatja azt a „%1$s” koppintással és a helyi biztonsági mentés kiválasztásával. + A fájl sérült. \n + Néhány tipp, amely segíthet a probléma diagnosztizálásában:\n + + - Ha a fájlt USB-n keresztül másolta (MTP-mód), próbálja meg újra egy olyan eszközzel, mint a MyPhoneExplorer. Az MTP bizonyos esetekben csonkítja a fájlokat.\n + - Ha nem tudja megnyitni a fájlt ugyanarról a helyről a számítógépéről sem, akkor nagyon valószínű, hogy a fájl valóban sérült. Kérjük, ekkor használja az adatbázis egy biztonsági mentését. Ha feltételezi, hogy a Keepass2Android okozta a sérülést, kérjük, lépjen kapcsolatba a támogatói csapatot.\n + - Ha még meg tudja nyitni a fájlt a számítógépén, kérjük, lépjen kapcsolatba a támogatói csapattal. Megpróbálhatja más beállításokkal elmenteni a számítógépen (például tömörítetlenül), és azt megnyitni a Keepass2Androidban. Egy másik adatbázis megnyitása… Adatbázis kiválasztása Csatolt adatbázisok konfigurálása… @@ -734,8 +777,8 @@ Jelszó - KP2A Private/Public key - Custom Private key + KP2A privát/publikus kulcs + Egyedi privát kulcs Továbblépés, figyelmeztetés nélkül @@ -753,6 +796,11 @@ Az automatikus kitöltés engedélyezése %1$s esetén Nem sikerült összerendelni a %1$s internettartományt a %2$s alkalmazással Biometrikus eszköz detektálva. Szeretné engedélyezni az adatbázis biometrikus feloldását? + Értesítések engedélyezése + A Keepass2Android képes értesítéseket megjeleníteni, ami lehetővé teszi, hogy többször vagy egyszer használatos jelszavakat másoljon a vágólapra, vagy aktiválja a beépített billentyűzetet. Ez hasznos többféle érték más alkalmazásokba történő átviteléhez, úgy, hogy ne kelljen többször is alkalmazást váltani. Szeretné engedélyezni az ilyen értesítéseket? + Értesítések engedélyezése + A lehetőség kikapcsolása + Ne most Értem Ne mutassa többet Emlékszik a főkulcsra (jelszó)? @@ -771,5 +819,8 @@ A(z) \"%1$s\" tartományhoz tartozó azonosítókat készül a(z) \"%2$s\" alkalmazás számára elérhetővé tenni. Ha megbízik abban, hogy a(z) \"%1$s\" tartomány a(z) \"%2$s\" alkalmazáshoz tartozik, vagy megbízik abban, hogy az alkalmazás nem él vissza a titkos adatokkal (mert például egy megbízható böngészőprogram), folytassa. Ha nem, szakítsa meg a folyamatot. Mindig fogadja el itt: \"%1$s\" + Visszakapcsolás, ha végzett + Visszaváltás a Küldés/Ugrás/Kész gombok megnyomásakor + A QR-kód beolvasásához szükséges a Google Play Service. Kérjük, telepítse vagy frissítse a szolgáltatást a készülékén. Keepass2Android billentyűzetbeállítások From b0cb0b06a20337f9490e3edd9b67e6b525ec3e0b Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 20 Mar 2025 19:11:11 +0100 Subject: [PATCH 010/150] New translations strings.xml (German) --- .../Resources/values-de/strings.xml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/keepass2android-app/Resources/values-de/strings.xml b/src/keepass2android-app/Resources/values-de/strings.xml index 131b97d3..9bd5e551 100644 --- a/src/keepass2android-app/Resources/values-de/strings.xml +++ b/src/keepass2android-app/Resources/values-de/strings.xml @@ -642,7 +642,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die Datenbank ist schreibgeschützt Keepass2Android hat die aktuelle Datenbank im schreibgeschützten Modus geöffnet. Es scheint, dass die Datei von einer externen Anwendung aus geöffnet wurde. Über diesen Weg ist das Schreiben nicht möglich. Wenn Änderungen an der Datenbank vorgenommen werden sollen, bitte die Datenbank schließen und „Datenbank wechseln“ wählen. Danach die Datei über eine der verfügbaren Optionen öffnen, sofern möglich. - Datei ist schreibgeschützt. Diese Attribut entfernen, wenn Änderungen an der Datenbank vorgenommen werden sollen. + Datei ist schreibgeschützt. Dieses Attribut entfernen, wenn Änderungen an der Datenbank vorgenommen werden sollen. Das Speichern ist aufgrund von Einschränkungen, die in Android KitKat eingeführt wurden, nicht möglich. Wenn Änderungen an der Datenbank vorgenommen werden sollen, bitte die Datenbank schließen und „Datenbank wechseln“ wählen. Danach die Datei über die systeminterne Dateiauswahl öffnen. Lokale Sicherungskopien können nicht bearbeitet werden. Du kannst über \"Datenbank-Einstellungen\" - \"Datenbank exportieren\" dieses Backup an einen anderen Ort exportieren und dann von dort öffnen. Dann kannst du auch wieder Änderungen vornehmen. Icon aus Datei hinzufügen... @@ -716,6 +716,19 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Benachrichtigung zum schnellen Zugriff auf den aktuell gewählten Eintrag. Datenbank nach drei fehlgeschlagenen biometrischen Entsperrversuchen schließen. Achtung! Die biometrische Authentifizierung kann von Android ungültig gemacht werden, z. B. nach dem Hinzufügen eines neuen Fingerabdrucks in den Geräteeinstellungen. Bitte sicherstellen, dass jederzeit klar ist, wie mit dem eigenen Hauptpasswort entsperrt werden kann! + + Upgraded from Xamarin Android to .net 8 + Upgrade auf Target-SDK 34 + Upgraded to Material 3 user interface + Improve autofill to work with Compose apps + Fix hostname matching in autofill and search + + + OneDrive SDK auf Version 5.68 aktualisiert + Dropbox SDK auf Version 7.0.0 aktualisiert + Gradle, NewtonsoftJson, FluentFTP, MegaApiClient und okhttp aktualisiert + Bugfix in WebDav-Dateiauswahl + Buttons für die Suche und eine TOTP-Übersicht hinzugefügt (falls TOTP-Einträge vorhanden sind) Darstellung von TOTP-Feldern verbessert: Timeout-Anzeige hinzugefügt und besser sichtbar gemacht. @@ -1146,5 +1159,6 @@ Erstes öffentliches Release Für „%1$s“ immer akzeptieren Tastatur zurückwechseln wenn fertig Beim Drücken von Senden/Los/Fertig zurückschalten + QR-Code-Scannen erfordert Google Play-Dienste. Bitte installiere oder aktualisiere Google Play-Dienste auf deinem Gerät. Android-Tastatureinstellungen From e05fe94650325cf7bc3083f90ea9ac8766a1a064 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 20 Mar 2025 21:28:17 +0100 Subject: [PATCH 011/150] New translations strings.xml (Italian) --- .../Resources/values-it/strings.xml | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/keepass2android-app/Resources/values-it/strings.xml b/src/keepass2android-app/Resources/values-it/strings.xml index d369f65b..b9f3299b 100644 --- a/src/keepass2android-app/Resources/values-it/strings.xml +++ b/src/keepass2android-app/Resources/values-it/strings.xml @@ -546,6 +546,7 @@ Dropbox (cartella KP2A) Se non vuoi dare a KP2A accesso completo al tuo Dropbox, puoi selezionare questa opzione. Richiederà solo l\'accesso alla cartella Applicazioni/Keepass2Android. Ciò è particolarmente indicato quando si crea un nuovo database. Se hai già un database, fai click su questa opzione per creare la cartella, poi spostaci dentro il file (dal PC), quindi seleziona di nuovo questa opzione per aprire il file. Google Drive + Nota: Google sta limitando l\'accesso a Google Drive dalle app per un numero sempre maggiore di utenti. Se la funzione integrata di Google Drive non funziona, si prega di utilizzare il selettore di file di sistema e selezionare Google Drive! Google Drive (file KP2A) Se non vuoi dare a KP2A accesso completo al tuo Google Drive completo, puoi selezionare questa opzione. Nota che è necessario prima creare un file di database, i file esistenti non sono visibili per l\'app. Scegli questa opzione dalla schermata Crea database o, se hai già aperto un database, esportando il database scegliendo questa opzione. PCloud (KP2A folder) @@ -672,6 +673,22 @@ Continua L\'URI inserito non sembra il nome di un file. Sei sicuro che sia un file valido? Chiave composita non valida! Riprova. + Chiave composta non valida! Per favore prova la seguente procedura per sbloccare il database: \n + +• assicurati di aver inserito la password corretta. Usa l\'icona che rappresenta un occhio per vedere la password immessa.\n +• assicurati di aver selezionato il tipo di password corretto. Assicurati che coincida con il tipo usato quando hai creato il database.\n +• assicurati di aver selezionato il file del database corretto. + \n + • Suggerimento: se pensi che il tuo file di database possa essere danneggiato oppure non ricordi la password principale dopo averla modificata, puoi provare con l\'ultima versione di file aperta correttamente facendo clic su \"%1$s\" e selezionando il backup locale. + \n + • Suggerimento: Keepass2Android ha archiviato l\'ultima versione del file aperta correttamente nella memoria interna. È possibile aprirla facendo clic su \"%1$s\" e selezionando il backup locale. + + Il file è corrotto.\n +Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\n + +• se hai copiato il file tramite USB (MTP-Mode), riprova usando uno strumento come MyPhoneExplorer. (MTP a volte tronca i file.)\n +• se non puoi aprire il file dallo stesso percorso sul tuo PC, è molto probabile che il file sia effettivamente danneggiato. Per favore usa un backup del database. Se credi che Keepass2Android abbia corrotto il file, contatta il supporto.\n +• se puoi ancora aprire il file sul tuo PC, contatta il supporto. Puoi provare a salvarlo con impostazioni differenti (es: non compresso) sul PC e, poi, riprovare ad aprirlo in Keepass2Android. Apri un altro database… Seleziona il database Configura i database figli… @@ -699,6 +716,19 @@ Notifica per semplificare l\'accesso alla voce attualmente selezionata. Chiudi il database dopo tre tentativi di sblocco biometrici falliti. Attenzione! L\'autenticazione biometrica può essere invalidata da Android, ad es. dopo aver aggiunto una nuova impronta digitale nelle impostazioni del dispositivo. Assicurati di sapere sempre come sbloccare con la tua password principale! + + Aggiornato da Xamarin Android a .net 8 + Aggiornato a Target SDK 34 + Aggiornato all\'interfaccia utente Material 3 + Migliora l\'autofill per funzionare con le app Compose + Corretta la corrispondenza con l\' hostname in riempimento automatico e ricerca + + + Aggiornato OneDrive SDK alla versione 5.68 + Aggiornato Dropbox SDK alla versione 7.0.0 + Aggiornati Gradle , NewtonsoftJson, FluentFTP, MegaApiClient e okhttp + Bugfix nella selezione dei file WebDav + Aggiunti pulsanti di azione fluttuanti per la ricerca e TOTP panoramica (se sono presenti voci TOTP). Vista migliorata dei campi TOTP aggiungendo un indicatore di tempo limite e mostrandolo in modo più evidente. @@ -989,5 +1019,7 @@ Stai per inserire le credenziali per il dominio \"%1$s\" nell\'app \"%2$s\" Se ti fidi di \"%2$s\" ad appartenere a \"%1$s\" o se ti fidi dell\'app \"%2$s\" a non abusare delle credenziali (es. perché si tratta di un\'applicazione sicura), è possibile continuare. Altrimenti si prega di annullare. Accetta sempre in \"%1$s\" + Torna indietro quando premi invia/vai/fatto + La scansione del codice QR richiede Google Play Services. Installa o aggiorna Google Play Services sul tuo dispositivo. Impostazioni tastiera Keepass2Android From dc3ee35c8bd373d4269a67b8d768fa0374e80859 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Fri, 21 Mar 2025 14:54:31 +0100 Subject: [PATCH 012/150] New translations strings.xml (Italian) --- .../Resources/values-it/strings.xml | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/keepass2android-app/Resources/values-it/strings.xml b/src/keepass2android-app/Resources/values-it/strings.xml index b9f3299b..be8df53b 100644 --- a/src/keepass2android-app/Resources/values-it/strings.xml +++ b/src/keepass2android-app/Resources/values-it/strings.xml @@ -932,6 +932,17 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\ * Puoi installare altri pacchetti di icone (le vecchie icone in stile Windows sono disponibili sul Play Store)\n * Aggiunta richiesta di conferma prima di eliminare voci senza passare dal cestino\n * Correzione errori (errata visualizzazione dell\'OTP-secret, icona dell\'app errata in certi posti)\n + Versione 0.9.8b\n +* correzione di errori (il salvataggio di alcuni database fallisce, l\'esportazione su periferica locale non funziona, la selezione di alcune opzioni manda l\'app in crash)\n + Versione 0.9.8\n +* supporto per Storage Access Framework (permette a KP2A Offline di scrivere su scheda SD e Google Drive)\n +* tenta di rilevare errori dell\'utente nell\'inserimento degli URL di WebDAV (cartella al posto di file)\n +* cambiato il font della password\n +* consente di modificare l\'account di Dropbox\n +* bugfix: ora ricorda la password OTP + Versione 0.9.7b\n +* aggiornate le traduzioni\n +* bugfix: font Password mancante nella versione 0.9.7; ordina per nome non ordinava i gruppi\n Estesa la possibilità di donare una birra o qualcos\'altro 30 secondi @@ -981,8 +992,8 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\ Password - KP2A Private/Public key - Custom Private key + Chiave privata/pubblica di KP2A + Chiave privata personalizzata Ignora gli errori di convalida del certificato @@ -1000,6 +1011,10 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\ Attiva Compilazione automatica per %1$s Non è possibile associare il dominio web %1$s con l\'app %2$s Keepass2Android ha rilevato il sensore biometrico. Desideri attivare lo sblocco biometrico per questo database? + Consenti le notifiche + Keepass2Android può mostrare le notifiche con i pulsanti per copiare valori come password e TOTP negli appunti, o per far apparire la tastiera integrata. Questo è utile per trasferire i valori in altre applicazioni senza passare a Keepass2Android ripetutamente. Vuoi abilitare tali notifiche? + Consenti le notifiche + Disabilita questa funzione Non ora Ho capito Non mostrare più @@ -1019,6 +1034,7 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\ Stai per inserire le credenziali per il dominio \"%1$s\" nell\'app \"%2$s\" Se ti fidi di \"%2$s\" ad appartenere a \"%1$s\" o se ti fidi dell\'app \"%2$s\" a non abusare delle credenziali (es. perché si tratta di un\'applicazione sicura), è possibile continuare. Altrimenti si prega di annullare. Accetta sempre in \"%1$s\" + Cambia tastiera quando terminato Torna indietro quando premi invia/vai/fatto La scansione del codice QR richiede Google Play Services. Installa o aggiorna Google Play Services sul tuo dispositivo. Impostazioni tastiera Keepass2Android From a53ff37e8943c10b6c33d06d6ead7ffe8889bd83 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 23 Mar 2025 07:30:07 +0100 Subject: [PATCH 013/150] New translations strings.xml (Vietnamese) --- src/keepass2android-app/Resources/values-vi/strings.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/keepass2android-app/Resources/values-vi/strings.xml b/src/keepass2android-app/Resources/values-vi/strings.xml index f9f95c04..11af52e0 100644 --- a/src/keepass2android-app/Resources/values-vi/strings.xml +++ b/src/keepass2android-app/Resources/values-vi/strings.xml @@ -546,6 +546,7 @@ Dropbox (thư mục KP2A) Nếu bạn không muốn cấp cho KP2A quyền truy cập vào Dropbox đầy đủ của mình, bạn có thể chọn tùy chọn này. Nó sẽ chỉ yêu cầu quyền truy cập vào thư mục Apps/Keepass2Android. Điều này đặc biệt phù hợp khi tạo cơ sở dữ liệu mới. Nếu bạn đã có cơ sở dữ liệu, hãy chọn tùy chọn này để tạo thư mục, sau đó đặt tệp của bạn bên trong thư mục (từ PC của bạn) và sau đó chọn lại tùy chọn này để mở tệp. Google Drive + Xin lưu ý: Google ngày càng giới hạn quyền truy cập Google Drive của các ứng dụng đối với nhiều người dùng hơn. Nếu mục Google Drive không dùng được, hãy chọn Trình chọn tập tin của hệ thống sau đó chọn mục Google Drive! Google Drive (tệp KP2A) Nếu bạn không muốn cấp cho KP2A quyền truy cập vào Google Drive đầy đủ của mình, bạn có thể chọn tùy chọn này. Lưu ý rằng trước tiên bạn cần tạo tệp cơ sở dữ liệu, các tệp hiện có sẽ không hiển thị với ứng dụng. Chọn tùy chọn này từ màn hình Tạo cơ sở dữ liệu hoặc, nếu bạn đã mở cơ sở dữ liệu, bằng cách xuất cơ sở dữ liệu chọn tùy chọn này. PCloud (thư mục KP2A) @@ -672,6 +673,12 @@ Tiếp tục URI bạn đã nhập không có dạng tên tập tin. Bạn có chắc chắn đây là tập tin hợp lệ không? Khoá hỗn hợp không hợp lệ. Xin thử lại. + Khoá tổng hợp không hợp lệ! Hãy thử các bước sau để mở khoá cơ sở dữ liệu của bạn:\n + + • Nhập đúng mật khẩu. Ấn vào biểu tượng con mắt để hiện mật khẩu đã nhập.\n + • Chọn đúng loại mật khẩu. Loại mật khẩu phải giống với loại mật khẩu đã chọn khi tạo cơ sở dữ liệu.\n + • Chọn đúng tập tin cơ sở dữ liệu. + Mở cơ sở dữ liệu khác… Chọn cơ sở dữ liệu Định cấu hình cơ sở dữ liệu con… From 1cb036941e3dff35a45a1b228005dea8eb041a52 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Sun, 23 Mar 2025 09:12:18 +0100 Subject: [PATCH 014/150] New translations strings.xml (Vietnamese) --- .../Resources/values-vi/strings.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/keepass2android-app/Resources/values-vi/strings.xml b/src/keepass2android-app/Resources/values-vi/strings.xml index 11af52e0..b5da333a 100644 --- a/src/keepass2android-app/Resources/values-vi/strings.xml +++ b/src/keepass2android-app/Resources/values-vi/strings.xml @@ -679,6 +679,20 @@ • Chọn đúng loại mật khẩu. Loại mật khẩu phải giống với loại mật khẩu đã chọn khi tạo cơ sở dữ liệu.\n • Chọn đúng tập tin cơ sở dữ liệu. + \n + • Gợi ý: Nếu bạn nghĩ rằng tập tin cơ sở dữ liệu bị hỏng hoặc bạn đã quên khoá chính sau khi thay đổi nó, bạn có thể nhấn \"%1$s\" và chọn bản sao lưu cục bộ để mở phiên bản tập tin được mở thành công gần đây nhất. + + \n + • Gợi ý: Keepass2Android đã lưu trữ phiên bản tập tin được mở thành công gần đây nhất trên bộ nhớ trong. Bạn có thể mở nó bằng cách nhấn vào \"%1$s\" và chọn bản sao lưu cục bộ. + + Tập tin bị hỏng. \n + Có một số mẹo giúp chẩn đoán vấn đề như sau:\n + + • Nếu bạn sao chép tập tin qua USB (sử dụng chế độ MTP), hãy thử sao chép lại bằng một phần mềm như MyPhoneExplorer. Trong một số trường hợp, MTP có thể cắt bớt nội dung tập tin.\n + • Nếu không mở được tập tin ở cùng một vị trí trên máy tính, rất có thể tập tin đó thực sự bị hỏng. Trong trường hợp này, hãy sử dụng một bản sao lưu cơ sở dữ liệu. Nếu bạn nghi ngờ rằng Keepass2Android làm hỏng tập tin, hãy liên hệ với bộ phận hỗ trợ.\n + • Nếu tập tin vẫn mở được bằng máy tính, hãy liên hệ với bộ phận hỗ trợ. Bạn có thể thử lưu lại tập tin trên máy tính với cài đặt khác (ví dụ như không nén) sau đó thử mở lại bằng Keepass2Android. + + Mở cơ sở dữ liệu khác… Chọn cơ sở dữ liệu Định cấu hình cơ sở dữ liệu con… From ecf416febc8b51c5cec6da13d6a0f75aee774dc9 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:25 +0100 Subject: [PATCH 015/150] New translations strings.xml (German) --- src/keepass2android-app/Resources/values-de/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-de/strings.xml b/src/keepass2android-app/Resources/values-de/strings.xml index 9bd5e551..ffe45c1d 100644 --- a/src/keepass2android-app/Resources/values-de/strings.xml +++ b/src/keepass2android-app/Resources/values-de/strings.xml @@ -722,6 +722,7 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n Upgraded to Material 3 user interface Improve autofill to work with Compose apps Fix hostname matching in autofill and search + Fix issue with password generator OneDrive SDK auf Version 5.68 aktualisiert From 9939e07b7dd3f691c1bab5dd8f6844773bccc1a1 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:27 +0100 Subject: [PATCH 016/150] New translations strings.xml (Italian) --- src/keepass2android-app/Resources/values-it/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-it/strings.xml b/src/keepass2android-app/Resources/values-it/strings.xml index be8df53b..5578be53 100644 --- a/src/keepass2android-app/Resources/values-it/strings.xml +++ b/src/keepass2android-app/Resources/values-it/strings.xml @@ -722,6 +722,7 @@ Ecco alcuni suggerimenti che ti potrebbero aiutare a diagnosticare il problema:\ Aggiornato all\'interfaccia utente Material 3 Migliora l\'autofill per funzionare con le app Compose Corretta la corrispondenza con l\' hostname in riempimento automatico e ricerca + Fix issue with password generator Aggiornato OneDrive SDK alla versione 5.68 From 3c8b530e2eb26223542106cd5fdf68df181b720f Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:28 +0100 Subject: [PATCH 017/150] New translations strings.xml (Slovak) --- src/keepass2android-app/Resources/values-sk/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-sk/strings.xml b/src/keepass2android-app/Resources/values-sk/strings.xml index ba4527b6..b37bb55b 100644 --- a/src/keepass2android-app/Resources/values-sk/strings.xml +++ b/src/keepass2android-app/Resources/values-sk/strings.xml @@ -726,6 +726,7 @@ Aktualizované na používateľské rozhranie Material 3 Vylepšené automatické dopĺňanie kvôli fungovaniu s aplikáciami Compose Oprava zhody mena hostiteľa v automatickom dopĺňaní a vyhľadávaní + Fix issue with password generator Aktualizované na OneDrive SDK, verziu 5.68 From 14efce62ffde0912269e8a729eefb9febfb98efe Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:29 +0100 Subject: [PATCH 018/150] New translations strings.xml (Slovenian) --- src/keepass2android-app/Resources/values-sl/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-sl/strings.xml b/src/keepass2android-app/Resources/values-sl/strings.xml index 2825e61d..8fb045c8 100644 --- a/src/keepass2android-app/Resources/values-sl/strings.xml +++ b/src/keepass2android-app/Resources/values-sl/strings.xml @@ -726,6 +726,7 @@ Nadgrajen na uporabniški vmesnik Material 3 Izboljšanje samodejnega izpolnjevanja za delovanje z aplikacijami Compose Popravek ujemanja gostiteljskega imena v samodejnem izpolnjevanju in iskanju + Fix issue with password generator Nadgradnja OneDrive SDK na različico 5.68 From f06937dab325f860017a00d4e3092c474ba39c4d Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:32 +0100 Subject: [PATCH 019/150] New translations strings.xml (French) --- src/keepass2android-app/Resources/values-fr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-fr/strings.xml b/src/keepass2android-app/Resources/values-fr/strings.xml index 0199439b..c9b5a3a0 100644 --- a/src/keepass2android-app/Resources/values-fr/strings.xml +++ b/src/keepass2android-app/Resources/values-fr/strings.xml @@ -725,6 +725,7 @@ Mise à niveau vers l\'interface utilisateur Material 3 Improve autofill to work with Compose apps Fix hostname matching in autofill and search + Fix issue with password generator Ajout de boutons d\'action flottants pour la recherche et l\'aperçu TOTP (si des entrées TOTP sont présentes). From b32c2dbc7ecab717b0ecdacc96faa1c06bdebe74 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:37 +0100 Subject: [PATCH 020/150] New translations strings.xml (Czech) --- src/keepass2android-app/Resources/values-cs/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-cs/strings.xml b/src/keepass2android-app/Resources/values-cs/strings.xml index 12dce326..9d5cee2f 100644 --- a/src/keepass2android-app/Resources/values-cs/strings.xml +++ b/src/keepass2android-app/Resources/values-cs/strings.xml @@ -723,6 +723,7 @@ Aktualizováno na uživatelské rozhraní Material 3 Vylepšení automatického vyplňování pro práci s aplikacemi Compose Oprava přiřazování názvů hostitelů v automatickém vyplňování a vyhledávání + Fix issue with password generator Aktualizováno OneDrive SDK na verzi 5.68 From 1b389ef12e1f82b5f7eb88c508f2b27b3b656422 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:43 +0100 Subject: [PATCH 021/150] New translations strings.xml (Japanese) --- src/keepass2android-app/Resources/values-ja/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-ja/strings.xml b/src/keepass2android-app/Resources/values-ja/strings.xml index ecd955d2..3f76eafe 100644 --- a/src/keepass2android-app/Resources/values-ja/strings.xml +++ b/src/keepass2android-app/Resources/values-ja/strings.xml @@ -724,6 +724,7 @@ ユーザーインターフェイスを Material 3 にアップグレード Compose アプリでの自動入力機能を改善 自動入力と検索でホスト名の一致条件を修正 + Fix issue with password generator OneDrive SDK をバージョン 5.68 にアップグレード From 4764b15e7534b0c27cc573fa2a73ae65753cc427 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 09:06:54 +0100 Subject: [PATCH 022/150] New translations strings.xml (Portuguese, Brazilian) --- src/keepass2android-app/Resources/values-pt-rBR/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml index 4de49320..74bbe4fe 100644 --- a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml @@ -728,6 +728,7 @@ Atualizado para a interface de usuário Material 3 Melhorado o preenchimento automático para trabalhar com aplicativos Compose Corrigido a correspondência do nome do host em preenchimento automático e pesquisa + Fix issue with password generator Atualizado o OneDrive SDK para a versão 5.68 From e2711b709de2a5a220c0ce0c51b31e7f2c155bd3 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Wed, 26 Mar 2025 12:13:50 +0100 Subject: [PATCH 023/150] New translations strings.xml (Portuguese, Brazilian) --- src/keepass2android-app/Resources/values-pt-rBR/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml index 74bbe4fe..02b4a76b 100644 --- a/src/keepass2android-app/Resources/values-pt-rBR/strings.xml +++ b/src/keepass2android-app/Resources/values-pt-rBR/strings.xml @@ -728,7 +728,7 @@ Atualizado para a interface de usuário Material 3 Melhorado o preenchimento automático para trabalhar com aplicativos Compose Corrigido a correspondência do nome do host em preenchimento automático e pesquisa - Fix issue with password generator + Corrigido um problema com gerador de senhas Atualizado o OneDrive SDK para a versão 5.68 From 4ba40ba24fb133eba67ee3a00b4bfcd0fb7bbb4d Mon Sep 17 00:00:00 2001 From: PhilippC Date: Thu, 27 Mar 2025 12:19:23 +0100 Subject: [PATCH 024/150] New translations strings.xml (Slovenian) --- src/keepass2android-app/Resources/values-sl/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keepass2android-app/Resources/values-sl/strings.xml b/src/keepass2android-app/Resources/values-sl/strings.xml index 8fb045c8..840297d6 100644 --- a/src/keepass2android-app/Resources/values-sl/strings.xml +++ b/src/keepass2android-app/Resources/values-sl/strings.xml @@ -726,7 +726,7 @@ Nadgrajen na uporabniški vmesnik Material 3 Izboljšanje samodejnega izpolnjevanja za delovanje z aplikacijami Compose Popravek ujemanja gostiteljskega imena v samodejnem izpolnjevanju in iskanju - Fix issue with password generator + Odpravljena težava z generatorjem gesel Nadgradnja OneDrive SDK na različico 5.68 From e76f3999b6e8634afcb84e8dbbe8b1338606bea6 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 1 Apr 2025 15:36:39 +0200 Subject: [PATCH 025/150] reduce logging verbosity of file provider --- .../kp2afilechooser/Kp2aFileProvider.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java b/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java index f46fb622..dbf96499 100644 --- a/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java +++ b/src/java/android-filechooser-AS/app/src/main/java/keepass2android/kp2afilechooser/Kp2aFileProvider.java @@ -64,8 +64,6 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { @Override public boolean onCreate() { - Log.d("KP2A_FC_P", "onCreate"); - BaseFileProviderUtils.registerProviderInfo(_ID, getAuthority()); @@ -222,12 +220,12 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { try { checkConnection(uri); - Log.d("KP2A_FC_P", "checking connection for " + uri + " ok."); + if (Utils.doLog()) Log.d("KP2A_FC_P", "checking connection for " + uri + " ok."); return null; } catch (Exception e) { - Log.d("KP2A_FC_P","Check connection failed with: " + e.toString()); + if (Utils.doLog()) Log.d("KP2A_FC_P","Check connection failed with: " + e.toString()); MatrixCursor matrixCursor = new MatrixCursor(BaseFileProviderUtils.CONNECTION_CHECK_CURSOR_COLUMNS); RowBuilder newRow = matrixCursor.newRow(); @@ -255,7 +253,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { } catch (FileNotFoundException ex) { - Log.d("KP2A_FC_P","File not found. Ignore."); + if (Utils.doLog()) Log.d("KP2A_FC_P","File not found. Ignore."); return; } @@ -276,8 +274,8 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { MatrixCursor matrixCursor = null; String lastPathSegment = uri.getLastPathSegment(); - - Log.d("KP2A_FC_P", "lastPathSegment:" + lastPathSegment); + + if (Utils.doLog()) Log.d("KP2A_FC_P", "lastPathSegment:" + lastPathSegment); if (BaseFile.CMD_CANCEL.equals(lastPathSegment)) { int taskId = ProviderUtils.getIntQueryParam(uri, @@ -361,7 +359,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { } else if (BaseFile.CMD_CHECK_CONNECTION.equals(lastPathSegment)) { - Log.d("KP2A_FC_P","Check connection..."); + if (Utils.doLog()) Log.d("KP2A_FC_P","Check connection..."); return getCheckConnectionCursor(uri); } @@ -470,7 +468,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { String displayName = getFileEntryCached(dirName).displayName; newRow.add(displayName); - Log.d(CLASSNAME, "Returning name " + displayName+" for " +dirName); + if (Utils.doLog()) Log.d(CLASSNAME, "Returning name " + displayName+" for " +dirName); } } @@ -690,7 +688,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { } catch (Exception e) { - Log.d("KP2A_FC_P", "sortFiles() >> "+e); + if (Utils.doLog()) Log.d("KP2A_FC_P", "sortFiles() >> "+e); throw e; } }// sortFiles() @@ -777,14 +775,14 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { path = removeTrailingSlash(path); if (path.indexOf("://") == -1) { - Log.d("KP2A_FC_P", "invalid path: " + path); + if (Utils.doLog()) Log.d("KP2A_FC_P", "invalid path: " + path); return null; } String pathWithoutProtocol = path.substring(path.indexOf("://") + 3); int lastSlashPos = path.lastIndexOf("/"); if (pathWithoutProtocol.indexOf("/") == -1) { - Log.d("KP2A_FC_P", "parent of " + path + " is null"); + if (Utils.doLog()) Log.d("KP2A_FC_P", "parent of " + path + " is null"); return null; } else @@ -793,7 +791,7 @@ public abstract class Kp2aFileProvider extends BaseFileProvider { if (params != null) { parent += params; } - Log.d("KP2A_FC_P", "parent of " + path +" is " + parent); + if (Utils.doLog()) Log.d("KP2A_FC_P", "parent of " + path +" is " + parent); return parent; } } From c4a73bf1074f6199876bb885bc35a6f5129780b4 Mon Sep 17 00:00:00 2001 From: PhilippC Date: Fri, 4 Apr 2025 15:32:59 +0200 Subject: [PATCH 026/150] New translations strings.xml (Czech) --- src/keepass2android-app/Resources/values-cs/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/keepass2android-app/Resources/values-cs/strings.xml b/src/keepass2android-app/Resources/values-cs/strings.xml index 9d5cee2f..7b36be0e 100644 --- a/src/keepass2android-app/Resources/values-cs/strings.xml +++ b/src/keepass2android-app/Resources/values-cs/strings.xml @@ -546,6 +546,7 @@ Dropbox (KP2A složka) Pokud nechcete, aby měl KP2A plný přístup k vašemu Dropbox účtu, může vybrat tuto možnost. Bude vyžadován pouze přístup ke složce Apps/Keepass2Android. Toto je vhodné zejména při vytváření nové databáze. Pokud již máte databázi, zvolte na tuto možnost pro vytvoření složky, poté umístěte soubor (z PC) do této složky a zvolte tuto možnost znovu pro otevření souboru. Google Drive + Upozornění: Společnost Google omezuje přístup k Disku Google z aplikací pro stále více uživatelů. Pokud vestavěná implementace Disku Google nefunguje, použijte místo toho systémový výběr souborů a vyberte Disk Google tam! Google Drive (KP2A soubory) Nechcete-li dát aplikaci KeePass2Android přístup k celému vašemu Google Drive, použijte tuto možnost. Upozorňujeme, že nejprve musíte vytvořit soubor s databází položek, existující soubory nejsou viditelné pro aplikaci. Toto můžete udělat z obrazovky Vytvořit databázi, nebo exportem právě otevřené databáze, volbou této možnosti PCloud (složka KP2A) @@ -723,7 +724,7 @@ Aktualizováno na uživatelské rozhraní Material 3 Vylepšení automatického vyplňování pro práci s aplikacemi Compose Oprava přiřazování názvů hostitelů v automatickém vyplňování a vyhledávání - Fix issue with password generator + Oprava problému s generátorem hesel Aktualizováno OneDrive SDK na verzi 5.68 @@ -1166,5 +1167,6 @@ První veřejné vydání Přijmout vždy v \"%1$s\" Přepnout zpět po dokončení Přepnout zpět při stisknutí tlačítka odeslat/pokračovat/ukončit + Skenování QR kódu vyžaduje služby Google Play. Nainstalujte nebo aktualizujte služby Google Play ve svém zařízení. Nastavení klávesnice Keepass2Android From 17241bc422e21d9bf74956c23c50e147bd969b86 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 8 Apr 2025 10:37:40 +0200 Subject: [PATCH 027/150] use snackbars instead of toasts (in most cases) --- src/Kp2aBusinessLogic/IKp2aApp.cs | 19 +- .../SelectStorageLocationActivityBase.cs | 6 +- .../database/edit/OnFinish.cs | 26 +- src/keepass2android-app/AboutDialog.cs | 6 +- .../CreateDatabaseActivity.cs | 6 +- .../DisableAutofillForQueryActivity.cs | 2 +- src/keepass2android-app/EntryActivity.cs | 24 +- src/keepass2android-app/EntryEditActivity.cs | 25 +- .../ExportDatabaseActivity.cs | 4 +- .../FileSaveProcessManager.cs | 2 +- src/keepass2android-app/FileSelectHelper.cs | 33 +- .../FingerprintSetupActivity.cs | 2 +- .../GeneratePasswordActivity.cs | 2 +- src/keepass2android-app/GroupBaseActivity.cs | 6 +- src/keepass2android-app/GroupEditActivity.cs | 7 +- src/keepass2android-app/KeeAutoExec.cs | 2 +- src/keepass2android-app/LockingActivity.cs | 31 +- src/keepass2android-app/NfcOtpActivity.cs | 2 +- src/keepass2android-app/PasswordActivity.cs | 193 +-- .../QueryCredentialsActivity.cs | 6 +- src/keepass2android-app/QuickUnlock.cs | 13 +- .../Resources/layout/entry_edit.xml | 11 +- .../SelectCurrentDbActivity.cs | 8 +- .../SelectStorageLocationActivity.cs | 10 +- src/keepass2android-app/SetPasswordDialog.cs | 6 +- src/keepass2android-app/ShareUrlResults.cs | 4 +- src/keepass2android-app/SyncUtil.cs | 2 +- .../Totp/TrayTotpPluginAdapter.cs | 2 +- .../Utils/MessagePresenter.cs | 153 +++ src/keepass2android-app/Utils/Util.cs | 1066 +++++++++-------- src/keepass2android-app/app/App.cs | 69 +- src/keepass2android-app/app/AppTask.cs | 10 +- .../app/OtpAuxCacheSupervisor.cs | 6 +- .../fileselect/FileSelectActivity.cs | 15 +- .../search/SearchResults.cs | 6 +- .../search/SearchTotpResults.cs | 2 +- .../ChooseForAutofillActivityBase.cs | 4 +- .../services/CopyToClipboardService.cs | 14 +- .../settings/AppSettingsActivity.cs | 14 +- .../settings/ExportKeyfileActivity.cs | 6 +- .../settings/RoundsPreference.cs | 2 +- 41 files changed, 1080 insertions(+), 747 deletions(-) create mode 100644 src/keepass2android-app/Utils/MessagePresenter.cs diff --git a/src/Kp2aBusinessLogic/IKp2aApp.cs b/src/Kp2aBusinessLogic/IKp2aApp.cs index d4602a17..9a8357f8 100644 --- a/src/Kp2aBusinessLogic/IKp2aApp.cs +++ b/src/Kp2aBusinessLogic/IKp2aApp.cs @@ -29,6 +29,14 @@ namespace keepass2android } + + public enum MessageSeverity + { + Info, + Warning, + Error + } + /// /// Interface through which Activities and the logic layer can access some app specific functionalities and Application static data /// @@ -102,10 +110,13 @@ namespace keepass2android Context ctx, string messageSuffix = ""); - /// - /// Returns a Handler object which can run tasks on the UI thread - /// - Handler UiThreadHandler { get; } + void ShowMessage(Context ctx, int resourceId, MessageSeverity severity); + void ShowMessage(Context ctx, string text, MessageSeverity severity); + + /// + /// Returns a Handler object which can run tasks on the UI thread + /// + Handler UiThreadHandler { get; } IProgressDialog CreateProgressDialog(Context ctx); diff --git a/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs b/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs index df1277bb..f44b11d9 100644 --- a/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs +++ b/src/Kp2aBusinessLogic/SelectStorageLocationActivityBase.cs @@ -94,7 +94,7 @@ namespace keepass2android } if ((resultCode == Result.Canceled) && (data != null) && (data.HasExtra("EXTRA_ERROR_MESSAGE"))) { - ShowToast(data.GetStringExtra("EXTRA_ERROR_MESSAGE")); + ShowErrorToast(data.GetStringExtra("EXTRA_ERROR_MESSAGE")); } if (resultCode == Result.Ok) @@ -150,7 +150,7 @@ namespace keepass2android protected abstract void StartFileChooser(string path, int requestCode, bool isForSave); - protected abstract void ShowToast(string text); + protected abstract void ShowErrorToast(string text); protected abstract void ShowInvalidSchemeMessage(string dataString); @@ -208,7 +208,7 @@ namespace keepass2android { return () => { - ShowToast(_app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message); + ShowErrorToast(_app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message); ReturnCancel(); }; } diff --git a/src/Kp2aBusinessLogic/database/edit/OnFinish.cs b/src/Kp2aBusinessLogic/database/edit/OnFinish.cs index 455e3a53..7c3071e8 100644 --- a/src/Kp2aBusinessLogic/database/edit/OnFinish.cs +++ b/src/Kp2aBusinessLogic/database/edit/OnFinish.cs @@ -130,24 +130,24 @@ namespace keepass2android if ( !String.IsNullOrEmpty(message) ) { Kp2aLog.Log("OnFinish message: " + message); if (makeDialog && ctx != null) - { - try - { - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ctx); - - builder.SetMessage(message) - .SetPositiveButton(Android.Resource.String.Ok, (sender, args) => ((Dialog)sender).Dismiss()) - .Show(); + { + try + { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ctx); + + builder.SetMessage(message) + .SetPositiveButton(Android.Resource.String.Ok, (sender, args) => ((Dialog)sender).Dismiss()) + .Show(); } catch (Exception) - { - Toast.MakeText(ctx, message, ToastLength.Long).Show(); - } - } + { + Toast.MakeText(ctx, message, ToastLength.Long).Show(); + } + } else Toast.MakeText(ctx ?? Application.Context, message, ToastLength.Long).Show(); - } + } } } } diff --git a/src/keepass2android-app/AboutDialog.cs b/src/keepass2android-app/AboutDialog.cs index 203a34c0..421311c3 100644 --- a/src/keepass2android-app/AboutDialog.cs +++ b/src/keepass2android-app/AboutDialog.cs @@ -59,7 +59,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(Context, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.no_url_handler, MessageSeverity.Error); } }; @@ -71,7 +71,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(Context, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.no_url_handler, MessageSeverity.Error); } }; FindViewById(Resource.Id.translate).Click += delegate @@ -82,7 +82,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(Context, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.no_url_handler, MessageSeverity.Error); } }; FindViewById(Resource.Id.donate).Click += delegate { diff --git a/src/keepass2android-app/CreateDatabaseActivity.cs b/src/keepass2android-app/CreateDatabaseActivity.cs index 60da7bea..e417ef34 100644 --- a/src/keepass2android-app/CreateDatabaseActivity.cs +++ b/src/keepass2android-app/CreateDatabaseActivity.cs @@ -183,7 +183,7 @@ namespace keepass2android // Verify that a password or keyfile is set if (password.Length == 0 && !keyfileCheckbox.Checked) { - Toast.MakeText(this, Resource.String.error_nopass, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_nopass, MessageSeverity.Error); return; } @@ -207,7 +207,7 @@ namespace keepass2android } catch (Exception) { - Toast.MakeText(this, Resource.String.error_adding_keyfile, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_adding_keyfile, MessageSeverity.Error); return; } } @@ -235,7 +235,7 @@ namespace keepass2android if (! pass.Equals(confpass)) { // Passwords do not match - Toast.MakeText(this, Resource.String.error_pass_match, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_pass_match, MessageSeverity.Error); return false; } return true; diff --git a/src/keepass2android-app/DisableAutofillForQueryActivity.cs b/src/keepass2android-app/DisableAutofillForQueryActivity.cs index df6e3101..3f5eac86 100644 --- a/src/keepass2android-app/DisableAutofillForQueryActivity.cs +++ b/src/keepass2android-app/DisableAutofillForQueryActivity.cs @@ -41,7 +41,7 @@ namespace keepass2android string requestedUrl = Intent.GetStringExtra(ChooseForAutofillActivityBase.ExtraQueryString); if (requestedUrl == null) { - Toast.MakeText(this, "Cannot execute query for null.", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "Cannot execute query for null.", MessageSeverity.Error); RestartApp(); return; } diff --git a/src/keepass2android-app/EntryActivity.cs b/src/keepass2android-app/EntryActivity.cs index 832e850a..c84e108c 100644 --- a/src/keepass2android-app/EntryActivity.cs +++ b/src/keepass2android-app/EntryActivity.cs @@ -78,7 +78,7 @@ namespace keepass2android var task = new EntryActivity.WriteBinaryTask(_activity, App.Kp2a, new ActionOnFinish(_activity, (success, message, activity) => { if (!success) - Toast.MakeText(activity, message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error); } ), ((EntryActivity)_activity).Entry.Binaries.Get(_binaryToSave), ioc); ProgressTask pt = new ProgressTask(App.Kp2a, _activity, task); @@ -107,8 +107,8 @@ namespace keepass2android public const int requestCodeBinaryFilename = 42376; public const int requestCodeSelFileStorageForWriteAttachment = 42377; - + protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content); public static void Launch(Activity act, PwEntry pw, int pos, AppTask appTask, ActivityFlags? flags = null, int historyIndex=-1) { @@ -767,9 +767,9 @@ namespace keepass2android if (parent == null || (parent.Exists() && !parent.IsDirectory)) { - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, Resource.String.error_invalid_path, - ToastLength.Long).Show(); + MessageSeverity.Error); return null; } @@ -778,9 +778,9 @@ namespace keepass2android // Create parent directory if (!parent.Mkdirs()) { - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, Resource.String.error_could_not_create_parent, - ToastLength.Long).Show(); + MessageSeverity.Error); return null; } @@ -794,18 +794,18 @@ namespace keepass2android } catch (Exception exWrite) { - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, GetString(Resource.String.SaveAttachment_Failed, new Java.Lang.Object[] {filename}) - + exWrite.Message, ToastLength.Long).Show(); + + exWrite.Message, MessageSeverity.Error); return null; } finally { MemUtil.ZeroByteArray(pbData); } - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, GetString(Resource.String.SaveAttachment_doneMessage, new Java.Lang.Object[] {filename}), - ToastLength.Short).Show(); + MessageSeverity.Info); return Uri.Parse("content://" + AttachmentContentProvider.Authority + "/" + filename); } @@ -838,7 +838,7 @@ namespace keepass2android catch (ActivityNotFoundException) { //ignore - Toast.MakeText(this, "Couldn't open file", ToastLength.Short).Show(); + App.Kp2a.ShowMessage(this, "Couldn't open file", MessageSeverity.Error); } } @@ -1558,7 +1558,7 @@ namespace keepass2android } catch (ActivityNotFoundException) { - Toast.MakeText(this, Resource.String.no_url_handler, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.no_url_handler, MessageSeverity.Error); } return true; } diff --git a/src/keepass2android-app/EntryEditActivity.cs b/src/keepass2android-app/EntryEditActivity.cs index d6337052..709c299b 100644 --- a/src/keepass2android-app/EntryEditActivity.cs +++ b/src/keepass2android-app/EntryEditActivity.cs @@ -64,10 +64,10 @@ namespace keepass2android { [Activity(Label = "@string/app_name", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden, Theme = "@style/Kp2aTheme_ActionBar")] public class EntryEditActivity : LockCloseActivity { - - - public const String KeyEntry = "entry"; + protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content); + + public const String KeyEntry = "entry"; public const String KeyParent = "parent"; public const String KeyTemplateUuid = "KeyTemplateUuid"; @@ -715,7 +715,7 @@ namespace keepass2android } catch(Exception exAttach) { - Toast.MakeText(this, GetString(Resource.String.AttachFailed)+" "+exAttach.Message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.AttachFailed)+" "+exAttach.Message, MessageSeverity.Error); } State.EntryModified = true; PopulateBinaries(); @@ -833,7 +833,7 @@ namespace keepass2android string s = Util.GetFilenameFromInternalFileChooser(data, this); if (s == null) { - Toast.MakeText(this, "No URI retrieved.", ToastLength.Short).Show(); + App.Kp2a.ShowMessage(this, "No URI retrieved.", MessageSeverity.Error); return; } uri = Uri.Parse(s); @@ -1139,7 +1139,7 @@ namespace keepass2android } else { - Toast.MakeText(this, "did not find target field", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "did not find target field", MessageSeverity.Error); } @@ -1158,7 +1158,8 @@ namespace keepass2android { if (GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this) != ConnectionResult.Success) { - Toast.MakeText(this, Resource.String.qr_scanning_error_no_google_play_services, ToastLength.Long); + App.Kp2a.ShowMessage(this, Resource.String.qr_scanning_error_no_google_play_services, + MessageSeverity.Error); return; } @@ -1178,7 +1179,7 @@ namespace keepass2android } else { - Toast.MakeText(this, "Scanned code should contain an otpauth:// text.", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "Scanned code should contain an otpauth:// text.", MessageSeverity.Warning); } })) .AddOnFailureListener(new FailureListener((e) => @@ -1503,7 +1504,7 @@ namespace keepass2android // Require title String title = Util.GetEditText(this, Resource.Id.entry_title); if ( title.Length == 0 ) { - Toast.MakeText(this, Resource.String.error_title_required, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_title_required, MessageSeverity.Error); return false; } @@ -1513,7 +1514,7 @@ namespace keepass2android DateTime newExpiry = new DateTime(); if ((State.Entry.Expires) && (!DateTime.TryParse( Util.GetEditText(this,Resource.Id.entry_expires), out newExpiry))) { - Toast.MakeText(this, Resource.String.error_invalid_expiry_date, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_invalid_expiry_date, MessageSeverity.Error); return false; } State.Entry.ExpiryTime = newExpiry.ToUniversalTime(); @@ -1527,13 +1528,13 @@ namespace keepass2android string key = keyView.Text; if (String.IsNullOrEmpty(key)) { - Toast.MakeText(this, Resource.String.error_string_key, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_string_key, MessageSeverity.Error); return false; } if (allKeys.Contains(key)) { - Toast.MakeText(this, GetString(Resource.String.error_string_duplicate_key, new Object[]{key}), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.error_string_duplicate_key, new Object[]{key}), MessageSeverity.Error); return false; } diff --git a/src/keepass2android-app/ExportDatabaseActivity.cs b/src/keepass2android-app/ExportDatabaseActivity.cs index 6193df0b..46898f33 100644 --- a/src/keepass2android-app/ExportDatabaseActivity.cs +++ b/src/keepass2android-app/ExportDatabaseActivity.cs @@ -29,9 +29,9 @@ namespace keepass2android var exportDb = new ExportDatabaseActivity.ExportDb(_activity, App.Kp2a, new ActionOnFinish(_activity, (success, message, activity) => { if (!success) - Toast.MakeText(activity, message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error); else - Toast.MakeText(activity, _activity.GetString(Resource.String.export_database_successful), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(activity, _activity.GetString(Resource.String.export_database_successful), MessageSeverity.Info); activity.Finish(); } ), _ffp, ioc); diff --git a/src/keepass2android-app/FileSaveProcessManager.cs b/src/keepass2android-app/FileSaveProcessManager.cs index 529d6811..802b1789 100644 --- a/src/keepass2android-app/FileSaveProcessManager.cs +++ b/src/keepass2android-app/FileSaveProcessManager.cs @@ -107,7 +107,7 @@ namespace keepass2android { if (!success) { - Toast.MakeText(activity, messageOrFilename, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(activity, messageOrFilename, MessageSeverity.Error); return; } SaveFile(new IOConnectionInfo { Path = FileSelectHelper.ConvertFilenameToIocPath(messageOrFilename) }); diff --git a/src/keepass2android-app/FileSelectHelper.cs b/src/keepass2android-app/FileSelectHelper.cs index 9e528808..db38d28f 100644 --- a/src/keepass2android-app/FileSelectHelper.cs +++ b/src/keepass2android-app/FileSelectHelper.cs @@ -115,6 +115,7 @@ namespace keepass2android string keyContent = keyContentTxt.Text; string toastMsg = null; + MessageSeverity severity = MessageSeverity.Info; if (!string.IsNullOrEmpty(keyName) && !string.IsNullOrEmpty(keyContent)) { try @@ -128,7 +129,9 @@ namespace keepass2android { toastMsg = ctx.GetString(Resource.String.private_key_save_failed, new Java.Lang.Object[] { e.Message }); - } + severity = MessageSeverity.Error; + + } } else { @@ -136,7 +139,7 @@ namespace keepass2android } if (toastMsg!= null) { - Toast.MakeText(_activity, toastMsg, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(_activity, toastMsg, severity); } UpdatePrivateKeyNames(keyNamesAdapter, fileStorage, ctx); @@ -153,7 +156,7 @@ namespace keepass2android int msgId = deleted ? Resource.String.private_key_delete : Resource.String.private_key_delete_failed; string msg = ctx.GetString(msgId, new Java.Lang.Object[] { keyName }); - Toast.MakeText(_activity, msg, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(_activity, msg, deleted ? MessageSeverity.Info :MessageSeverity.Error); UpdatePrivateKeyNames(keyNamesAdapter, fileStorage, ctx); keySpinner.SetSelection(SftpKeySpinnerCreateNewIdx); @@ -581,9 +584,9 @@ namespace keepass2android // Make sure file name exists if (filename.Length == 0) { - Toast.MakeText(_activity, + App.Kp2a.ShowMessage(_activity, Resource.String.error_filename_required, - ToastLength.Long).Show(); + MessageSeverity.Error); return false; } @@ -604,9 +607,9 @@ namespace keepass2android } catch (NoFileStorageFoundException) { - Toast.MakeText(_activity, + App.Kp2a.ShowMessage(_activity, "Unexpected scheme in "+filename, - ToastLength.Long).Show(); + MessageSeverity.Error); return false; } @@ -620,9 +623,9 @@ namespace keepass2android if (parent == null || (parent.Exists() && !parent.IsDirectory)) { - Toast.MakeText(_activity, + App.Kp2a.ShowMessage(_activity, Resource.String.error_invalid_path, - ToastLength.Long).Show(); + MessageSeverity.Error); return false; } @@ -631,9 +634,9 @@ namespace keepass2android // Create parent dircetory if (!parent.Mkdirs()) { - Toast.MakeText(_activity, + App.Kp2a.ShowMessage(_activity, Resource.String.error_could_not_create_parent, - ToastLength.Long).Show(); + MessageSeverity.Error); return false; } @@ -643,11 +646,11 @@ namespace keepass2android } catch (Java.IO.IOException ex) { - Toast.MakeText( + App.Kp2a.ShowMessage( _activity, _activity.GetText(Resource.String.error_file_not_create) + " " + ex.LocalizedMessage, - ToastLength.Long).Show(); + MessageSeverity.Error); return false; } @@ -700,7 +703,7 @@ namespace keepass2android _activity.StartActivityForResult(i, _requestCode); #else - Toast.MakeText(LocaleManager.LocalizedAppContext, "File chooser is excluded!", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(LocaleManager.LocalizedAppContext, "File chooser is excluded!", MessageSeverity.Error); #endif return true; } @@ -782,7 +785,7 @@ namespace keepass2android { if (!success) { - Toast.MakeText(newActivity, messageOrFilename, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(newActivity, messageOrFilename, MessageSeverity.Error); return; } var ioc = new IOConnectionInfo { Path = ConvertFilenameToIocPath(messageOrFilename) }; diff --git a/src/keepass2android-app/FingerprintSetupActivity.cs b/src/keepass2android-app/FingerprintSetupActivity.cs index b1b06413..f45fd5c2 100644 --- a/src/keepass2android-app/FingerprintSetupActivity.cs +++ b/src/keepass2android-app/FingerprintSetupActivity.cs @@ -251,7 +251,7 @@ namespace keepass2android catch (Exception e) { CheckCurrentRadioButton(); - Toast.MakeText(this, e.ToString(), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, e.ToString(), MessageSeverity.Error); FindViewById(Resource.Id.radio_buttons).Visibility = ViewStates.Visible; FindViewById(Resource.Id.fingerprint_auth_container).Visibility = ViewStates.Gone; } diff --git a/src/keepass2android-app/GeneratePasswordActivity.cs b/src/keepass2android-app/GeneratePasswordActivity.cs index ec1af73d..054fe80c 100644 --- a/src/keepass2android-app/GeneratePasswordActivity.cs +++ b/src/keepass2android-app/GeneratePasswordActivity.cs @@ -543,7 +543,7 @@ namespace keepass2android } catch (Exception e) { - Toast.MakeText(this, e.Message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, e.Message, MessageSeverity.Error); } return password; diff --git a/src/keepass2android-app/GroupBaseActivity.cs b/src/keepass2android-app/GroupBaseActivity.cs index 7525e610..8f43e58d 100644 --- a/src/keepass2android-app/GroupBaseActivity.cs +++ b/src/keepass2android-app/GroupBaseActivity.cs @@ -56,6 +56,8 @@ namespace keepass2android public const int RequestCodeActivateRealSearch = 12366; + protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content); + static readonly Dictionary bottomBarElementsPriority = new Dictionary() { { Resource.Id.cancel_insert_element, 20 }, @@ -927,7 +929,7 @@ namespace keepass2android { ((GroupBaseActivity)activity)?.StopMovingElements(); if (!String.IsNullOrEmpty(message)) - Toast.MakeText(activity, message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error); })); var progressTask = new ProgressTask(App.Kp2a, this, moveElement); progressTask.Run(); @@ -1328,7 +1330,7 @@ namespace keepass2android { Handler.Post(() => { - Toast.MakeText(ActiveActivity ?? LocaleManager.LocalizedAppContext, "Unrecoverable error: " + Message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(ActiveActivity ?? LocaleManager.LocalizedAppContext, "Unrecoverable error: " + Message, MessageSeverity.Error); }); App.Kp2a.Lock(false); diff --git a/src/keepass2android-app/GroupEditActivity.cs b/src/keepass2android-app/GroupEditActivity.cs index 92a8a4be..7bab9c03 100644 --- a/src/keepass2android-app/GroupEditActivity.cs +++ b/src/keepass2android-app/GroupEditActivity.cs @@ -111,9 +111,10 @@ namespace keepass2android SetResult (Result.Ok, intent); Finish (); - } else { - Toast.MakeText (this, Resource.String.error_no_name, ToastLength.Long).Show (); - } + } else + { + App.Kp2a.ShowMessage(this, Resource.String.error_no_name, MessageSeverity.Error); + } }; if (Intent.HasExtra(KeyGroupUuid)) diff --git a/src/keepass2android-app/KeeAutoExec.cs b/src/keepass2android-app/KeeAutoExec.cs index 257f4356..4f223e2a 100644 --- a/src/keepass2android-app/KeeAutoExec.cs +++ b/src/keepass2android-app/KeeAutoExec.cs @@ -316,7 +316,7 @@ namespace keepass2android try { ck.AddUserKey(new KcpKeyFile(strAbs)); } catch (InvalidOperationException) { - Toast.MakeText(LocaleManager.LocalizedAppContext,Resource.String.error_adding_keyfile,ToastLength.Long).Show(); + App.Kp2a.ShowMessage(LocaleManager.LocalizedAppContext,Resource.String.error_adding_keyfile, MessageSeverity.Error); return false; } catch (Exception) { throw; } diff --git a/src/keepass2android-app/LockingActivity.cs b/src/keepass2android-app/LockingActivity.cs index 2df074ed..1c9dd9d2 100644 --- a/src/keepass2android-app/LockingActivity.cs +++ b/src/keepass2android-app/LockingActivity.cs @@ -21,8 +21,10 @@ using Android.App; using Android.Content; using Android.Content.PM; using Android.Runtime; +using Android.Views; using Google.Android.Material.Dialog; using keepass2android; +using keepass2android.Utils; namespace keepass2android { @@ -76,19 +78,34 @@ namespace keepass2android base.OnPause(); TimeoutHelper.Pause(this); - } + App.Kp2a.MessagePresenter = new NonePresenter(); + } protected override void OnDestroy() { base.OnDestroy(); GC.Collect(); } - - protected override void OnResume() { - base.OnResume(); - - TimeoutHelper.Resume(this); - } + + protected override void OnResume() + { + base.OnResume(); + + TimeoutHelper.Resume(this); + var snackbarAnchorView = SnackbarAnchorView; + if (snackbarAnchorView != null) + { + App.Kp2a.MessagePresenter = new ChainedSnackbarPresenter(snackbarAnchorView); + } + else + { + App.Kp2a.MessagePresenter = new ToastPresenter(); + } + } + + + protected virtual View? SnackbarAnchorView => null; + public const int RequestCodeChallengeYubikey = 793; diff --git a/src/keepass2android-app/NfcOtpActivity.cs b/src/keepass2android-app/NfcOtpActivity.cs index ceafc5dd..d09d3db4 100644 --- a/src/keepass2android-app/NfcOtpActivity.cs +++ b/src/keepass2android-app/NfcOtpActivity.cs @@ -145,7 +145,7 @@ namespace keepass2android catch (Exception e) { Kp2aLog.LogUnexpectedError(e); - Toast.MakeText(this, "No Yubikey OTP found!", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "No Yubikey OTP found!", MessageSeverity.Error); Finish(); return; } diff --git a/src/keepass2android-app/PasswordActivity.cs b/src/keepass2android-app/PasswordActivity.cs index ae50b99a..68b2f7cf 100644 --- a/src/keepass2android-app/PasswordActivity.cs +++ b/src/keepass2android-app/PasswordActivity.cs @@ -66,6 +66,7 @@ using Exception = System.Exception; using String = System.String; using Toolbar = AndroidX.AppCompat.Widget.Toolbar; using AndroidX.Core.Content; +using Google.Android.Material.Snackbar; namespace keepass2android { @@ -309,7 +310,7 @@ namespace keepass2android catch (Exception e) { Kp2aLog.Log(e.ToString()); - Toast.MakeText(this, "Error: " + e.Message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "Error: " + e.Message, MessageSeverity.Error); return; } @@ -328,8 +329,7 @@ namespace keepass2android ChallengeInfo temp = _challengeProv.Encrypt(_challengeSecret); if (!temp.Save(_otpAuxIoc)) { - Toast.MakeText(this, Resource.String.ErrorUpdatingChalAuxFile, ToastLength.Long) - .Show(); + App.Kp2a.ShowMessage(this, Resource.String.ErrorUpdatingChalAuxFile, MessageSeverity.Error); return false; } @@ -348,7 +348,7 @@ namespace keepass2android } else { - Toast.MakeText(this, Resource.String.bad_resp, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.bad_resp, MessageSeverity.Error); } } } @@ -458,7 +458,7 @@ namespace keepass2android } else { - Toast.MakeText(Activity,GetErrorMessage(), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Activity,GetErrorMessage(), MessageSeverity.Error); } return; @@ -957,7 +957,7 @@ namespace keepass2android { btn.SetImageResource(Resource.Drawable.baseline_fingerprint_24); }, 1300); - Toast.MakeText(this, message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, message, MessageSeverity.Error); } public void OnBiometricAttemptFailed(string message) @@ -1036,7 +1036,7 @@ namespace keepass2android if (_appnameclickCount == 6) { Kp2aLog.LogUnexpectedError(new Exception("some blabla")); - Toast.MakeText(this, "Once again and the app will crash.", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "Once again and the app will crash.", MessageSeverity.Warning); } if (_appnameclickCount == 7) @@ -1123,7 +1123,7 @@ namespace keepass2android //For security reasons: discard the OTP (otherwise the user might not select a database now and forget //about the OTP, but it would still be stored in the Intents and later be passed to PasswordActivity again. - Toast.MakeText(this, GetString(Resource.String.otp_discarded_because_no_db), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.otp_discarded_because_no_db), MessageSeverity.Warning); GoToFileSelectActivity(); return false; } @@ -1400,7 +1400,7 @@ namespace keepass2android string errorMessage; if (!CreateCompositeKey(out compositeKey, out errorMessage)) return (() => { - Toast.MakeText(this, errorMessage, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, errorMessage, MessageSeverity.Warning); _performingLoad = false; }); return () => { PerformLoadDatabaseWithCompositeKey(compositeKey); }; @@ -1668,7 +1668,7 @@ namespace keepass2android //did we find a field? if (!foundEmptyField) { - Toast.MakeText(this, GetString(Resource.String.otp_discarded_no_space), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.otp_discarded_no_space), MessageSeverity.Error); } } @@ -1729,80 +1729,128 @@ namespace keepass2android UsedFingerprintUnlock = false; } + protected override View? SnackbarAnchorView => FindViewById(Resource.Id.main_content); + protected override void OnResume() - { - base.OnResume(); - _activityDesign.ReapplyTheme(); + { + base.OnResume(); + + _activityDesign.ReapplyTheme(); - Kp2aLog.Log("starting: " + _starting + ", Finishing: " + IsFinishing + ", _performingLoad: " + _performingLoad); + Kp2aLog.Log("starting: " + _starting + ", Finishing: " + IsFinishing + ", _performingLoad: " + + _performingLoad); - CheckBox cbOfflineMode = (CheckBox)FindViewById(Resource.Id.work_offline); - App.Kp2a.OfflineMode = cbOfflineMode.Checked = App.Kp2a.OfflineModePreference; //this won't overwrite new user settings because every change is directly saved in settings - LinearLayout offlineModeContainer = FindViewById(Resource.Id.work_offline_container); - var cachingFileStorage = App.Kp2a.GetFileStorage(_ioConnection) as CachingFileStorage; - if ((cachingFileStorage != null) && cachingFileStorage.IsCached(_ioConnection)) - { - offlineModeContainer.Visibility = ViewStates.Visible; - } - else - { - offlineModeContainer.Visibility = ViewStates.Gone; - App.Kp2a.OfflineMode = false; - } - + CheckBox cbOfflineMode = (CheckBox)FindViewById(Resource.Id.work_offline); + App.Kp2a.OfflineMode = + cbOfflineMode.Checked = + App.Kp2a + .OfflineModePreference; //this won't overwrite new user settings because every change is directly saved in settings + LinearLayout offlineModeContainer = FindViewById(Resource.Id.work_offline_container); + var cachingFileStorage = App.Kp2a.GetFileStorage(_ioConnection) as CachingFileStorage; + if ((cachingFileStorage != null) && cachingFileStorage.IsCached(_ioConnection)) + { + offlineModeContainer.Visibility = ViewStates.Visible; + } + else + { + offlineModeContainer.Visibility = ViewStates.Gone; + App.Kp2a.OfflineMode = false; + } - - View killButton = FindViewById(Resource.Id.kill_app); - if (PreferenceManager.GetDefaultSharedPreferences(this) - .GetBoolean(GetString(Resource.String.show_kill_app_key), false)) - { - killButton.Click += (sender, args) => - { - _killOnDestroy = true; + + + View killButton = FindViewById(Resource.Id.kill_app); + if (PreferenceManager.GetDefaultSharedPreferences(this) + .GetBoolean(GetString(Resource.String.show_kill_app_key), false)) + { + killButton.Click += (sender, args) => + { + _killOnDestroy = true; SetResult(Result.Canceled); - Finish(); + Finish(); - }; - killButton.Visibility = ViewStates.Visible; + }; + killButton.Visibility = ViewStates.Visible; - } - else - { - killButton.Visibility = ViewStates.Gone; - } + } + else + { + killButton.Visibility = ViewStates.Gone; + } - TryGetOtpFromClipboard(); + TryGetOtpFromClipboard(); - if (!_keepPasswordInOnResume) - { - if ( - _lastOnPauseTime < DateTime.Now - TimeSpan.FromSeconds(5) //only clear when user left the app for more than 5 seconds (allows to use Yubiclip, also allows to switch shortly to another app) - && - PreferenceManager.GetDefaultSharedPreferences(this) - .GetBoolean(GetString(Resource.String.ClearPasswordOnLeave_key), true)) - { - ClearEnteredPassword(); - } + if (!_keepPasswordInOnResume) + { + if ( + _lastOnPauseTime < + DateTime.Now - + TimeSpan.FromSeconds( + 5) //only clear when user left the app for more than 5 seconds (allows to use Yubiclip, also allows to switch shortly to another app) + && + PreferenceManager.GetDefaultSharedPreferences(this) + .GetBoolean(GetString(Resource.String.ClearPasswordOnLeave_key), true)) + { + ClearEnteredPassword(); + } - } + } - _keepPasswordInOnResume = false; + _keepPasswordInOnResume = false; - MakePasswordMaskedOrVisible(); + MakePasswordMaskedOrVisible(); - UpdateOkButtonState(); + UpdateOkButtonState(); - if (KeyProviderTypes.Contains(KeyProviders.Challenge)) - { - FindViewById(Resource.Id.otpInitView).Visibility = _challengeSecret == null ? ViewStates.Visible : ViewStates.Gone; - } + if (KeyProviderTypes.Contains(KeyProviders.Challenge)) + { + FindViewById(Resource.Id.otpInitView).Visibility = + _challengeSecret == null ? ViewStates.Visible : ViewStates.Gone; + } + /* + Snackbar snackbar = Snackbar + .Make(FindViewById(Resource.Id.main_content), + "snack snack snack snack snack snack snack snack snack snack snack snack snack snack snacksnack snack snacksnack snack snacksnack snack snack snack snack snack snack snack snack snack snack snack snack snack snack snacksnack snack snacksnack snack snacksnack snack snack snack snack snacksnack snack snack ", + Snackbar.LengthLong); + snackbar.SetTextMaxLines(5); + snackbar.SetBackgroundTint(GetColor(Resource.Color.md_theme_secondaryContainer)); + snackbar.SetTextColor(GetColor(Resource.Color.md_theme_onSecondaryContainer)); + snackbar.SetAction("dismiss", + view => snackbar.SetBackgroundTint(GetColor(Resource.Color.md_theme_surfaceContainer))); - //use !IsFinishing to make sure we're not starting another activity when we're already finishing (e.g. due to TaskComplete in OnActivityResult) - //use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!) - if ( !IsFinishing && !_performingLoad) + snackbar.Show(); + + new Handler().PostDelayed(() => + { + + Snackbar snackbar2 = Snackbar + .Make(FindViewById(Resource.Id.main_content), "snack snack snack ", + Snackbar.LengthLong); + snackbar2.SetTextMaxLines(5); + snackbar2.SetBackgroundTint(GetColor(Resource.Color.md_theme_errorContainer)); + snackbar2.SetTextColor(GetColor(Resource.Color.md_theme_onErrorContainer)); + snackbar2.Show(); + }, 1500); + + + new Handler().PostDelayed(() => + { + + Snackbar snackbar2 = Snackbar + .Make(FindViewById(Resource.Id.main_content), "snack snack warn ", + Snackbar.LengthLong); + snackbar2.SetTextMaxLines(5); + snackbar2.SetBackgroundTint(GetColor(Resource.Color.md_theme_inverseSurface)); + snackbar2.SetTextColor(GetColor(Resource.Color.md_theme_inverseOnSurface)); + snackbar2.Show(); + }, 2500);*/ + + //use !IsFinishing to make sure we're not starting another activity when we're already finishing (e.g. due to TaskComplete in OnActivityResult) + //use !performingLoad to make sure we're not already loading the database (after ActivityResult from File-Prepare-Activity; this would cause _loadDbFileTask to exist when we reload later!) + if ( !IsFinishing && !_performingLoad) { @@ -1954,7 +2002,7 @@ namespace keepass2android btn.Tag = error; - Toast.MakeText(this, Resource.String.fingerprint_reenable2, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.fingerprint_reenable2, MessageSeverity.Error); _biometricDec = null; return false; @@ -2024,7 +2072,7 @@ namespace keepass2android /* private void errorMessage(CharSequence text) { - Toast.MakeText(this, text, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, text, MessageSeverity.Error); } */ @@ -2084,7 +2132,9 @@ namespace keepass2android _act.LoadingErrorCount++; } - if ((Exception != null) && (Exception.Message == KeePassLib.Resources.KLRes.FileCorrupted)) + + + if ((Exception != null) && (Exception.Message == KeePassLib.Resources.KLRes.FileCorrupted)) { Message = _act.GetString(Resource.String.CorruptDatabaseHelp); } @@ -2150,7 +2200,8 @@ namespace keepass2android } else { - DisplayMessage(_act); + MessageSeverity severity = Success ? MessageSeverity.Info : MessageSeverity.Error; + App.Kp2a.ShowMessage(_act, Message, severity); if (Success) { _act.LaunchNextActivity(); @@ -2234,7 +2285,7 @@ namespace keepass2android private void ShowError(string message) { - App.Kp2a.ShowToast(message); + App.Kp2a.ShowToast(message, MessageSeverity.Error); } } private class PasswordActivityBroadcastReceiver : BroadcastReceiver diff --git a/src/keepass2android-app/QueryCredentialsActivity.cs b/src/keepass2android-app/QueryCredentialsActivity.cs index 43948a4e..6c86e965 100644 --- a/src/keepass2android-app/QueryCredentialsActivity.cs +++ b/src/keepass2android-app/QueryCredentialsActivity.cs @@ -128,11 +128,11 @@ namespace keepass2android Kp2aLog.LogUnexpectedError(e); } if (String.IsNullOrEmpty(_requestedUrl)) - Toast.MakeText(this, GetString(Resource.String.query_credentials, new Java.Lang.Object[] {pluginDisplayName}), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.query_credentials, new Java.Lang.Object[] {pluginDisplayName}), MessageSeverity.Info); else - Toast.MakeText(this, + App.Kp2a.ShowMessage(this, GetString(Resource.String.query_credentials_for_url, - new Java.Lang.Object[] { pluginDisplayName, _requestedUrl }), ToastLength.Long).Show(); ; + new Java.Lang.Object[] { pluginDisplayName, _requestedUrl }), MessageSeverity.Info); ; } private void StartQuery() diff --git a/src/keepass2android-app/QuickUnlock.cs b/src/keepass2android-app/QuickUnlock.cs index 71cea014..4dd2176a 100644 --- a/src/keepass2android-app/QuickUnlock.cs +++ b/src/keepass2android-app/QuickUnlock.cs @@ -35,6 +35,7 @@ using KeePassLib; using KeePassLib.Serialization; using Toolbar = AndroidX.AppCompat.Widget.Toolbar; using AndroidX.Core.Content; +using keepass2android.Utils; namespace keepass2android { @@ -203,7 +204,7 @@ namespace keepass2android btn.SetImageResource(Resource.Drawable.baseline_fingerprint_24); }, 1300); - Toast.MakeText(this, message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, message, MessageSeverity.Error); } @@ -325,7 +326,7 @@ namespace keepass2android { Kp2aLog.Log("QuickUnlock not successful!"); App.Kp2a.Lock(false); - Toast.MakeText(this, GetString(Resource.String.QuickUnlock_fail), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.QuickUnlock_fail), MessageSeverity.Error); Finish(); } @@ -383,8 +384,9 @@ namespace keepass2android { base.OnResume(); _design.ReapplyTheme(); - - CheckIfUnloaded(); + App.Kp2a.MessagePresenter = new ChainedSnackbarPresenter(FindViewById(Resource.Id.main_content)); + + CheckIfUnloaded(); InitFingerprintUnlock(); @@ -449,7 +451,8 @@ namespace keepass2android protected override void OnPause() { - if (_biometryIdentifier != null) + App.Kp2a.MessagePresenter = new NonePresenter(); + if (_biometryIdentifier != null) { Kp2aLog.Log("FP: Stop listening"); _biometryIdentifier.StopListening(); diff --git a/src/keepass2android-app/Resources/layout/entry_edit.xml b/src/keepass2android-app/Resources/layout/entry_edit.xml index 02a0066b..2f8ba8ee 100644 --- a/src/keepass2android-app/Resources/layout/entry_edit.xml +++ b/src/keepass2android-app/Resources/layout/entry_edit.xml @@ -1,5 +1,11 @@ - + + - \ No newline at end of file + + \ No newline at end of file diff --git a/src/keepass2android-app/SelectCurrentDbActivity.cs b/src/keepass2android-app/SelectCurrentDbActivity.cs index 0430dc8b..6be80475 100644 --- a/src/keepass2android-app/SelectCurrentDbActivity.cs +++ b/src/keepass2android-app/SelectCurrentDbActivity.cs @@ -392,7 +392,7 @@ namespace keepass2android if (ioc.Path.Length == 0) { // No file name - Toast.MakeText(this, Resource.String.FileNotFound, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.FileNotFound, MessageSeverity.Error); return false; } @@ -400,7 +400,7 @@ namespace keepass2android if (!dbFile.Exists()) { // File does not exist - Toast.MakeText(this, Resource.String.FileNotFound, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.FileNotFound, MessageSeverity.Error); return false; } } @@ -408,7 +408,7 @@ namespace keepass2android { if (!ioc.Path.StartsWith("content://")) { - Toast.MakeText(this, Resource.String.error_can_not_handle_uri, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resource.String.error_can_not_handle_uri, MessageSeverity.Error); return false; } IoUtil.TryTakePersistablePermissions(this.ContentResolver, intent.Data); @@ -468,7 +468,7 @@ namespace keepass2android } catch (Exception e) { - Toast.MakeText(this, "Failed to open child databases",ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "Failed to open child databases", MessageSeverity.Error); Kp2aLog.LogUnexpectedError(e); } diff --git a/src/keepass2android-app/SelectStorageLocationActivity.cs b/src/keepass2android-app/SelectStorageLocationActivity.cs index a7b6d122..ecfa3005 100644 --- a/src/keepass2android-app/SelectStorageLocationActivity.cs +++ b/src/keepass2android-app/SelectStorageLocationActivity.cs @@ -70,15 +70,15 @@ namespace keepass2android protected Bundle State { get; set; } - protected override void ShowToast(string text) + protected override void ShowErrorToast(string text) { - Toast.MakeText(this, text, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, text, MessageSeverity.Error); } protected override void ShowInvalidSchemeMessage(string dataString) { - Toast.MakeText(this, Resources.GetString(Resource.String.unknown_uri_scheme, new Java.Lang.Object[] { dataString }), - ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, Resources.GetString(Resource.String.unknown_uri_scheme, new Java.Lang.Object[] { dataString }), + MessageSeverity.Error); } protected override string IntentToFilename(Intent data) @@ -194,7 +194,7 @@ namespace keepass2android StartActivityForResult(intent, requestCode); #else - Toast.MakeText(this, "File chooser is excluded!", ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, "File chooser is excluded!", MessageSeverity.Error); #endif } diff --git a/src/keepass2android-app/SetPasswordDialog.cs b/src/keepass2android-app/SetPasswordDialog.cs index cf581570..61c410f8 100644 --- a/src/keepass2android-app/SetPasswordDialog.cs +++ b/src/keepass2android-app/SetPasswordDialog.cs @@ -57,7 +57,7 @@ namespace keepass2android // Verify that passwords match if ( ! pass.Equals(confpass) ) { // Passwords do not match - Toast.MakeText(Context, Resource.String.error_pass_match, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.error_pass_match, MessageSeverity.Error); return; } @@ -67,7 +67,7 @@ namespace keepass2android // Verify that a password or keyfile is set if ( pass.Length == 0 && keyfile.Length == 0 ) { - Toast.MakeText(Context, Resource.String.error_nopass, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(Context, Resource.String.error_nopass, MessageSeverity.Error); return; } @@ -114,7 +114,7 @@ namespace keepass2android edit.PutString(App.Kp2a.CurrentDb.CurrentFingerprintModePrefKey, FingerprintUnlockMode.Disabled.ToString()); edit.Commit(); - Toast.MakeText(_dlg.Context, Resource.String.fingerprint_reenable, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(_dlg.Context, Resource.String.fingerprint_reenable, MessageSeverity.Warning); _dlg.Context.StartActivity(typeof(BiometricSetupActivity)); } diff --git a/src/keepass2android-app/ShareUrlResults.cs b/src/keepass2android-app/ShareUrlResults.cs index 0eb4e09b..ff3d6887 100644 --- a/src/keepass2android-app/ShareUrlResults.cs +++ b/src/keepass2android-app/ShareUrlResults.cs @@ -121,7 +121,7 @@ namespace keepass2android } catch (Exception e) { - Toast.MakeText(this, e.Message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, e.Message, MessageSeverity.Error); SetResult(Result.Canceled); Finish(); return; @@ -184,7 +184,7 @@ namespace keepass2android createUrlEntry.Click += (sender, e) => { GroupActivity.Launch(this, new CreateEntryThenCloseTask { Url = searchUrl, ShowUserNotifications = (AppTask as SelectEntryTask)?.ShowUserNotifications ?? ActivationCondition.Always }, new ActivityLaunchModeRequestCode(0)); - Toast.MakeText(this, GetString(Resource.String.select_group_then_add, new Java.Lang.Object[] { GetString(Resource.String.add_entry) }), ToastLength.Long).Show(); + App.Kp2a.ShowMessage(this, GetString(Resource.String.select_group_then_add, new Java.Lang.Object[] { GetString(Resource.String.add_entry) }), MessageSeverity.Info); }; } else diff --git a/src/keepass2android-app/SyncUtil.cs b/src/keepass2android-app/SyncUtil.cs index 19ba57e4..16701ea3 100644 --- a/src/keepass2android-app/SyncUtil.cs +++ b/src/keepass2android-app/SyncUtil.cs @@ -56,7 +56,7 @@ namespace keepass2android OnFinish onFinish = new ActionOnFinish(_activity, (success, message, activity) => { if (!String.IsNullOrEmpty(message)) - Toast.MakeText(activity, message, ToastLength.Long).Show(); + App.Kp2a.ShowMessage(activity, message, MessageSeverity.Error); // Tell the adapter to refresh it's list BaseAdapter adapter = (activity as GroupBaseActivity)?.ListAdapter; diff --git a/src/keepass2android-app/Totp/TrayTotpPluginAdapter.cs b/src/keepass2android-app/Totp/TrayTotpPluginAdapter.cs index 4f1a2e36..c4b343cf 100644 --- a/src/keepass2android-app/Totp/TrayTotpPluginAdapter.cs +++ b/src/keepass2android-app/Totp/TrayTotpPluginAdapter.cs @@ -161,7 +161,7 @@ namespace PluginTOTP return; try { - _uiThreadHandler.Post(() => Toast.MakeText(_ctx, warning, ToastLength.Short).Show()); + _uiThreadHandler.Post(() => App.Kp2a.ShowMessage(_ctx, warning, MessageSeverity.Warning)); } catch (Exception e) { diff --git a/src/keepass2android-app/Utils/MessagePresenter.cs b/src/keepass2android-app/Utils/MessagePresenter.cs new file mode 100644 index 00000000..0ad025b6 --- /dev/null +++ b/src/keepass2android-app/Utils/MessagePresenter.cs @@ -0,0 +1,153 @@ +using Android.OS; +using Android.Views; +using Google.Android.Material.Snackbar; + +namespace keepass2android.Utils +{ + public struct Message + { + public Message() + { + Text = null; + Severity = MessageSeverity.Info; + } + + public string Text { get; set; } + public MessageSeverity Severity { get; set; } + public bool ShowOnSubsequentScreens { get; set; } = true; + } + public interface IMessagePresenter + { + void ShowMessage(Message message); + + List PendingMessages + { + get; + } + + } + + internal class NonePresenter : IMessagePresenter + { + public void ShowMessage(Message message) + { + PendingMessages.Add(message); + } + + public List PendingMessages + { + get; + set; + } = new List(); + } + + + internal class ToastPresenter : IMessagePresenter + { + public void ShowMessage(Message message) + { + Toast.MakeText(App.Context, message.Text, ToastLength.Long).Show(); + } + + public List PendingMessages => new(); + } + + internal class ChainedSnackbarPresenter: IMessagePresenter + { + internal ChainedSnackbarPresenter(View anchorView) + { + this.AnchorView = anchorView; + + } + + private DateTime nextSnackbarShowTime = DateTime.Now; + private List queuedMessages = new List(); + + public View AnchorView { get; set; } + + private TimeSpan chainingTime = TimeSpan.FromSeconds(1.5); + private Snackbar snackbar; + private Message lastMessage; + + public void ShowMessage(Message message) + { + if (DateTime.Now < nextSnackbarShowTime) + { + var waitDuration = nextSnackbarShowTime - DateTime.Now; + nextSnackbarShowTime = nextSnackbarShowTime.Add(chainingTime); + + new Handler().PostDelayed(() => { ShowNextSnackbar(); }, (long)waitDuration.TotalMilliseconds); + if (queuedMessages.Any()) + { + queuedMessages.Add(message); + } + + return; + } + ShowSnackbarNow(message); + nextSnackbarShowTime = DateTime.Now.Add(chainingTime); + + } + + public List PendingMessages + { + get + { + List pendingMessages = new List(); + if (snackbar?.IsShown == true) + { + pendingMessages.Add(lastMessage); + } + + pendingMessages.AddRange(queuedMessages); + return pendingMessages; + } + } + + private void ShowNextSnackbar() + { + if (!queuedMessages.Any()) + { + return; + } + + ShowSnackbarNow(queuedMessages.First()); + queuedMessages.RemoveAt(0); + + if (!queuedMessages.Any()) + { + new Handler().PostDelayed(() => { ShowNextSnackbar(); }, (long)chainingTime.TotalMilliseconds); + } + } + + private void ShowSnackbarNow(Message message) + { + snackbar = Snackbar + .Make(AnchorView, message.Text, + Snackbar.LengthLong); + snackbar.SetTextMaxLines(10); + if ((int)Build.VERSION.SdkInt >= 23) + { + if (message.Severity == MessageSeverity.Error) + { + snackbar.SetBackgroundTint(App.Context.GetColor(Resource.Color.md_theme_errorContainer)); + snackbar.SetTextColor(App.Context.GetColor(Resource.Color.md_theme_onErrorContainer)); + } + else if (message.Severity == MessageSeverity.Warning) + { + snackbar.SetBackgroundTint(App.Context.GetColor(Resource.Color.md_theme_inverseSurface)); + snackbar.SetTextColor(App.Context.GetColor(Resource.Color.md_theme_inverseOnSurface)); + } + else + { + snackbar.SetBackgroundTint(App.Context.GetColor(Resource.Color.md_theme_secondaryContainer)); + snackbar.SetTextColor(App.Context.GetColor(Resource.Color.md_theme_onSecondaryContainer)); + } + } + + snackbar.Show(); + lastMessage = message; + + } + } +} diff --git a/src/keepass2android-app/Utils/Util.cs b/src/keepass2android-app/Utils/Util.cs index 67389100..a9bf3d8b 100644 --- a/src/keepass2android-app/Utils/Util.cs +++ b/src/keepass2android-app/Utils/Util.cs @@ -172,289 +172,311 @@ namespace keepass2android } - public class Util { - - - public const String KeyFilename = "fileName"; - public const String KeyServerusername = "serverCredUser"; - public const String KeyServerpassword = "serverCredPwd"; - public const String KeyServercredmode = "serverCredRememberMode"; + public class Util + { - public static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i, string prefix="") - { - i.PutExtra(prefix+KeyFilename, ioc.Path); - i.PutExtra(prefix + KeyServerusername, ioc.UserName); - i.PutExtra(prefix + KeyServerpassword, ioc.Password); - i.PutExtra(prefix + KeyServercredmode, (int)ioc.CredSaveMode); - } + public const String KeyFilename = "fileName"; + public const String KeyServerusername = "serverCredUser"; + public const String KeyServerpassword = "serverCredPwd"; + public const String KeyServercredmode = "serverCredRememberMode"; - public static void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent i, string prefix="") - { - ioc.Path = i.GetStringExtra(prefix + KeyFilename); - ioc.UserName = i.GetStringExtra(prefix + KeyServerusername) ?? ""; - ioc.Password = i.GetStringExtra(prefix + KeyServerpassword) ?? ""; - ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(prefix + KeyServercredmode, (int)IOCredSaveMode.NoSave); - } + + public static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i, string prefix = "") + { + i.PutExtra(prefix + KeyFilename, ioc.Path); + i.PutExtra(prefix + KeyServerusername, ioc.UserName); + i.PutExtra(prefix + KeyServerpassword, ioc.Password); + i.PutExtra(prefix + KeyServercredmode, (int)ioc.CredSaveMode); + } + + public static void SetIoConnectionFromIntent(IOConnectionInfo ioc, Intent i, string prefix = "") + { + ioc.Path = i.GetStringExtra(prefix + KeyFilename); + ioc.UserName = i.GetStringExtra(prefix + KeyServerusername) ?? ""; + ioc.Password = i.GetStringExtra(prefix + KeyServerpassword) ?? ""; + ioc.CredSaveMode = (IOCredSaveMode)i.GetIntExtra(prefix + KeyServercredmode, (int)IOCredSaveMode.NoSave); + } public static Bitmap DrawableToBitmap(Drawable drawable) - { - Bitmap bitmap = null; + { + Bitmap bitmap = null; - if (drawable is BitmapDrawable) - { - BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable; - if (bitmapDrawable.Bitmap != null) - { - return bitmapDrawable.Bitmap; - } - } + if (drawable is BitmapDrawable) + { + BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable; + if (bitmapDrawable.Bitmap != null) + { + return bitmapDrawable.Bitmap; + } + } - if (drawable.IntrinsicWidth <= 0 || drawable.IntrinsicHeight <= 0) - { - bitmap = Bitmap.CreateBitmap(1, 1, Bitmap.Config.Argb8888); // Single color bitmap will be created of 1x1 pixel - } - else - { - bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth, drawable.IntrinsicHeight, Bitmap.Config.Argb8888); - } + if (drawable.IntrinsicWidth <= 0 || drawable.IntrinsicHeight <= 0) + { + bitmap = Bitmap.CreateBitmap(1, 1, + Bitmap.Config.Argb8888); // Single color bitmap will be created of 1x1 pixel + } + else + { + bitmap = Bitmap.CreateBitmap(drawable.IntrinsicWidth, drawable.IntrinsicHeight, Bitmap.Config.Argb8888); + } - Canvas canvas = new Canvas(bitmap); - drawable.SetBounds(0, 0, canvas.Width, canvas.Height); + Canvas canvas = new Canvas(bitmap); + drawable.SetBounds(0, 0, canvas.Width, canvas.Height); drawable.Draw(canvas); - + return bitmap; - } + } - public static Bitmap ChangeImageColor(Bitmap sourceBitmap, Color color) - { - Bitmap temp = Bitmap.CreateBitmap(sourceBitmap, 0, 0, - sourceBitmap.Width, sourceBitmap.Height); - Bitmap resultBitmap = temp.Copy(Bitmap.Config.Argb8888, true); + public static Bitmap ChangeImageColor(Bitmap sourceBitmap, Color color) + { + Bitmap temp = Bitmap.CreateBitmap(sourceBitmap, 0, 0, + sourceBitmap.Width, sourceBitmap.Height); + Bitmap resultBitmap = temp.Copy(Bitmap.Config.Argb8888, true); Paint p = new Paint(); - ColorFilter filter = new LightingColorFilter(color.ToArgb(), 0); - p.SetColorFilter(filter); + ColorFilter filter = new LightingColorFilter(color.ToArgb(), 0); + p.SetColorFilter(filter); - Canvas canvas = new Canvas(resultBitmap); - canvas.DrawBitmap(resultBitmap, 0, 0, p); - return resultBitmap; - } + Canvas canvas = new Canvas(resultBitmap); + canvas.DrawBitmap(resultBitmap, 0, 0, p); + return resultBitmap; + } public static float convertDpToPixel(float dp, Context context) - { - Resources resources = context.Resources; - DisplayMetrics metrics = resources.DisplayMetrics; - float px = dp * metrics.Density; - return px; - } - public static String GetClipboard(Context context) { - Android.Content.ClipboardManager clipboardManager = (ClipboardManager)context.GetSystemService(Context.ClipboardService); + Resources resources = context.Resources; + DisplayMetrics metrics = resources.DisplayMetrics; + float px = dp * metrics.Density; + return px; + } + + public static String GetClipboard(Context context) + { + Android.Content.ClipboardManager clipboardManager = + (ClipboardManager)context.GetSystemService(Context.ClipboardService); var clip = clipboardManager.PrimaryClip; if (clip != null && clip.ItemCount > 0) { return clip.GetItemAt(0).CoerceToText(context); } + return ""; } - - public static void CopyToClipboard(Context context, String text, bool isProtected) { - Android.Content.ClipboardManager clipboardManager = (ClipboardManager)context.GetSystemService(Context.ClipboardService); - ClipData clipData = Android.Content.ClipData.NewPlainText("KP2A", text); - if (isProtected) - { - //ClipDescription.Extras is only available since 24 - if ((int) Build.VERSION.SdkInt >= 24) - { - var extras = clipData.Description.Extras ?? new Android.OS.PersistableBundle(); - extras.PutBoolean("android.content.extra.IS_SENSITIVE", true); - clipData.Description.Extras = extras; - } - } - clipboardManager.PrimaryClip = clipData; - if (text == "") - { - //on some devices, adding empty text does not seem to work. Try again with some garbage. - clipData = Android.Content.ClipData.NewPlainText("KP2A", "***"); - clipboardManager.PrimaryClip = clipData; - //seems to work better on some devices: - try - { - clipboardManager.Text = text; - } - catch (Exception exception) - { - Kp2aLog.LogUnexpectedError(exception); - } - + public static void CopyToClipboard(Context context, String text, bool isProtected) + { + Android.Content.ClipboardManager clipboardManager = + (ClipboardManager)context.GetSystemService(Context.ClipboardService); + ClipData clipData = Android.Content.ClipData.NewPlainText("KP2A", text); + if (isProtected) + { + //ClipDescription.Extras is only available since 24 + if ((int)Build.VERSION.SdkInt >= 24) + { + var extras = clipData.Description.Extras ?? new Android.OS.PersistableBundle(); + extras.PutBoolean("android.content.extra.IS_SENSITIVE", true); + clipData.Description.Extras = extras; + } + } + + clipboardManager.PrimaryClip = clipData; + if (text == "") + { + //on some devices, adding empty text does not seem to work. Try again with some garbage. + clipData = Android.Content.ClipData.NewPlainText("KP2A", "***"); + clipboardManager.PrimaryClip = clipData; + //seems to work better on some devices: + try + { + clipboardManager.Text = text; + } + catch (Exception exception) + { + Kp2aLog.LogUnexpectedError(exception); + + } + } } - private static readonly Regex ARC_DEVICE_PATTERN = new Regex(".+_cheets|cheets_.+"); + private static readonly Regex ARC_DEVICE_PATTERN = new Regex(".+_cheets|cheets_.+"); - public static bool IsChromeOS(Context context) - { - return - context.PackageManager.HasSystemFeature( - "org.chromium.arc.device_management") // https://stackoverflow.com/a/39843396/292233 - || (Build.Device != null && ARC_DEVICE_PATTERN.IsMatch(Build.Device)) + public static bool IsChromeOS(Context context) + { + return + context.PackageManager.HasSystemFeature( + "org.chromium.arc.device_management") // https://stackoverflow.com/a/39843396/292233 + || (Build.Device != null && ARC_DEVICE_PATTERN.IsMatch(Build.Device)) ; - } + } - public static void GotoUrl(Context context, String url) { - if ( !string.IsNullOrEmpty(url) ) { + public static void GotoUrl(Context context, String url) + { + if (!string.IsNullOrEmpty(url)) + { - if (url.StartsWith("androidapp://")) - { - string packageName = url.Substring("androidapp://".Length); - Intent startKp2aIntent = context.PackageManager.GetLaunchIntentForPackage(packageName); - if (startKp2aIntent != null) - { - startKp2aIntent.AddCategory(Intent.CategoryLauncher); - startKp2aIntent.AddFlags(ActivityFlags.NewTask); - context.StartActivity(startKp2aIntent); - } - } - else - { - Uri uri = Uri.Parse(url); - context.StartActivity(new Intent( - url.StartsWith("tel:") ? Intent.ActionDial : Intent.ActionView, - uri)); - } - } - } - - public static void GotoUrl(Context context, int resId) { - GotoUrl(context, context.GetString(resId)); - } + if (url.StartsWith("androidapp://")) + { + string packageName = url.Substring("androidapp://".Length); + Intent startKp2aIntent = context.PackageManager.GetLaunchIntentForPackage(packageName); + if (startKp2aIntent != null) + { + startKp2aIntent.AddCategory(Intent.CategoryLauncher); + startKp2aIntent.AddFlags(ActivityFlags.NewTask); + context.StartActivity(startKp2aIntent); + } + } + else + { + Uri uri = Uri.Parse(url); + context.StartActivity(new Intent( + url.StartsWith("tel:") ? Intent.ActionDial : Intent.ActionView, + uri)); + } + } + } - public static void GotoMarket(Context context) - { - GotoUrl(context, context.GetString(Resource.String.MarketURL)+context.PackageName); - } + public static void GotoUrl(Context context, int resId) + { + GotoUrl(context, context.GetString(resId)); + } - public static bool GotoDonateUrl(Context context) - { - string donateUrl = context.GetString(Resource.String.donate_url, - new Java.Lang.Object[]{context.Resources.Configuration.Locale.Language, - context.PackageName - }); - try - { - GotoUrl(context, donateUrl); - return true; - } - catch (ActivityNotFoundException) - { - Toast.MakeText(context, Resource.String.error_failed_to_launch_link, ToastLength.Long).Show(); - return false; - } - - } - - public static String GetEditText(Activity act, int resId) { - TextView te = (TextView) act.FindViewById(resId); - System.Diagnostics.Debug.Assert(te != null); - - if (te != null) { - return te.Text; - } else { - return ""; - } - } - - public static void SetEditText(Activity act, int resId, String str) { - TextView te = (TextView) act.FindViewById(resId); - System.Diagnostics.Debug.Assert(te != null); - - if (te != null) { - te.Text = str; - } - } + public static void GotoMarket(Context context) + { + GotoUrl(context, context.GetString(Resource.String.MarketURL) + context.PackageName); + } - /** - * Indicates whether the specified action can be used as an intent. This - * method queries the package manager for installed packages that can - * respond to an intent with the specified action. If no suitable package is - * found, this method returns false. - * - * @param context The application's environment. - * @param action The Intent action to check for availability. - * - * @return True if an Intent with the specified action can be sent and - * responded to, false otherwise. - */ - static bool IsIntentAvailable(Context context, String action, String type, List categories ) - { - PackageManager packageManager = context.PackageManager; - Intent intent = new Intent(action); - if (type != null) - intent.SetType(type); - if (categories != null) - categories.ForEach(c => intent.AddCategory(c)); - IList list = - packageManager.QueryIntentActivities(intent, - PackageInfoFlags.MatchDefaultOnly); - foreach (ResolveInfo i in list) - Kp2aLog.Log(i.ActivityInfo.ApplicationInfo.PackageName); - return list.Count > 0; - } + public static bool GotoDonateUrl(Context context) + { + string donateUrl = context.GetString(Resource.String.donate_url, + new Java.Lang.Object[] + { + context.Resources.Configuration.Locale.Language, + context.PackageName + }); + try + { + GotoUrl(context, donateUrl); + return true; + } + catch (ActivityNotFoundException) + { + App.Kp2a.ShowMessage(context, Resource.String.error_failed_to_launch_link, MessageSeverity.Error); + return false; + } - /// - /// Opens a browse dialog for selecting a file. - /// - /// context activity - /// requestCode for onActivityResult - /// if true, the file location is meant for saving - /// if true, the caller prefers a location that can be used permanently - /// This means that ActionOpenDocument should be used instead of ActionGetContent (for not saving), as ActionGetContent - /// is more for one-time access, but therefore allows possibly more available sources. - public static void ShowBrowseDialog(Activity activity, int requestCodeBrowse, bool forSaving, bool tryGetPermanentAccess) - { - //even though GetContent is not well supported (since Android 7, see https://commonsware.com/Android/previews/appendix-b-android-70) - //we still offer it. - var loadAction = (tryGetPermanentAccess && IsKitKatOrLater) ? - Intent.ActionOpenDocument : Intent.ActionGetContent; - if ((!forSaving) && (IsIntentAvailable(activity, loadAction, "*/*", new List { Intent.CategoryOpenable}))) - { - Intent i = new Intent(loadAction); - i.SetType("*/*"); - i.AddCategory(Intent.CategoryOpenable); + } - activity.StartActivityForResult(i, requestCodeBrowse); - } - else - { - if ((forSaving) && (IsKitKatOrLater)) - { - Intent i = new Intent(Intent.ActionCreateDocument); - i.SetType("*/*"); - i.AddCategory(Intent.CategoryOpenable); + public static String GetEditText(Activity act, int resId) + { + TextView te = (TextView)act.FindViewById(resId); + System.Diagnostics.Debug.Assert(te != null); - activity.StartActivityForResult(i, requestCodeBrowse); - } - else - { - string defaultPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath; + if (te != null) + { + return te.Text; + } + else + { + return ""; + } + } - ShowInternalLocalFileChooser(activity, requestCodeBrowse, forSaving, defaultPath); - } - - } - } + public static void SetEditText(Activity act, int resId, String str) + { + TextView te = (TextView)act.FindViewById(resId); + System.Diagnostics.Debug.Assert(te != null); - public static bool IsKitKatOrLater - { - get { return (int)Build.VERSION.SdkInt >= 19; } - } + if (te != null) + { + te.Text = str; + } + } + + /** + * Indicates whether the specified action can be used as an intent. This + * method queries the package manager for installed packages that can + * respond to an intent with the specified action. If no suitable package is + * found, this method returns false. + * + * @param context The application's environment. + * @param action The Intent action to check for availability. + * + * @return True if an Intent with the specified action can be sent and + * responded to, false otherwise. + */ + static bool IsIntentAvailable(Context context, String action, String type, List categories) + { + PackageManager packageManager = context.PackageManager; + Intent intent = new Intent(action); + if (type != null) + intent.SetType(type); + if (categories != null) + categories.ForEach(c => intent.AddCategory(c)); + IList list = + packageManager.QueryIntentActivities(intent, + PackageInfoFlags.MatchDefaultOnly); + foreach (ResolveInfo i in list) + Kp2aLog.Log(i.ActivityInfo.ApplicationInfo.PackageName); + return list.Count > 0; + } + + /// + /// Opens a browse dialog for selecting a file. + /// + /// context activity + /// requestCode for onActivityResult + /// if true, the file location is meant for saving + /// if true, the caller prefers a location that can be used permanently + /// This means that ActionOpenDocument should be used instead of ActionGetContent (for not saving), as ActionGetContent + /// is more for one-time access, but therefore allows possibly more available sources. + public static void ShowBrowseDialog(Activity activity, int requestCodeBrowse, bool forSaving, + bool tryGetPermanentAccess) + { + //even though GetContent is not well supported (since Android 7, see https://commonsware.com/Android/previews/appendix-b-android-70) + //we still offer it. + var loadAction = (tryGetPermanentAccess && IsKitKatOrLater) + ? Intent.ActionOpenDocument + : Intent.ActionGetContent; + if ((!forSaving) && + (IsIntentAvailable(activity, loadAction, "*/*", new List { Intent.CategoryOpenable }))) + { + Intent i = new Intent(loadAction); + i.SetType("*/*"); + i.AddCategory(Intent.CategoryOpenable); + + activity.StartActivityForResult(i, requestCodeBrowse); + } + else + { + if ((forSaving) && (IsKitKatOrLater)) + { + Intent i = new Intent(Intent.ActionCreateDocument); + i.SetType("*/*"); + i.AddCategory(Intent.CategoryOpenable); + + activity.StartActivityForResult(i, requestCodeBrowse); + } + else + { + string defaultPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath; + + ShowInternalLocalFileChooser(activity, requestCodeBrowse, forSaving, defaultPath); + } + + } + } + + public static bool IsKitKatOrLater + { + get { return (int)Build.VERSION.SdkInt >= 19; } + } public static PendingIntentFlags AddMutabilityFlag(PendingIntentFlags flags, PendingIntentFlags mutability) @@ -464,219 +486,227 @@ namespace keepass2android else return flags; } - private static void ShowInternalLocalFileChooser(Activity act, int requestCodeBrowse, bool forSaving, string defaultPath) - { - + private static void ShowInternalLocalFileChooser(Activity act, int requestCodeBrowse, bool forSaving, + string defaultPath) + { + #if !EXCLUDE_FILECHOOSER - string fileProviderAuthority = act.PackageName+".android-filechooser.localfile"; + string fileProviderAuthority = act.PackageName + ".android-filechooser.localfile"; - Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(act, - fileProviderAuthority, - defaultPath); - if (forSaving) - i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true); + Intent i = Keepass2android.Kp2afilechooser.Kp2aFileChooserBridge.GetLaunchFileChooserIntent(act, + fileProviderAuthority, + defaultPath); + if (forSaving) + i.PutExtra("group.pals.android.lib.ui.filechooser.FileChooserActivity.save_dialog", true); - act.StartActivityForResult(i, requestCodeBrowse); + act.StartActivityForResult(i, requestCodeBrowse); #else - Toast.MakeText(act, "File Chooser excluded!",ToastLength.Long).Show(); + App.Kp2a.ShowMessage(act, "File Chooser excluded!", MessageSeverity.Error); #endif - } + } - /// - /// Tries to extract the filename from the intent. Returns that filename or null if no success - /// (e.g. on content-URIs in Android KitKat+). - /// Guarantees that the file exists. - /// - public static string IntentToFilename(Intent data, Context ctx) - { - string s = GetFilenameFromInternalFileChooser(data, ctx); - if (!String.IsNullOrEmpty(s)) - return s; + /// + /// Tries to extract the filename from the intent. Returns that filename or null if no success + /// (e.g. on content-URIs in Android KitKat+). + /// Guarantees that the file exists. + /// + public static string IntentToFilename(Intent data, Context ctx) + { + string s = GetFilenameFromInternalFileChooser(data, ctx); + if (!String.IsNullOrEmpty(s)) + return s; - try - { - Uri uri = data.Data; - if ((uri != null) && (uri.Scheme == "content")) - { - String[] col = new String[] {MediaStore.MediaColumns.Data}; - - ICursor c1 = ctx.ContentResolver.Query(uri, col, null, null, null); - c1.MoveToFirst(); + try + { + Uri uri = data.Data; + if ((uri != null) && (uri.Scheme == "content")) + { + String[] col = new String[] { MediaStore.MediaColumns.Data }; - var possibleFilename = c1.GetString(0); - if (File.Exists(possibleFilename)) - return possibleFilename; - } - } - catch (Exception e) - { - Kp2aLog.LogUnexpectedError(e); - } + ICursor c1 = ctx.ContentResolver.Query(uri, col, null, null, null); + c1.MoveToFirst(); - String filename = data.Data.Path; - if ((String.IsNullOrEmpty(filename) || (!File.Exists(filename)))) - filename = data.DataString; - if (File.Exists(filename)) - return filename; - //found no valid file - return null; - } + var possibleFilename = c1.GetString(0); + if (File.Exists(possibleFilename)) + return possibleFilename; + } + } + catch (Exception e) + { + Kp2aLog.LogUnexpectedError(e); + } - public static string GetFilenameFromInternalFileChooser(Intent data, Context ctx) - { + String filename = data.Data.Path; + if ((String.IsNullOrEmpty(filename) || (!File.Exists(filename)))) + filename = data.DataString; + if (File.Exists(filename)) + return filename; + //found no valid file + return null; + } + + public static string GetFilenameFromInternalFileChooser(Intent data, Context ctx) + { #if !EXCLUDE_FILECHOOSER - string EXTRA_RESULTS = "group.pals.android.lib.ui.filechooser.FileChooserActivity.results"; - if (data.HasExtra(EXTRA_RESULTS)) - { - IList uris = data.GetParcelableArrayListExtra(EXTRA_RESULTS); - Uri uri = (Uri) uris[0]; - { - return Group.Pals.Android.Lib.UI.Filechooser.Providers.BaseFileProviderUtils.GetRealUri(ctx, uri).ToString(); - } - } + string EXTRA_RESULTS = "group.pals.android.lib.ui.filechooser.FileChooserActivity.results"; + if (data.HasExtra(EXTRA_RESULTS)) + { + IList uris = data.GetParcelableArrayListExtra(EXTRA_RESULTS); + Uri uri = (Uri)uris[0]; + { + return Group.Pals.Android.Lib.UI.Filechooser.Providers.BaseFileProviderUtils.GetRealUri(ctx, uri) + .ToString(); + } + } #endif - return null; - } + return null; + } - public static bool HasActionBar(Activity activity) - { - //Actionbar is available since 11, but the layout has its own "pseudo actionbar" until 13 - return ((int)Android.OS.Build.VERSION.SdkInt >= 14) && (activity.ActionBar != null); - } + public static bool HasActionBar(Activity activity) + { + //Actionbar is available since 11, but the layout has its own "pseudo actionbar" until 13 + return ((int)Android.OS.Build.VERSION.SdkInt >= 14) && (activity.ActionBar != null); + } - public delegate bool FileSelectedHandler(string filename); - - - - public class DismissListener: Java.Lang.Object, IDialogInterfaceOnDismissListener - { - private readonly Action _onDismiss; - - public DismissListener(Action onDismiss) - { - _onDismiss = onDismiss; - } - - public void OnDismiss(IDialogInterface dialog) - { - _onDismiss(); - } - } + public delegate bool FileSelectedHandler(string filename); - class CancelListener: Java.Lang.Object, IDialogInterfaceOnCancelListener - { - private readonly Action _onCancel; - public CancelListener(Action onCancel) - { - _onCancel = onCancel; - } + public class DismissListener : Java.Lang.Object, IDialogInterfaceOnDismissListener + { + private readonly Action _onDismiss; - public void OnCancel(IDialogInterface dialog) - { - _onCancel(); - } - } + public DismissListener(Action onDismiss) + { + _onDismiss = onDismiss; + } - public static void ShowFilenameDialog(Activity activity, Func onOpen, Func onCreate, Action onCancel, bool showBrowseButton, string defaultFilename, string detailsText, int requestCodeBrowse) - { - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity); - builder.SetView(activity.LayoutInflater.Inflate(Resource.Layout.file_selection_filename, null)); - - if (onCancel != null) - builder.SetOnCancelListener(new CancelListener(onCancel)); - Dialog dialog = builder.Create(); - dialog.Show(); - - Button openButton = (Button) dialog.FindViewById(Resource.Id.open); - Button createButton = (Button) dialog.FindViewById(Resource.Id.create); - - TextView enterFilenameDetails = (TextView) dialog.FindViewById(Resource.Id.label_open_by_filename_details); - openButton.Visibility = onOpen != null ? ViewStates.Visible : ViewStates.Gone; - createButton.Visibility = onCreate != null? ViewStates.Visible : ViewStates.Gone; - // Set the initial value of the filename - EditText editFilename = (EditText) dialog.FindViewById(Resource.Id.file_filename); - editFilename.Text = defaultFilename; - enterFilenameDetails.Text = detailsText; - enterFilenameDetails.Visibility = enterFilenameDetails.Text == "" ? ViewStates.Gone : ViewStates.Visible; - - // Open button - if (onOpen != null) - openButton.Click += (sender, args) => - { - String fileName = ((EditText) dialog.FindViewById(Resource.Id.file_filename)).Text; - if (onOpen(fileName, dialog)) - dialog.Dismiss(); - }; - - // Create button - if (onCreate != null) - createButton.Click += (sender, args) => - { - String fileName = ((EditText)dialog.FindViewById(Resource.Id.file_filename)).Text; - if (onCreate(fileName, dialog)) - dialog.Dismiss(); - }; - - Button cancelButton = (Button) dialog.FindViewById(Resource.Id.fnv_cancel); - cancelButton.Click += delegate - { - dialog.Dismiss(); - if (onCancel != null) - onCancel(); - }; - - ImageButton browseButton = (ImageButton) dialog.FindViewById(Resource.Id.browse_button); - if (!showBrowseButton) - { - browseButton.Visibility = ViewStates.Invisible; - } - browseButton.Click += (sender, evt) => - { - string filename = ((EditText) dialog.FindViewById(Resource.Id.file_filename)).Text; - - Util.ShowBrowseDialog(activity, requestCodeBrowse, onCreate != null, /*TODO should we prefer ActionOpenDocument here?*/ false); - - }; - - } - - public static void QueryCredentials(IOConnectionInfo ioc, Action afterQueryCredentials, Activity activity) - { - //Build dialog to query credentials: - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity); - builder.SetTitle(activity.GetString(Resource.String.credentials_dialog_title)); - builder.SetPositiveButton(activity.GetString(Android.Resource.String.Ok), (dlgSender, dlgEvt) => - { - Dialog dlg = (Dialog)dlgSender; - string username = ((EditText)dlg.FindViewById(Resource.Id.cred_username)).Text; - string password = ((EditText)dlg.FindViewById(Resource.Id.cred_password)).Text; - int credentialRememberMode = ((Spinner)dlg.FindViewById(Resource.Id.cred_remember_mode)).SelectedItemPosition; - ioc.UserName = username; - ioc.Password = password; - ioc.CredSaveMode = (IOCredSaveMode)credentialRememberMode; - afterQueryCredentials(ioc); - }); - builder.SetView(activity.LayoutInflater.Inflate(Resource.Layout.url_credentials, null)); - builder.SetNeutralButton(activity.GetString(Android.Resource.String.Cancel), - (dlgSender, dlgEvt) => { }); - Dialog dialog = builder.Create(); - dialog.Show(); - ((EditText)dialog.FindViewById(Resource.Id.cred_username)).Text = ioc.UserName; - ((EditText)dialog.FindViewById(Resource.Id.cred_password)).Text = ioc.Password; - ((Spinner)dialog.FindViewById(Resource.Id.cred_remember_mode)).SetSelection((int)ioc.CredSaveMode); - } + public void OnDismiss(IDialogInterface dialog) + { + _onDismiss(); + } + } - public static void FinishAndForward(Activity activity, Intent i) - { - i.SetFlags(ActivityFlags.ForwardResult); - activity.StartActivity(i); - activity.Finish(); - } + class CancelListener : Java.Lang.Object, IDialogInterfaceOnCancelListener + { + private readonly Action _onCancel; + + public CancelListener(Action onCancel) + { + _onCancel = onCancel; + } + + public void OnCancel(IDialogInterface dialog) + { + _onCancel(); + } + } + + public static void ShowFilenameDialog(Activity activity, Func onOpen, + Func onCreate, Action onCancel, bool showBrowseButton, string defaultFilename, + string detailsText, int requestCodeBrowse) + { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity); + builder.SetView(activity.LayoutInflater.Inflate(Resource.Layout.file_selection_filename, null)); + + if (onCancel != null) + builder.SetOnCancelListener(new CancelListener(onCancel)); + Dialog dialog = builder.Create(); + dialog.Show(); + + Button openButton = (Button)dialog.FindViewById(Resource.Id.open); + Button createButton = (Button)dialog.FindViewById(Resource.Id.create); + + TextView enterFilenameDetails = (TextView)dialog.FindViewById(Resource.Id.label_open_by_filename_details); + openButton.Visibility = onOpen != null ? ViewStates.Visible : ViewStates.Gone; + createButton.Visibility = onCreate != null ? ViewStates.Visible : ViewStates.Gone; + // Set the initial value of the filename + EditText editFilename = (EditText)dialog.FindViewById(Resource.Id.file_filename); + editFilename.Text = defaultFilename; + enterFilenameDetails.Text = detailsText; + enterFilenameDetails.Visibility = enterFilenameDetails.Text == "" ? ViewStates.Gone : ViewStates.Visible; + + // Open button + if (onOpen != null) + openButton.Click += (sender, args) => + { + String fileName = ((EditText)dialog.FindViewById(Resource.Id.file_filename)).Text; + if (onOpen(fileName, dialog)) + dialog.Dismiss(); + }; + + // Create button + if (onCreate != null) + createButton.Click += (sender, args) => + { + String fileName = ((EditText)dialog.FindViewById(Resource.Id.file_filename)).Text; + if (onCreate(fileName, dialog)) + dialog.Dismiss(); + }; + + Button cancelButton = (Button)dialog.FindViewById(Resource.Id.fnv_cancel); + cancelButton.Click += delegate + { + dialog.Dismiss(); + if (onCancel != null) + onCancel(); + }; + + ImageButton browseButton = (ImageButton)dialog.FindViewById(Resource.Id.browse_button); + if (!showBrowseButton) + { + browseButton.Visibility = ViewStates.Invisible; + } + + browseButton.Click += (sender, evt) => + { + string filename = ((EditText)dialog.FindViewById(Resource.Id.file_filename)).Text; + + Util.ShowBrowseDialog(activity, requestCodeBrowse, + onCreate != null, /*TODO should we prefer ActionOpenDocument here?*/ false); + + }; + + } + + public static void QueryCredentials(IOConnectionInfo ioc, Action afterQueryCredentials, + Activity activity) + { + //Build dialog to query credentials: + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity); + builder.SetTitle(activity.GetString(Resource.String.credentials_dialog_title)); + builder.SetPositiveButton(activity.GetString(Android.Resource.String.Ok), (dlgSender, dlgEvt) => + { + Dialog dlg = (Dialog)dlgSender; + string username = ((EditText)dlg.FindViewById(Resource.Id.cred_username)).Text; + string password = ((EditText)dlg.FindViewById(Resource.Id.cred_password)).Text; + int credentialRememberMode = + ((Spinner)dlg.FindViewById(Resource.Id.cred_remember_mode)).SelectedItemPosition; + ioc.UserName = username; + ioc.Password = password; + ioc.CredSaveMode = (IOCredSaveMode)credentialRememberMode; + afterQueryCredentials(ioc); + }); + builder.SetView(activity.LayoutInflater.Inflate(Resource.Layout.url_credentials, null)); + builder.SetNeutralButton(activity.GetString(Android.Resource.String.Cancel), + (dlgSender, dlgEvt) => { }); + Dialog dialog = builder.Create(); + dialog.Show(); + ((EditText)dialog.FindViewById(Resource.Id.cred_username)).Text = ioc.UserName; + ((EditText)dialog.FindViewById(Resource.Id.cred_password)).Text = ioc.Password; + ((Spinner)dialog.FindViewById(Resource.Id.cred_remember_mode)).SetSelection((int)ioc.CredSaveMode); + } + + + public static void FinishAndForward(Activity activity, Intent i) + { + i.SetFlags(ActivityFlags.ForwardResult); + activity.StartActivity(i); + activity.Finish(); + } public static void PrepareDonateOptionMenu(IMenu menu, Context ctx) { @@ -685,12 +715,12 @@ namespace keepass2android { donateItem.SetVisible( !PreferenceManager.GetDefaultSharedPreferences(ctx) - .GetBoolean(ctx.GetString(Resource.String.NoDonateOption_key), false) - ); + .GetBoolean(ctx.GetString(Resource.String.NoDonateOption_key), false) + ); } } - + public static bool GetCloseDatabaseAfterFailedBiometricQuickUnlock(Context ctx) { return (PreferenceManager.GetDefaultSharedPreferences(ctx).GetBoolean( @@ -699,102 +729,110 @@ namespace keepass2android } - + public static void MoveBottomBarButtons(int btn1Id, int btn2Id, int bottomBarId, Activity context) - { - var btn1 = context.FindViewById