Compare commits

..

475 Commits

Author SHA1 Message Date
J-Jamet
2b0f4fe46b Merge branch 'release/4.1.1' 2024-11-24 15:46:00 +01:00
J-Jamet
55c2f41c71 fix: tags 2024-11-24 14:59:06 +01:00
109247019824
94985422ca Translated using Weblate (Bulgarian)
Currently translated at 99.0% (660 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-11-24 14:27:14 +01:00
Matthaiks
eaff1aa58f Translated using Weblate (Polish)
Currently translated at 100.0% (666 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2024-11-24 14:27:14 +01:00
Ghost of Sparta
c7cb9d0990 Translated using Weblate (Hungarian)
Currently translated at 100.0% (666 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2024-11-24 14:27:14 +01:00
gallegonovato
a9fdf30421 Translated using Weblate (Spanish)
Currently translated at 100.0% (666 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-11-24 14:27:13 +01:00
Matthaiks
d0f45f6dfb Translated using Weblate (Polish)
Currently translated at 99.3% (662 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2024-11-24 12:07:11 +01:00
Hosted Weblate
8cdb6a3c9f Merge branch 'origin/develop' into Weblate. 2024-11-24 12:06:37 +01:00
Kunzisoft
b369a46431 Translated using Weblate (French)
Currently translated at 100.0% (666 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2024-11-24 12:06:37 +01:00
gallegonovato
f40ca2d5e0 Translated using Weblate (Spanish)
Currently translated at 100.0% (666 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-11-24 12:06:37 +01:00
Anonymous
400393c677 Translated using Weblate (Azerbaijani)
Currently translated at 97.1% (647 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-11-24 12:05:41 +01:00
Anonymous
5710e3be55 Translated using Weblate (Serbian)
Currently translated at 50.4% (336 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sr/
2024-11-24 12:05:41 +01:00
Anonymous
af1312a92b Translated using Weblate (Estonian)
Currently translated at 32.4% (216 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-11-24 12:05:40 +01:00
Anonymous
d2a63c48b1 Translated using Weblate (Filipino)
Currently translated at 46.2% (308 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fil/
2024-11-24 12:05:40 +01:00
Anonymous
8f10ea7ed6 Translated using Weblate (Cantonese (Traditional Han script))
Currently translated at 20.1% (134 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/yue_Hant/
2024-11-24 12:05:40 +01:00
Anonymous
7bd701368a Translated using Weblate (Thai)
Currently translated at 89.3% (595 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2024-11-24 12:05:40 +01:00
Anonymous
894e846a62 Translated using Weblate (English (United Kingdom))
Currently translated at 33.9% (226 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en_GB/
2024-11-24 12:05:40 +01:00
Anonymous
504ef5a7ab Translated using Weblate (Vietnamese)
Currently translated at 98.6% (657 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2024-11-24 12:05:40 +01:00
Anonymous
af6436da77 Translated using Weblate (Bulgarian)
Currently translated at 98.6% (657 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-11-24 12:05:40 +01:00
Anonymous
d031420ed3 Translated using Weblate (Portuguese)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2024-11-24 12:05:40 +01:00
Anonymous
4b6b7478de Translated using Weblate (Indonesian)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2024-11-24 12:05:40 +01:00
Anonymous
bb1b5eab96 Translated using Weblate (Romanian)
Currently translated at 98.6% (657 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-11-24 12:05:40 +01:00
Anonymous
9486b50342 Translated using Weblate (Croatian)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2024-11-24 12:05:39 +01:00
Anonymous
fc9a5b3545 Translated using Weblate (Turkish)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2024-11-24 12:05:39 +01:00
Anonymous
8b4d0e2541 Translated using Weblate (Norwegian Bokmål)
Currently translated at 98.6% (657 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nb_NO/
2024-11-24 12:05:39 +01:00
Anonymous
0ef07f615c Translated using Weblate (Galician)
Currently translated at 86.7% (578 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2024-11-24 12:05:39 +01:00
Anonymous
836413cff2 Translated using Weblate (Arabic)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2024-11-24 12:05:39 +01:00
Anonymous
c71e34fee9 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2024-11-24 12:05:39 +01:00
Anonymous
b389a4db92 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2024-11-24 12:05:39 +01:00
Anonymous
0a1a54cb33 Translated using Weblate (Ukrainian)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2024-11-24 12:05:39 +01:00
Anonymous
630228675c Translated using Weblate (Swedish)
Currently translated at 62.4% (416 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sv/
2024-11-24 12:05:39 +01:00
Anonymous
f7955d00fc Translated using Weblate (Slovak)
Currently translated at 92.0% (613 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sk/
2024-11-24 12:05:39 +01:00
Anonymous
68b08f9b9a Translated using Weblate (Russian)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-11-24 12:05:39 +01:00
Anonymous
612f136ced Translated using Weblate (Portuguese (Portugal))
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2024-11-24 12:05:39 +01:00
Anonymous
8c313c3d48 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2024-11-24 12:05:38 +01:00
Anonymous
517a6c0062 Translated using Weblate (Polish)
Currently translated at 99.2% (661 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2024-11-24 12:05:38 +01:00
Matthaiks
46c61b10de Translated using Weblate (Polish)
Currently translated at 99.2% (661 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2024-11-24 12:05:38 +01:00
Anonymous
edc8d27577 Translated using Weblate (Dutch)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2024-11-24 12:05:38 +01:00
Anonymous
05354777fe Translated using Weblate (Japanese)
Currently translated at 96.8% (645 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2024-11-24 12:05:38 +01:00
Anonymous
98d3d2a39b Translated using Weblate (Italian)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2024-11-24 12:05:38 +01:00
Anonymous
f91f75912e Translated using Weblate (Hungarian)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2024-11-24 12:05:38 +01:00
Anonymous
9f21f67035 Translated using Weblate (French)
Currently translated at 99.5% (663 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2024-11-24 12:05:38 +01:00
Kunzisoft
699e4da112 Translated using Weblate (French)
Currently translated at 99.5% (663 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2024-11-24 12:05:38 +01:00
Anonymous
6458285e75 Translated using Weblate (Basque)
Currently translated at 95.7% (638 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2024-11-24 12:05:38 +01:00
Anonymous
e0ddf3711f Translated using Weblate (Spanish)
Currently translated at 99.8% (665 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-11-24 12:05:38 +01:00
gallegonovato
68d415375d Translated using Weblate (Spanish)
Currently translated at 99.8% (665 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-11-24 12:05:38 +01:00
Anonymous
0e11afdd8b Translated using Weblate (Greek)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2024-11-24 12:05:37 +01:00
Anonymous
ff2c01584f Translated using Weblate (German)
Currently translated at 98.6% (657 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-11-24 12:05:37 +01:00
Anonymous
a59e20b864 Translated using Weblate (Danish)
Currently translated at 98.6% (657 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2024-11-24 12:05:37 +01:00
Anonymous
d7d898896d Translated using Weblate (Czech)
Currently translated at 98.7% (658 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2024-11-24 12:05:37 +01:00
Anonymous
2dde78d5e7 Translated using Weblate (Catalan)
Currently translated at 94.8% (632 of 666 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ca/
2024-11-24 12:05:37 +01:00
J-Jamet
2ca39ff399 fix: update string 2024-11-24 12:04:36 +01:00
Hosted Weblate
1f6fdaf9b3 Merge branch 'origin/develop' into Weblate. 2024-11-24 11:58:45 +01:00
J-Jamet
edaf58135f fix: Upgrade to 4.1.1 2024-11-24 11:56:41 +01:00
J-Jamet
724698fc51 fix: Date parser #1933 2024-11-24 11:52:13 +01:00
summoner001
6aabe9e12c Translated using Weblate (Hungarian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2024-11-23 19:39:32 +01:00
bowornsin
2b5a1bb893 Translated using Weblate (Thai)
Currently translated at 90.2% (595 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2024-11-23 04:00:27 +00:00
summoner001
7403305f3c Translated using Weblate (Hungarian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2024-11-23 04:00:26 +00:00
J-Jamet
e780f8a3f0 fix: Matching against domain goes too far #1820 2024-11-19 21:48:16 +01:00
J-Jamet
7f2fda0327 Merge tag '4.1.0' into develop
4.1.0
2024-11-18 11:54:37 +01:00
J-Jamet
ada8f74e2c Merge branch 'release/4.1.0' 2024-11-18 11:54:27 +01:00
J-Jamet
1ddfeaf950 fix: update Gemfile 2024-11-18 11:07:14 +01:00
J-Jamet
2ed2cc1499 fix: Replace strong tag 2024-11-18 11:00:46 +01:00
J-Jamet
be0f90f12a Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2024-11-18 10:58:28 +01:00
J-Jamet
4b362df23b Merge branch 'master' into develop 2024-11-17 20:32:20 +01:00
J-Jamet
b953a1c2f6 fix: Package authenticity 2024-11-17 20:29:45 +01:00
J-Jamet
4c30fa43d3 fix: Screenshot protection #1870 2024-11-17 19:32:23 +01:00
J-Jamet
6866b1a3bb fix: change expires icon 2024-11-17 14:59:07 +01:00
J-Jamet
328030f152 fix: timer precision #1467 2024-11-17 14:46:16 +01:00
J-Jamet
fd195bd926 fix: reset timer only if in DAO 2024-11-17 13:52:58 +01:00
J-Jamet
87e07366cd Resets the advanced unlock expiration #1600 2024-11-17 13:31:47 +01:00
J-Jamet
8133977e09 feat: Add shield icon as password strength indicator #1355 2024-11-16 12:56:46 +01:00
J-Jamet
11199b996c fix: Password color and entropy view 2024-11-15 19:25:00 +01:00
J-Jamet
eee61db189 Add entropy 2024-11-15 17:45:09 +01:00
J-Jamet
c7c5130030 fix: passkeyview to passwordview 2024-11-14 19:57:35 +01:00
J-Jamet
6de14a3840 fix: TimeZone 2024-11-13 21:13:50 +01:00
J-Jamet
55206b3dde fix: All past dates and times are crossed out #1710 2024-11-13 20:54:31 +01:00
Priit Jõerüüt
e1a44477af Translated using Weblate (Estonian)
Currently translated at 32.9% (217 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-11-12 18:00:27 +01:00
Aitor Elorza
23afee453e Translated using Weblate (Basque)
Currently translated at 96.8% (638 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2024-11-12 18:00:26 +01:00
J-Jamet
8e05309021 feat: Support otpauth://steam/Steam link #1289 2024-11-11 16:06:48 +01:00
J-Jamet
26fdf87070 fix: distinct domain names #1820 2024-11-11 15:34:48 +01:00
J-Jamet
1c95a0edc4 fix: distinct domain names #1105 2024-11-08 21:11:26 +01:00
J-Jamet
4723fb39e9 fix: Sort 2024-11-08 13:27:26 +01:00
Jamil Farajov
13d667d81c Translated using Weblate (Azerbaijani)
Currently translated at 98.6% (650 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-11-07 12:00:40 +00:00
Jamil Farajov
dce255dc58 Translated using Weblate (Azerbaijani)
Currently translated at 91.9% (606 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-11-06 12:00:23 +01:00
Random
f72c9704d9 Translated using Weblate (Italian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2024-11-06 12:00:21 +01:00
Sylvain Pichon
e623010e91 Translated using Weblate (French)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2024-11-05 07:00:22 +00:00
J-Jamet
587bfdc162 fix: Month save 2024-11-04 20:02:19 +01:00
J-Jamet
7c1c299282 fix: Off-by-one when selecting date fields #1695 2024-11-04 19:43:30 +01:00
Priit Jõerüüt
f2a5c0b04b Translated using Weblate (Estonian)
Currently translated at 32.6% (215 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-11-03 23:00:16 +01:00
J-Jamet
4ba77b76ec feat: Instant in copy #1889 2024-11-02 13:37:33 +01:00
J-Jamet
0bfce44317 fix: unlocking procedure #1760 2024-11-02 11:04:15 +01:00
solokot
13b6d6384c Translated using Weblate (Russian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-10-29 00:12:52 +01:00
ginger-co
80838bbef0 Translated using Weblate (Hebrew)
Currently translated at 92.5% (610 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2024-10-27 15:00:19 +01:00
Avi Parshan
8a557ff2fb Translated using Weblate (Hebrew)
Currently translated at 81.0% (534 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2024-10-26 15:45:55 +02:00
ginger-co
16e394087d Translated using Weblate (Hebrew)
Currently translated at 81.0% (534 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2024-10-26 15:45:55 +02:00
Avi Parshan
ee1b67b36e Translated using Weblate (Hebrew)
Currently translated at 70.4% (464 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2024-10-26 15:04:50 +02:00
ginger-co
36b9fa2387 Translated using Weblate (Hebrew)
Currently translated at 70.4% (464 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2024-10-26 15:04:50 +02:00
Jérémy JAMET
378169e939 Update README.md, remove the keytool section 2024-10-24 11:50:33 +02:00
Jamil Farajov
70a01e559d Translated using Weblate (Azerbaijani)
Currently translated at 36.8% (243 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-22 17:16:33 +02:00
shinebrillant
c09e8196f3 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2024-10-22 17:16:32 +02:00
J-Jamet
0382c05152 fix: Filters 2024-10-21 19:54:47 +02:00
Celeste Liu
75cf6e2a56 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2024-10-21 00:20:33 +02:00
J-Jamet
9fb4754430 feat: Number of children #421 2024-10-20 21:15:21 +02:00
J-Jamet
0312b504a9 fix: upgrade CHANGELOG 2024-10-20 18:51:28 +02:00
J-Jamet
1d6a9651bf fix: upgrade to API34 #1894 2024-10-20 18:44:06 +02:00
Jamil Farajov
e36b18e85e Translated using Weblate (Azerbaijani)
Currently translated at 26.5% (175 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-18 00:23:21 +02:00
Roko Magdalenić
4ae4951e0d Translated using Weblate (Serbian)
Currently translated at 51.1% (337 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sr/
2024-10-16 23:15:48 +02:00
Roko Magdalenić
a65f52ffba Translated using Weblate (Serbian (Latin script))
Currently translated at 59.7% (394 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sr_Latn/
2024-10-16 23:15:47 +02:00
Linerly
6de25ffa65 Translated using Weblate (Indonesian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2024-10-15 04:15:44 +02:00
Francisco Serrador
d8429bdd99 Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-10-13 22:16:18 +00:00
Jamil Farajov
26976ae6cf Translated using Weblate (Azerbaijani)
Currently translated at 22.7% (150 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-09 20:12:00 +02:00
Jamil Farajov
53beaca563 Translated using Weblate (Azerbaijani)
Currently translated at 18.6% (123 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-06 23:53:53 +02:00
Jamil Farajov
77628e2fb9 Translated using Weblate (Azerbaijani)
Currently translated at 18.2% (120 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-06 16:35:40 +02:00
Jamil Farajov
40d2f2de96 Translated using Weblate (Azerbaijani)
Currently translated at 18.0% (119 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-06 05:40:45 +02:00
Jamil Farajov
84cdb2483f Translated using Weblate (Azerbaijani)
Currently translated at 15.9% (105 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-06 05:04:26 +02:00
Jamil Farajov
c7866bfbbf Translated using Weblate (Azerbaijani)
Currently translated at 12.8% (85 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-05 23:50:54 +02:00
Jamil Farajov
5de1d6b343 Translated using Weblate (Azerbaijani)
Currently translated at 10.7% (71 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/az/
2024-10-05 20:04:36 +02:00
Jamil Farajov
7bde363704 Added translation using Weblate (Azerbaijani) 2024-10-05 17:03:03 +02:00
Priit Jõerüüt
1f9b2ce7b9 Translated using Weblate (Estonian)
Currently translated at 25.3% (167 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-10-04 00:41:37 +02:00
Francisco Serrador
ac2e47776a Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-09-25 01:15:42 +02:00
Ghost of Sparta
e7de5ca263 Translated using Weblate (Hungarian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2024-09-24 00:12:32 +02:00
Francisco Serrador
f7f079e653 Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-09-24 00:12:32 +02:00
Ghost of Sparta
f7cccb33de Translated using Weblate (Hungarian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2024-09-22 19:40:47 +02:00
J-Jamet
8177c9c34b fix: textColorHighlight #1711 2024-09-06 18:13:12 +02:00
J-Jamet
850c46f881 feat: Generate keyfile #1290 2024-09-06 17:13:24 +02:00
J-Jamet
ffcfe966d2 fix: Add warning for KeyFile length #1780 2024-09-06 15:55:36 +02:00
J-Jamet
800badd2a4 Merge branch 'shuvashish76-patch-1' into develop 2024-09-06 11:08:16 +02:00
J-Jamet
0a7ffbcc8f fix: Make the apk verification even clearer #1831 2024-09-06 10:31:41 +02:00
J-Jamet
019ec4de9a fix: Avoid DEPENDENCY_INFO_BLOCK 2024-09-06 09:54:35 +02:00
Priit Jõerüüt
78d1e4a12a Translated using Weblate (Estonian)
Currently translated at 24.8% (164 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-09-02 17:09:18 +02:00
SC
6c99fefad0 Translated using Weblate (Portuguese)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2024-08-23 19:09:13 +00:00
SC
24bc1424b9 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2024-08-23 19:09:12 +00:00
Random
94a0e17cfc Translated using Weblate (Italian)
Currently translated at 99.8% (658 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2024-08-23 19:09:12 +00:00
獅童乱(しどらん)
2f012d8cf2 Translated using Weblate (Japanese)
Currently translated at 98.0% (646 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2024-08-22 11:09:12 +00:00
gallegonovato
75b800054f Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-08-16 15:09:18 +02:00
Renko
d7c7733315 Translated using Weblate (Romanian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-08-15 13:09:11 +02:00
Ihor Hordiichuk
99600ad8d8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2024-08-15 13:09:11 +02:00
Milo Ivir
4a4c7b8b6b Translated using Weblate (Croatian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2024-08-14 12:09:21 +02:00
jonnysemon
8c3267b345 Translated using Weblate (Arabic)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2024-08-14 12:09:21 +02:00
ΣΤΑΥΡΟΣ ΔΑΛΙΑΚΟΠΟΥΛΟΣ
c0240b047b Translated using Weblate (Greek)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2024-08-14 12:09:20 +02:00
Fjuro
c52957ccfe Translated using Weblate (Czech)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2024-08-14 12:09:18 +02:00
Besnik Bleta
fb3f057adf Translated using Weblate (Albanian)
Currently translated at 54.9% (362 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sq/
2024-08-12 17:09:28 +02:00
109247019824
e333bd08a4 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-08-12 17:09:28 +02:00
Oğuz Ersen
1844a269cb Translated using Weblate (Turkish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2024-08-12 17:09:27 +02:00
大王叫我来巡山
859882d24f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2024-08-12 17:09:26 +02:00
solokot
c95543b8b0 Translated using Weblate (Russian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-08-12 17:09:26 +02:00
Wellington Terumi Uemura
d874125dc1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2024-08-12 17:09:25 +02:00
Matthaiks
795cd099f4 Translated using Weblate (Polish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2024-08-12 17:09:24 +02:00
Alex Bruinsma
66ef6fd9d8 Translated using Weblate (Dutch)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2024-08-12 17:09:23 +02:00
gallegonovato
3b0655354d Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-08-12 17:09:23 +02:00
Keterion
76acec93fd Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-08-12 17:09:22 +02:00
VfBFan
3b60068369 Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-08-12 17:09:21 +02:00
Keterion
a0fd0a71a2 Translated using Weblate (Catalan)
Currently translated at 96.0% (633 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ca/
2024-08-11 16:57:29 +02:00
Keterion
907accbcc9 Translated using Weblate (English)
Currently translated at 99.8% (658 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en/
2024-08-11 16:57:29 +02:00
Alex Bruinsma
ee284abf8d Translated using Weblate (Dutch)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2024-08-07 16:09:12 +00:00
Hierax Swiftwing
8239275770 Translated using Weblate (Serbian)
Currently translated at 9.1% (60 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sr/
2024-08-01 03:09:13 +02:00
Hierax Swiftwing
029485bace Translated using Weblate (Serbian)
Currently translated at 8.6% (57 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sr/
2024-07-31 02:09:18 +02:00
Thom
cef9f6ae3b Translated using Weblate (Danish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2024-07-31 02:09:17 +02:00
Hierax Swiftwing
8d88c94956 Added translation using Weblate (Serbian) 2024-07-30 02:03:40 +02:00
Patricio Carrau
692e155117 Translated using Weblate (French)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2024-07-30 02:03:40 +02:00
The One
9a9410de2b Translated using Weblate (Swedish)
Currently translated at 63.2% (417 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sv/
2024-07-29 23:09:12 +02:00
ssantos
a27f1181ea Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2024-07-15 14:09:14 +02:00
searinminecraft
ac65cadb1b Translated using Weblate (Filipino)
Currently translated at 47.0% (310 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fil/
2024-07-13 06:09:13 +00:00
Renko
4345e75b20 Translated using Weblate (Romanian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-07-10 16:09:29 +02:00
j
f64d085e7b Translated using Weblate (Lithuanian)
Currently translated at 61.0% (402 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/lt/
2024-07-10 16:09:28 +02:00
Kemal Karagöz
325b878f0a Translated using Weblate (Turkish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2024-07-09 10:09:19 +02:00
Salih ARSLAN
330f375a30 Translated using Weblate (Turkish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2024-07-06 11:49:51 +02:00
Fqwe1
7d6c211de1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2024-07-04 16:09:10 +02:00
Ben Towali
af5b36752c Translated using Weblate (Estonian)
Currently translated at 19.8% (131 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-07-01 22:09:24 +02:00
WebTrans
e0f563befb Translated using Weblate (Hebrew)
Currently translated at 44.3% (292 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2024-07-01 22:09:23 +02:00
Ben Towali
bf1b84dfea Translated using Weblate (Estonian)
Currently translated at 9.2% (61 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-06-30 21:20:00 +02:00
searinminecraft
b3f8ce9c16 Translated using Weblate (Filipino)
Currently translated at 46.4% (306 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fil/
2024-06-27 07:14:57 +02:00
Mr-Update
499152d066 Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-06-25 11:09:13 +02:00
VfBFan
c47e7edc9e Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-06-25 11:09:12 +02:00
shuvashish76
afc034b495 Improved IzzyOnDroid shield 2024-06-24 19:00:43 +05:30
J-Jamet
e1d19741af Merge branch 'feature/API34' into develop 2024-06-24 13:26:36 +02:00
J-Jamet
8d2de40df6 fix: Upgrade all modules to API 34 #1730 2024-06-24 13:14:52 +02:00
J-Jamet
f4b7db667f fix: Broadcast Receiver #1730 2024-06-24 12:59:33 +02:00
J-Jamet
4032e52317 fix: Upgrade Foreground service and version to 4.1.0 2024-06-24 12:32:05 +02:00
J-Jamet
f9db4325d8 Merge branch 'master' into develop 2024-06-24 10:37:39 +02:00
Jérémy JAMET
815824f76d Merge pull request #1862 from shuvashish76/patch-1
Add download sources table
2024-06-24 10:23:01 +02:00
Masowick
8534672c33 Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-06-24 10:20:54 +02:00
shuvashish76
b9bb9a166a Update README.md 2024-06-24 13:39:11 +05:30
shuvashish76
185c886472 Add download sources table 2024-06-24 04:52:01 +05:30
Mr-Update
acc565d021 Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-06-23 15:57:04 +02:00
solokot
64db137c6c Translated using Weblate (Russian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-06-21 20:09:59 +02:00
Kirill Isakov
4f2bdeb2c9 Translated using Weblate (Russian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-06-20 19:09:58 +02:00
ngocanhtve
527994084b Translated using Weblate (Vietnamese)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2024-06-19 02:09:25 +00:00
J-Jamet
ffaf5c9475 Merge tag '4.0.8' into develop
4.0.8
2024-06-18 20:19:52 +02:00
J-Jamet
d1e24bfcd8 Merge branch 'release/4.0.8' 2024-06-18 20:19:46 +02:00
J-Jamet
aab8612c63 fix: update fastlane 2024-06-18 20:19:40 +02:00
J-Jamet
79c1e2d21c fix: #1848 #1850 2024-06-18 20:08:54 +02:00
J-Jamet
7ff44f4839 Merge tag '4.0.7' into develop
4.0.7
2024-06-17 23:20:57 +02:00
J-Jamet
2de0272e3e Merge branch 'release/4.0.7' 2024-06-17 23:20:48 +02:00
J-Jamet
1d22fe72d0 fix: ru fastlane 2024-06-17 23:20:30 +02:00
J-Jamet
7e9821551c fix: tags 2024-06-17 22:53:21 +02:00
J-Jamet
8fb3cd71b9 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2024-06-17 22:50:28 +02:00
J-Jamet
b0f6f1f2ba fix: Update CHANGELOG 2024-06-17 19:07:43 +02:00
Jérémy JAMET
df56dc4a4a Merge pull request #1840 from lgjint/fix-inline-suggestion
fix: inline suggestions in keyboard only show ''Select entry''
2024-06-17 19:05:29 +02:00
J-Jamet
b572ec4901 fix: Update CHANGELOG 2024-06-17 12:46:43 +02:00
J-Jamet
75759171c1 fix: Upgrade to 4.0.7 2024-06-17 12:39:47 +02:00
J-Jamet
322fe185dd fix: Description 2024-06-17 12:38:39 +02:00
J-Jamet
effe514ecb fix: Show broken link by default 2024-06-17 11:45:42 +02:00
jonnysemon
4ff9f69548 Translated using Weblate (Arabic)
Currently translated at 99.5% (656 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2024-06-11 21:02:14 +02:00
Priit Jõerüüt
e1c7cb17da Translated using Weblate (Estonian)
Currently translated at 2.7% (18 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/
2024-06-10 20:09:43 +02:00
jonnysemon
e6defd7770 Translated using Weblate (Arabic)
Currently translated at 99.2% (654 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2024-06-10 20:09:42 +02:00
J-Jamet
bba9f45075 fix: Group height resizable #1770 2024-06-10 18:45:22 +02:00
Priit Jõerüüt
de1a2d1557 Added translation using Weblate (Estonian) 2024-06-10 12:10:53 +02:00
ngocanhtve
e995d06a26 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2024-06-08 06:09:18 +02:00
NicolaeFericitu
63f54a1318 Translated using Weblate (Romanian)
Currently translated at 98.4% (649 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-06-05 19:09:11 +00:00
Milo Ivir
0828c9f901 Translated using Weblate (Croatian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2024-06-05 19:09:10 +00:00
lgjint
51cd38450a fix: inline suggestions in keyboard only show ''Select entry'' Kunzisoft/KeePassDX#1708 2024-06-03 22:42:53 +08:00
Knut-Helge Eikrem
0a4a720fea Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nb_NO/
2024-06-02 19:30:56 +02:00
Knut-Helge Eikrem
7f7ce171e0 Translated using Weblate (English)
Currently translated at 99.6% (657 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en/
2024-06-02 19:30:56 +02:00
ΣΤΑΥΡΟΣ ΔΑΛΙΑΚΟΠΟΥΛΟΣ
87622cc6ec Translated using Weblate (Greek)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2024-06-02 00:09:19 +02:00
solokot
aaf2e64fdb Translated using Weblate (Russian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-05-29 20:09:24 +02:00
Patricio Carrau
c6f22e7ce5 Translated using Weblate (French)
Currently translated at 99.8% (658 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2024-05-28 00:09:11 +02:00
Random
749a2d19aa Translated using Weblate (Italian)
Currently translated at 99.8% (658 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2024-05-25 10:09:13 +02:00
gallegonovato
ed3491fbba Translated using Weblate (Spanish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-05-21 18:13:40 +02:00
109247019824
f5e4b7cd6a Translated using Weblate (Bulgarian)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-05-21 08:01:49 +00:00
大王叫我来巡山
0b614e81ee Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2024-05-21 08:01:48 +00:00
Wellington Terumi Uemura
0a93b660cf Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2024-05-21 08:01:47 +00:00
Oğuz Ersen
71e104e4bd Translated using Weblate (Turkish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2024-05-20 09:01:58 +02:00
Matthaiks
189c5de7ea Translated using Weblate (Polish)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2024-05-20 09:01:58 +02:00
Stephan Paternotte
a5e141c361 Translated using Weblate (Dutch)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2024-05-20 09:01:57 +02:00
Masowick
e76d8d4df7 Translated using Weblate (German)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-05-20 09:01:56 +02:00
Fjuro
d54c093985 Translated using Weblate (Czech)
Currently translated at 100.0% (659 of 659 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2024-05-20 09:01:55 +02:00
Hosted Weblate
086709e40f Merge branch 'origin/develop' into Weblate. 2024-05-19 07:55:21 +02:00
SC
9477e32ec8 Translated using Weblate (Portuguese)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2024-05-18 10:01:56 +02:00
SC
a66a0628ad Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2024-05-18 10:01:55 +02:00
Random
ea018bd4c1 Translated using Weblate (Italian)
Currently translated at 99.8% (657 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2024-05-18 10:01:54 +02:00
searinminecraft
8e81ee3b75 Translated using Weblate (Filipino)
Currently translated at 42.2% (278 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fil/
2024-05-16 08:02:04 +00:00
NicolaeFericitu
9c326f9be9 Translated using Weblate (Romanian)
Currently translated at 98.6% (649 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-05-16 08:02:02 +00:00
J-Jamet
7d2a0aa793 fix: Bad link for device unlocking #1826 2024-05-15 22:25:04 +02:00
J-Jamet
22d1442033 fix: Screenshot banner #1770 2024-05-15 22:05:31 +02:00
J-Jamet
ffa32a5501 fix: Entry validation button not accessible with the keyboard open #1770 2024-05-15 21:24:01 +02:00
J-Jamet
f50a6a8416 fix: Remove the "merge, reload" wording in read only mode #1709 2024-05-15 19:19:18 +02:00
bowornsin
7a82b75ee2 Translated using Weblate (Thai)
Currently translated at 90.1% (593 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2024-05-15 07:01:51 +00:00
NicolaeFericitu
350c0585b8 Translated using Weblate (Romanian)
Currently translated at 98.1% (646 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-05-15 07:01:51 +00:00
J-Jamet
5c4454d3ed fix: Nav header margin 2024-05-14 16:32:13 +02:00
J-Jamet
dfd1ae7a50 fix:
Removing a file from recents list doesn't remove star #1755
2024-05-14 15:16:53 +02:00
J-Jamet
d16fdd062f fix: F-Droid logotype #1814 2024-05-14 14:22:50 +02:00
J-Jamet
d6432698fc Merge branch 'yurtpage-i18n' into develop 2024-05-13 13:17:38 +02:00
J-Jamet
1a9c1e8bc1 Merge branch 'i18n' of github.com:yurtpage/KeePassDX into yurtpage-i18n 2024-05-13 13:17:20 +02:00
J-Jamet
2d05c6cb13 fix:
Coordinator layout to show the Snackbar error
2024-05-13 12:40:02 +02:00
J-Jamet
05f689913f fix:
Database is 0 Byte if Yubikey save is canceled #1680
2024-05-13 12:16:42 +02:00
J-Jamet
9e714c4192 fix:
Database is 0 Byte if Yubikey save is canceled #1680
2024-05-13 11:38:16 +02:00
J-Jamet
e1ad1e31f8 Gemfile 2024-05-13 09:50:02 +02:00
109247019824
b473bf1da8 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-05-09 13:33:28 +02:00
Milo Ivir
dfdc6eecb6 Translated using Weblate (Croatian)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2024-05-09 13:33:28 +02:00
ngocanhtve
e9145df77a Translated using Weblate (Vietnamese)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2024-05-07 14:07:14 +02:00
Pavel
4e824990d1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2024-05-07 14:07:13 +02:00
Wellington Terumi Uemura
5a053378e1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2024-05-07 14:07:12 +02:00
J-Jamet
e09306b6f3 Merge remote-tracking branch 'origin/develop' into develop 2024-05-06 16:15:44 +02:00
J-Jamet
21e577c1d3 fix: Change version to 4.0.6 2024-05-06 16:15:30 +02:00
searinminecraft
9d85d0979c Translated using Weblate (Filipino)
Currently translated at 14.4% (95 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fil/
2024-05-05 16:07:16 +02:00
Linerly
e4fec7ea1f Translated using Weblate (Indonesian)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2024-05-05 16:07:12 +02:00
Fjuro
c998e513fc Translated using Weblate (Czech)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2024-05-05 16:07:11 +02:00
searinminecraft
855b06c4b2 Added translation using Weblate (Filipino) 2024-05-05 05:34:40 +02:00
Oğuz Ersen
776012f02f Translated using Weblate (Turkish)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2024-05-04 15:07:23 +02:00
何意挽秋風
9bff531618 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2024-05-04 15:07:22 +02:00
DVXG
4d64818da1 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2024-05-04 15:07:21 +02:00
qx100
837c8773a8 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2024-05-04 15:07:20 +02:00
solokot
97a199b504 Translated using Weblate (Russian)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-05-04 15:07:19 +02:00
Matthaiks
9cd37be5b1 Translated using Weblate (Polish)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2024-05-04 15:07:18 +02:00
Stephan Paternotte
90895fed52 Translated using Weblate (Dutch)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2024-05-04 15:07:17 +02:00
gallegonovato
df4b73abbb Translated using Weblate (Spanish)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2024-05-04 15:07:15 +02:00
ΣΤΑΥΡΟΣ ΔΑΛΙΑΚΟΠΟΥΛΟΣ
d2bed08ae0 Translated using Weblate (Greek)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2024-05-04 15:07:14 +02:00
Masowick
fd5e1472e1 Translated using Weblate (German)
Currently translated at 100.0% (658 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-05-04 15:07:13 +02:00
Anonymous
6a22126006 Translated using Weblate (Romanian)
Currently translated at 97.8% (644 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-05-03 14:38:37 +02:00
Anonymous
ff5e9049a0 Translated using Weblate (German)
Currently translated at 99.5% (655 of 658 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-05-03 14:38:36 +02:00
J-Jamet
7570aa9f49 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2024-05-03 14:32:56 +02:00
J-Jamet
4fcdd3da23 Merge branch 'develop' of github.com:Kunzisoft/KeePassDX into develop 2024-05-03 14:07:35 +02:00
qx100
f8a65b4d13 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2024-05-02 09:45:46 +02:00
Yurt Page
5bb70a5043 fastlane i18n ru
Signed-off-by: Yurt Page <yurtpage@gmail.com>
2024-04-23 19:18:09 +03:00
J-Jamet
c4788159e4 Merge branch 'thekyber-patch-1' into develop 2024-04-22 17:13:16 +02:00
J-Jamet
403b0aedca Merge branch 'ngocanhtve-master' into develop 2024-04-22 17:06:56 +02:00
TheKyber
cae12b84df better way to verify github apk files
Verifying the signing certificate hash is way better than verifying the hash of the apk files, because it does not change at all, and it will be very noticeable if it was changed from the README.md file than just GitHub release notes.

And you will not have to calculate the hash and publish it in the future, so less work for you.
2024-04-19 13:52:26 +01:00
J-Jamet
40dbbbf0a0 fix: Recognize Brave forms 2024-04-19 13:41:58 +02:00
Champ0999
9e0da27484 Translated using Weblate (English (United Kingdom))
Currently translated at 35.2% (228 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en_GB/
2024-04-18 18:03:25 +02:00
Gia Huy Lữ
7e6c2463d6 Translated using Weblate (Vietnamese)
Currently translated at 43.2% (280 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2024-04-18 18:03:24 +02:00
Thomas
69a76db166 Translated using Weblate (Chinese (Traditional))
Currently translated at 93.1% (603 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2024-04-18 18:03:24 +02:00
devchung
efd282e326 Translated using Weblate (Yue (Traditional))
Currently translated at 20.7% (134 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/yue_Hant/
2024-04-17 14:33:37 +02:00
devchung
6471fef28c Translated using Weblate (Chinese (Traditional))
Currently translated at 92.5% (599 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2024-04-17 14:33:36 +02:00
devchung
5a0691b70c Added translation using Weblate (Yue (Traditional)) 2024-04-17 08:21:39 +02:00
J-Jamet
27ea357348 fix: Fix username recognition with firefox #1665 2024-04-14 20:44:51 +02:00
bowornsin
e12de29cce Translated using Weblate (Thai)
Currently translated at 91.8% (594 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2024-04-12 06:01:55 +02:00
Rasmus
a236be4e38 Translated using Weblate (Danish)
Currently translated at 99.0% (641 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2024-04-05 14:01:53 +02:00
SpaceFrrog
5300643f62 Translated using Weblate (English (United Kingdom))
Currently translated at 25.9% (168 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en_GB/
2024-04-04 09:43:58 +02:00
SpaceFrrog
469b837daf Translated using Weblate (German)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-04-04 09:43:57 +02:00
Ghost of Sparta
84ca3e8982 Translated using Weblate (Hungarian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2024-03-28 12:02:02 +01:00
Tim Trek
bfb8be159a Translated using Weblate (German)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2024-03-19 07:09:23 +01:00
bowornsin
13d7af9c76 Translated using Weblate (Thai)
Currently translated at 91.6% (593 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2024-03-17 08:43:10 +01:00
David C
66d78497b9 Translated using Weblate (Slovenian)
Currently translated at 10.2% (66 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sl/
2024-03-08 14:01:54 +01:00
109247019824
32743f7e19 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-03-06 22:01:44 +01:00
109247019824
c2cc4451ff Translated using Weblate (Bulgarian)
Currently translated at 95.0% (615 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-03-05 15:02:38 +01:00
109247019824
67370bbc3d Translated using Weblate (Bulgarian)
Currently translated at 84.8% (549 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-03-04 08:01:48 +01:00
Lenni
1201ae1956 Translated using Weblate (English (United Kingdom))
Currently translated at 25.1% (163 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en_GB/
2024-03-03 07:01:51 +01:00
109247019824
0eb2786ce5 Translated using Weblate (Bulgarian)
Currently translated at 82.3% (533 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-03-03 07:01:50 +01:00
109247019824
bbdeb66f8e Translated using Weblate (Bulgarian)
Currently translated at 78.3% (507 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-03-02 06:02:00 +01:00
J-Jamet
641698a652 Merge branch 'MDP43140-master' into develop 2024-03-01 17:24:16 +01:00
J-Jamet
15880e995a Merge branch 'master' of github.com:MDP43140/KeePassDX into MDP43140-master 2024-03-01 17:23:54 +01:00
J-Jamet
1e849b106b Merge branch 'Rilele-master' into develop 2024-03-01 16:36:42 +01:00
109247019824
31bc405e86 Translated using Weblate (Bulgarian)
Currently translated at 73.1% (473 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-02-29 23:02:09 +01:00
109247019824
6e69eee2a3 Translated using Weblate (Bulgarian)
Currently translated at 69.2% (448 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-02-27 20:49:46 +01:00
109247019824
279b095f30 Translated using Weblate (Bulgarian)
Currently translated at 62.1% (402 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-02-27 12:02:02 +01:00
109247019824
9821499cdb Translated using Weblate (Bulgarian)
Currently translated at 36.9% (239 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-02-26 08:02:03 +01:00
--//--
b76c39862a Translated using Weblate (Burmese)
Currently translated at 6.8% (44 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/my/
2024-02-23 16:01:59 +01:00
adfc
7948d234f5 Translated using Weblate (English (United Kingdom))
Currently translated at 13.9% (90 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en_GB/
2024-02-23 16:01:58 +01:00
109247019824
50fc3aa9fc Translated using Weblate (Bulgarian)
Currently translated at 20.2% (131 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-02-23 16:01:57 +01:00
adfc
79a7adb05b Translated using Weblate (Hindi)
Currently translated at 22.7% (147 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hi/
2024-02-23 16:01:56 +01:00
Besnik Bleta
c02770ec2a Translated using Weblate (Albanian)
Currently translated at 55.9% (362 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sq/
2024-02-22 13:02:04 +01:00
Elvis
bf24033513 Translated using Weblate (Uzbek)
Currently translated at 7.5% (49 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uz/
2024-02-18 20:02:04 +01:00
solokot
d97c87e90c Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-02-18 20:02:02 +01:00
Elvis
6d29fdc448 Translated using Weblate (Uzbek)
Currently translated at 4.3% (28 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uz/
2024-02-17 19:39:44 +01:00
Elvis
d16f0dd3f6 Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-02-17 19:39:43 +01:00
Elvis
d023c97049 Added translation using Weblate (Uzbek) 2024-02-17 19:08:49 +01:00
jonnysemon
73c8d63f0e Translated using Weblate (Arabic)
Currently translated at 99.3% (643 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2024-02-07 11:52:29 +01:00
Salif Mehmed
30709de7e2 Translated using Weblate (Bulgarian)
Currently translated at 20.0% (130 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-02-06 23:01:53 +01:00
Salif Mehmed
c3e560766e Translated using Weblate (Bulgarian)
Currently translated at 17.9% (116 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2024-02-05 13:01:51 +01:00
Aleksandar Sazdanović
7c7889e87e Translated using Weblate (Serbian (latin))
Currently translated at 37.0% (240 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sr_Latn/
2024-02-04 12:01:59 +01:00
Pere O
6547ccecdd Translated using Weblate (Catalan)
Currently translated at 97.9% (634 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ca/
2024-02-03 09:35:48 +01:00
Pere O
d467a591b0 Translated using Weblate (Catalan)
Currently translated at 65.3% (423 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ca/
2024-02-01 23:01:52 +01:00
solokot
42613ff480 Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2024-01-21 10:01:50 +01:00
NicolaeFericitu
3a3d4b9e54 Translated using Weblate (Romanian)
Currently translated at 99.6% (645 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-01-15 17:06:12 +01:00
NicolaeFericitu
0b5c0bcf74 Translated using Weblate (Romanian)
Currently translated at 88.4% (572 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-01-09 23:06:34 +00:00
Deleted User
5937f009e1 Translated using Weblate (Danish)
Currently translated at 98.4% (637 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2024-01-09 23:06:13 +00:00
SC
c7f3d2a64e Translated using Weblate (Portuguese)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2024-01-06 17:06:11 +01:00
NicolaeFericitu
41263307d7 Translated using Weblate (Romanian)
Currently translated at 78.0% (505 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2024-01-06 17:06:11 +01:00
SC
f2ff52477e Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2024-01-06 17:06:11 +01:00
Mike
6baa5a0730 Translated using Weblate (Slovak)
Currently translated at 95.0% (615 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sk/
2023-12-31 18:36:23 +01:00
ERYpTION
5a5cb8c866 Translated using Weblate (Danish)
Currently translated at 96.9% (627 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2023-12-08 20:03:49 +00:00
Kenny
a3a78366f7 Translated using Weblate (Romanian)
Currently translated at 76.3% (494 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2023-12-06 15:11:11 +01:00
ngocanhtve
d936292ed9 Updated vi\strings.xml
Complete the Vietnamese translation.
2023-12-01 21:35:47 +07:00
ngocanhtve
a3ded18f59 Translated using Weblate (Vietnamese)
Currently translated at 38.3% (248 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2023-12-01 14:14:44 +01:00
Avi Parshan
0969135f7f Translated using Weblate (Hebrew)
Currently translated at 44.9% (291 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2023-11-27 18:02:20 +00:00
Rilele
7e1c1a6324 Fix German translation 2023-11-25 13:02:36 +01:00
J-Jamet
aa43dd2a49 fix: Upgrade to 4.1.0 2023-11-10 23:00:34 +01:00
J-Jamet
81fe9b6fc2 fix: phone field recognition 2023-11-10 22:56:23 +01:00
J-Jamet
6807fdc1cc Merge tag '4.0.5' into develop
4.0.5
2023-11-09 08:16:36 +01:00
J-Jamet
ac1590810f Merge branch 'release/4.0.5' 2023-11-09 08:16:29 +01:00
J-Jamet
9dd4d77535 fix: upgrade version 2023-11-09 08:06:30 +01:00
J-Jamet
c7aa6a9d96 fix: revert #1490 2023-11-09 08:02:16 +01:00
J-Jamet
fc56db2f83 fix: Autofill recognition 2023-11-08 20:43:50 +01:00
MDP43140
c58e56257d Fix Indonesia language
language code for Indonesia is apparently `in` instead of `id` in Java, thus makes the app displays default English language for users with Indonesian language. a simple folder rename should hopefully fix this
2023-11-07 23:27:49 +07:00
solokot
b27eb280a8 Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2023-11-07 10:11:49 +01:00
J-Jamet
78c7f4078c Merge tag '4.0.4' into develop
4.0.4
2023-11-07 00:33:28 +01:00
J-Jamet
28ccaffcf5 Merge branch 'release/4.0.4' 2023-11-07 00:33:15 +01:00
J-Jamet
78739558d6 fix: password color #1490 2023-11-07 00:26:24 +01:00
J-Jamet
cd195d30de fix: update CHANGELOG 2023-11-06 23:49:58 +01:00
J-Jamet
03bf752284 fix: update CHANGELOG 2023-11-06 23:48:39 +01:00
J-Jamet
238fab3e1d fix: device unlock #1682 2023-11-06 23:47:31 +01:00
J-Jamet
fcd9af8f84 Revert "Revert "fix: Remove Lock in Autofill""
This reverts commit b44491ebbe.
2023-11-06 23:37:28 +01:00
J-Jamet
b44491ebbe Revert "fix: Remove Lock in Autofill"
This reverts commit 544f7003f6.
2023-11-06 23:35:14 +01:00
J-Jamet
1f8018fd5b fix: autofill 2023-11-06 23:23:42 +01:00
J-Jamet
1d67656fa0 fix: autofill 2023-11-06 22:40:48 +01:00
J-Jamet
64b8023d1a fix: upgrade version and CHANGELOG 2023-11-06 21:40:01 +01:00
J-Jamet
cc1697e7ec fix: last form field recognition #1572 2023-11-06 21:37:27 +01:00
J-Jamet
28943e77e8 Merge tag '4.0.3' into develop
4.0.3
2023-11-06 12:29:02 +01:00
J-Jamet
575109da9f Merge branch 'release/4.0.3' 2023-11-06 12:28:53 +01:00
J-Jamet
a99667d471 feat: New fastfile to build Libre in github 2023-11-06 12:28:28 +01:00
J-Jamet
6a7420bd3a fix: replace tags 2023-11-06 10:45:20 +01:00
J-Jamet
e8dbe05615 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2023-11-06 10:35:53 +01:00
J-Jamet
6b6566cd29 fix: small change #1674 2023-11-06 08:58:36 +01:00
J-Jamet
0001d31c2c fix: small change #1674 2023-11-06 08:57:48 +01:00
J-Jamet
974686e698 fix: small changes 2023-11-04 18:56:36 +01:00
J-Jamet
7b7063b9be fix: check biometric unlock availability before build the fragment #1400 2023-11-04 18:14:24 +01:00
J-Jamet
55061a9469 fix: runtime exception #1649 2023-11-04 18:01:23 +01:00
J-Jamet
c433fb643c fix: change password color dynamically #1490 2023-11-04 17:33:40 +01:00
J-Jamet
02306385b6 fix: #1641 #1656 2023-11-04 16:09:10 +01:00
J-Jamet
432ac1bcec Merge branch 'JohnVeness-biometric' into develop 2023-11-04 16:07:41 +01:00
J-Jamet
d9480e0c9a Merge branch 'MkQtS-f-droid-link' into develop 2023-11-04 16:05:24 +01:00
J-Jamet
815fb911d6 fix: regex OTP recognition #1596 2023-11-04 16:03:20 +01:00
J-Jamet
68cbdae8e0 fix: update CHANGELOG 2023-11-04 15:07:15 +01:00
J-Jamet
2d8f8aeef3 fix: Compatibility mode to retrieve username #1508 2023-11-04 13:02:57 +01:00
J-Jamet
479bc7be71 Upgrade to 4.0.3 2023-11-04 11:36:44 +01:00
/dev/urandom
cbc6df2e62 Translated using Weblate (Esperanto)
Currently translated at 21.9% (142 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eo/
2023-11-03 06:10:15 +01:00
Urystem
d16b4cfadb Added translation using Weblate (Kazakh) 2023-10-31 12:48:01 +01:00
ngocanhtve
a97bad1f86 Translated using Weblate (Vietnamese)
Currently translated at 34.4% (223 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2023-10-30 07:09:19 +01:00
J-Jamet
7198ffff43 fix: Save as 2023-10-29 20:45:35 +01:00
ngocanhtve
e173159d13 Translated using Weblate (Vietnamese)
Currently translated at 33.3% (216 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2023-10-28 17:33:10 +02:00
Jean Mareilles
1b54b79e88 Translated using Weblate (French)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2023-10-27 11:26:36 +02:00
P.O
bb3436615e Translated using Weblate (Swedish)
Currently translated at 60.1% (389 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sv/
2023-10-16 04:19:17 +00:00
Stasky745
809db61c35 Translated using Weblate (Catalan)
Currently translated at 62.4% (404 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ca/
2023-10-16 04:19:16 +00:00
elgratea
88e53fcba8 Translated using Weblate (Bulgarian)
Currently translated at 13.1% (85 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2023-10-13 21:02:05 +02:00
Balázs Meskó
fe68b7e294 Translated using Weblate (Hungarian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2023-10-08 16:01:48 +02:00
Åzze
b7b76d6da7 Translated using Weblate (Finnish)
Currently translated at 39.7% (257 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fi/
2023-10-08 16:01:48 +02:00
Fjuro
e2eae43fc9 Translated using Weblate (Czech)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2023-10-08 16:01:47 +02:00
bowornsin
f41ecec09c Translated using Weblate (Thai)
Currently translated at 91.4% (592 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2023-10-02 02:01:14 +02:00
John Veness
15ad4d11ef Fix paragraph break in Biometric warning text
Added an extra new line between the last two paragraphs, for consistency with the paragraphs above.
2023-10-01 21:07:54 +01:00
P.O
0cf9d98f14 Translated using Weblate (Swedish)
Currently translated at 59.3% (384 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sv/
2023-09-29 18:35:22 +02:00
elgratea
612e642523 Translated using Weblate (Bulgarian)
Currently translated at 9.8% (64 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2023-09-19 22:59:13 +02:00
Milo Ivir
0ff77eb157 Translated using Weblate (Croatian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2023-09-18 17:01:16 +00:00
Alexthegib
2b8935a5d7 Translated using Weblate (Portuguese)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2023-09-16 02:53:56 +02:00
Mesut Akcan
afdc5c8460 Translated using Weblate (Turkish)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2023-09-13 15:48:51 +02:00
alejandracios
91ba2dff2d Translated using Weblate (Spanish)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2023-09-13 15:48:50 +02:00
MkQtS
2d26079c49 readme: don't specify language in F-droid links
then F-droid will follow the browser locale
2023-09-13 19:16:43 +08:00
J-Jamet
f13d99e0d1 Merge tag '4.0.2' into develop
4.0.2
2023-09-11 21:55:56 +02:00
J-Jamet
798c95d8a8 Merge branch 'release/4.0.2' 2023-09-11 21:55:48 +02:00
J-Jamet
ef77c2acfb fix: Add buggy method comment #1638 2023-09-11 21:38:12 +02:00
J-Jamet
11a98267a2 fix: Upgrade to 4.0.2 2023-09-11 21:17:18 +02:00
J-Jamet
b2aa1155d0 fix: Autofill authentication 2023-09-11 21:13:26 +02:00
Linerly
d3182b8d2a Translated using Weblate (Indonesian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2023-09-11 19:51:53 +02:00
jonnysemon
f52d139acc Translated using Weblate (Arabic)
Currently translated at 97.5% (631 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2023-09-11 19:51:53 +02:00
Eric
87e9a38548 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2023-09-11 19:51:52 +02:00
Ihor Hordiichuk
faa70c57b3 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2023-09-11 19:51:52 +02:00
Alexthegib
5172c07c18 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2023-09-11 19:51:51 +02:00
Wellington Terumi Uemura
a80fa03db4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2023-09-11 19:51:51 +02:00
Matthaiks
d73e02948e Translated using Weblate (Polish)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2023-09-11 19:51:51 +02:00
Stephan Paternotte
283657e1b7 Translated using Weblate (Dutch)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2023-09-11 19:51:50 +02:00
Random
d3c4a3a17e Translated using Weblate (Italian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2023-09-11 19:51:50 +02:00
Kunzisoft
9184bc40e5 Translated using Weblate (French)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2023-09-11 19:51:50 +02:00
gallegonovato
84bd98ebf4 Translated using Weblate (Spanish)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2023-09-11 19:51:49 +02:00
Retrial
4ef2cbcaeb Translated using Weblate (Greek)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2023-09-11 19:51:49 +02:00
Fjuro
35f8b45bf4 Translated using Weblate (Czech)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2023-09-11 19:51:48 +02:00
J-Jamet
5d6aac2d1b Merge tag '4.0.1' into develop
4.0.1
2023-09-10 11:07:13 +02:00
J-Jamet
c6723ecd4e Merge branch 'release/4.0.1' 2023-09-10 11:07:06 +02:00
J-Jamet
838c8f48d3 fix: Translation for themes #1631 2023-09-10 10:53:43 +02:00
J-Jamet
65229fae1f fix: Lock button in Autofill settings and Magikeyboard settings #1630 2023-09-10 10:26:01 +02:00
J-Jamet
f25ea89160 fix: Add CHANGELOG link 2023-09-10 09:57:56 +02:00
J-Jamet
18401d5d1e fix: Upgrade to 4.0.1 2023-09-10 09:50:26 +02:00
J-Jamet
1f2cf08108 fix: back lock 2023-09-10 09:43:08 +02:00
J-Jamet
74e86badba Merge tag '4.0.0' into develop
4.0.0
2023-09-09 21:34:37 +02:00
J-Jamet
31444a823e Merge branch 'release/4.0.0' 2023-09-09 21:34:28 +02:00
J-Jamet
068933f0fb fix: fastlane changelog version 2023-09-09 21:30:51 +02:00
J-Jamet
f496711280 Replace art screen 2023-09-09 21:24:40 +02:00
J-Jamet
657d2420d6 Revert "fix: Small bug"
This reverts commit 2467721265.
2023-09-09 21:21:04 +02:00
J-Jamet
2467721265 fix: Small bug 2023-09-09 21:11:39 +02:00
J-Jamet
d37fbb9992 fix: Change screenshot 2023-09-09 21:06:33 +02:00
J-Jamet
19b8b54dae fix: Strong tag 2023-09-08 21:22:55 +02:00
J-Jamet
84328caf3c fix: Add browsers to compatibility package 2023-09-08 21:22:36 +02:00
J-Jamet
a0bdfc973a Merge branch 'translations' into develop 2023-09-08 21:16:04 +02:00
J-Jamet
1f91854490 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2023-09-08 21:15:42 +02:00
J-Jamet
1380325b66 Upgrade to 4.0.0 2023-09-08 21:14:21 +02:00
J-Jamet
d244eef62e feat: Add recursive number of entries #874 #1327 2023-09-08 20:32:19 +02:00
Hosted Weblate
8fb8d9ed37 Merge branch 'origin/develop' into Weblate. 2023-09-08 19:35:10 +02:00
J-Jamet
8ce63cb5c5 Merge branch 'JohnVeness-master' into develop 2023-09-08 19:31:49 +02:00
J-Jamet
9ecf2ae942 Merge branch 'master' of github.com:JohnVeness/KeePassDX into JohnVeness-master 2023-09-08 19:31:07 +02:00
J-Jamet
544f7003f6 fix: Remove Lock in Autofill 2023-09-04 20:45:32 +02:00
J-Jamet
6d633c9986 fix: Autofill implementation 2023-09-04 19:16:16 +02:00
J-Jamet
1e77a42c93 fix: Remove Autofill deprecation 2023-09-03 18:41:32 +02:00
J-Jamet
d1f2641e40 fix: On back pressed deprecation 2023-09-03 12:29:45 +02:00
jonnysemon
4b8ae154cc Translated using Weblate (Arabic)
Currently translated at 97.6% (632 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2023-08-29 18:57:00 +02:00
J-Jamet
0c1aacdf83 fix: Navigation bar margin 2023-08-28 21:52:51 +02:00
J-Jamet
5f34df3549 fix: Ellipsis 2023-08-28 17:20:09 +02:00
Alexandru
f2e6aa1abb Translated using Weblate (Romanian)
Currently translated at 72.9% (472 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2023-08-28 10:53:32 +02:00
John Veness
866731df81 Correct "im/exportation" wording 2023-08-20 19:39:09 +01:00
John Veness
5d931e09d5 Changed "app properties" wording to "app settings" 2023-08-20 19:08:51 +01:00
Kunzisoft
fe17c21c01 Translated using Weblate (French)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2023-08-20 11:52:19 +02:00
J-Jamet
085941019e fix: Small bugs 2023-08-19 19:58:26 +02:00
J-Jamet
24b3758545 feat: Entry Edit Activity Fit Window 2023-08-19 19:16:55 +02:00
J-Jamet
9083f99325 feat: Entry Activity Fit Window 2023-08-19 18:15:21 +02:00
J-Jamet
2189be9267 fix: Screenshot mode 2023-08-19 17:47:49 +02:00
J-Jamet
43218eede1 feat: Group screen as fit window 2023-08-19 17:00:26 +02:00
J-Jamet
d1a176d27d fix: Small UI 2023-08-19 12:25:38 +02:00
J-Jamet
cf51af91bf feat: Logo color 2023-08-19 12:20:41 +02:00
Darin Avdeyeva
02ff1188b2 Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2023-08-18 15:54:40 +02:00
jonnysemon
0fac9b6864 Translated using Weblate (Arabic)
Currently translated at 97.5% (631 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2023-08-17 01:55:03 +02:00
VfBFan
b550830c30 Translated using Weblate (German)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-08-15 11:47:13 +02:00
gallegonovato
6f485dd298 Translated using Weblate (Spanish)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2023-08-12 10:53:07 +02:00
solokot
b0dfde62c7 Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2023-08-09 17:50:55 +02:00
109247019824
686dae0af6 Translated using Weblate (Bulgarian)
Currently translated at 2.9% (19 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2023-08-08 17:21:18 +02:00
Darin Avdeyeva
ee3eabe8c8 Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2023-08-08 17:21:18 +02:00
C. Rüdinger
521c8aa6a9 Translated using Weblate (German)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-08-08 17:21:17 +02:00
solokot
66207d599f Translated using Weblate (Russian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2023-08-08 08:51:37 +02:00
Masowick
e0029e0c3f Translated using Weblate (German)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-08-08 08:51:37 +02:00
C. Rüdinger
3683b64721 Translated using Weblate (German)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-08-08 08:51:37 +02:00
J-Jamet
8d4a0971f9 Merge tag '4.0.0beta02' into develop
4.0.0beta02
2023-08-07 16:00:38 +02:00
Hosted Weblate
d212fa180b Merge branch 'origin/develop' into Weblate. 2023-08-06 23:00:27 +02:00
Salif Mehmed
bc4ea2ec2a Translated using Weblate (Bulgarian)
Currently translated at 2.7% (18 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bg/
2023-08-06 23:00:27 +02:00
Linerly
5d8c80fc1e Translated using Weblate (Indonesian)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2023-08-06 23:00:27 +02:00
Alexandru
a02714ff6e Translated using Weblate (Romanian)
Currently translated at 63.5% (411 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2023-08-06 23:00:26 +02:00
Fjuro
4bd952e223 Translated using Weblate (Czech)
Currently translated at 100.0% (647 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2023-08-06 23:00:25 +02:00
J-Jamet
0474e5b1fe Merge branch 'Sandelinos-themed-icons' into develop 2022-09-29 16:44:43 +02:00
232 changed files with 9900 additions and 3204 deletions

View File

@@ -1,11 +1,65 @@
KeePassDX(4.1.1)
* Fix date parser #1933
* Fix domain search #1820 #1936
KeePassDX(4.1.0)
* Generate keyfile #1290
* Hide template group #1894
* Group count sum recursively #421
* Fix date fields #1695 #1710
* Fix distinct domain names #1105 #1820
* Resets the advanced unlock expiration #1600
* Password entropy #1490 #1355
* Upgrade to API 34 (Android 14) #1730
* Small fixes #1711 #1831 #1780 #1821 #1863 #1889 #1289 #1600 #1467 #1870
KeePassDX(4.0.8)
* Fix graphical bug that prevented databases from being opened on some versions of Android #1848 #1850
KeePassDX(4.0.7)
* Prevent 0 Byte file with cache during a save exception #1620 #1594 #1680
* Fix inline suggestions in keyboard #1840
* Fix broken links by default #1755
* Fix UX by allowing validation in entry edition #1770
* Fix small bugs #1709
KeePassDX(4.0.6)
* Fix form filled recognition #1508 #1735 #1508 #1790 #1783 #1797 #1801 #1802 #1804 #1665
* Fix translations #1707 #1683 #1712
* Update APK verifier #1810
KeePassDX(4.0.5)
* Fix form filled recognition #1572 #1508
* Rollback password color #1686 #1490
KeePassDX(4.0.4)
* Fix form filled recognition #1572 #1677
* Fix device unlock #1682
* Fix password color #1490
KeePassDX(4.0.3)
* Fix "Save as" in Read Only mode #1666
* Fix username autofill #1665 #530 #1572 #1426 #1523 #1556 #1653 #1658 #1508 #1667
* Fix regex OTP recognition #1596
* Change password color dynamically #1490
* Small fixes #1641 #1656 #1649 #1400 #1674
KeePassDX(4.0.2)
* Fix Autofill with API 33
KeePassDX(4.0.1)
* Fix back lock #1635 #1629 #1634
* Fix lock button in settings #1630
* Improve theme translation #1631
KeePassDX(4.0.0)
* New UX/UI with Material 3 #1183 #1529 #1428 #1441 #1607
* Material You theme (follow system colors) #1469
* Refactoring inner code #1371
* Migration to API 33
# Cut, copy and delete from search #891 #1308 #1263
* Fix behaviors #1351
* Fix bugs #1589 #1584 #1545 #1563 #1371
* Cut, copy and delete from search #891 #1308 #1263
* Fix behaviors #1351 #874 #1327
* Fix bugs #1589 #1584 #1545 #1563 #1371 #1609
KeePassDX(3.5.1)
* Fix action dialog with YubiKey challenge-response #1506

View File

@@ -1,29 +1,32 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.6)
CFPropertyList (3.0.7)
base64
nkf
rexml
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
artifactory (3.0.15)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.794.0)
aws-sdk-core (3.180.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
aws-eventstream (1.3.0)
aws-partitions (1.1009.0)
aws-sdk-core (3.213.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.71.0)
aws-sdk-core (~> 3, >= 3.177.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.132.0)
aws-sdk-core (~> 3, >= 3.179.0)
aws-sdk-kms (1.95.0)
aws-sdk-core (~> 3, >= 3.210.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.171.0)
aws-sdk-core (~> 3, >= 3.210.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.6)
aws-sigv4 (1.6.0)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.10.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.2.0)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
@@ -32,12 +35,11 @@ GEM
declarative (0.0.20)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.100.0)
faraday (1.10.3)
excon (0.112.0)
faraday (1.10.4)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -58,22 +60,22 @@ GEM
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http (1.0.2)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday_middleware (1.2.1)
faraday (~> 1.0)
fastimage (2.2.7)
fastlane (2.214.0)
fastimage (2.3.1)
fastlane (2.225.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
colored (~> 1.2)
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
@@ -82,34 +84,39 @@ GEM
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
fastlane-sirp (>= 1.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
optparse (>= 0.1.1, < 1.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
security (= 0.1.5)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-versioning_android (0.1.0)
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
fastlane-plugin-versioning_android (0.1.1)
fastlane-sirp (1.0.0)
sysrandom (~> 1.0)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.46.0)
google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.1)
google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -117,64 +124,63 @@ GEM
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-apis-storage_v1 (0.31.0)
google-apis-core (>= 0.11.0, < 2.a)
google-cloud-core (1.7.1)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.1)
google-cloud-storage (1.44.0)
google-cloud-errors (1.4.0)
google-cloud-storage (1.47.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.19.0)
google-apis-storage_v1 (~> 0.31.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.7.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.5)
http-cookie (1.0.7)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.2)
json (2.6.3)
jwt (2.7.1)
memoist (0.16.2)
mini_magick (4.12.0)
mini_mime (1.1.2)
json (2.8.2)
jwt (2.9.3)
base64
mini_magick (4.13.2)
mini_mime (1.1.5)
multi_json (1.15.0)
multipart-post (2.3.0)
nanaimo (0.3.0)
multipart-post (2.4.1)
nanaimo (0.4.0)
naturally (2.2.1)
optparse (0.1.1)
nkf (0.2.0)
optparse (0.6.0)
os (1.1.4)
plist (3.7.0)
public_suffix (5.0.3)
rake (13.0.6)
plist (3.7.1)
public_suffix (6.0.1)
rake (13.2.1)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.6)
rexml (3.3.9)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.17.0)
security (0.1.5)
signet (0.19.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
@@ -182,28 +188,25 @@ GEM
simctl (1.6.10)
CFPropertyList
naturally
sysrandom (1.0.5)
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.8.1)
unicode-display_width (2.6.0)
word_wrap (1.0.0)
xcodeproj (1.22.0)
xcodeproj (1.27.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
nanaimo (~> 0.4.0)
rexml (>= 3.3.6, < 4.0)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
@@ -217,4 +220,4 @@ DEPENDENCIES
fastlane-plugin-versioning_android
BUNDLED WITH
2.1.4
2.5.10

View File

@@ -1,8 +1,8 @@
# Android KeePassDX
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/icon.png"> **Lightweight password manager for Android**, KeePassDX allows editing encrypted data in a single file in KeePass format and fill in the forms in a secure way.
<img alt="KeePassDX Icon" src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/icon.png"> **Lightweight password safe and manager for Android**, KeePassDX allows editing encrypted data in a single file in KeePass format and fill in the forms in a secure way.
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen.jpg" width="220">
<img alt="KeePassDX Screenshot" src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen.jpg" width="220">
### Features
@@ -48,18 +48,40 @@ Optional visual styles are accessible after a contribution (and a congratulatory
## Download
*[F-Droid](https://f-droid.org/en/packages/com.kunzisoft.keepass.libre/) is the recommended way of installing, a libre software project that verifies that all the libraries and app code is libre software.*
*[F-Droid](https://f-droid.org/packages/com.kunzisoft.keepass.libre/) is the recommended way of installing, a libre software project that verifies all the libraries and app code is libre software.*
| Source | Status | [Version](https://github.com/Kunzisoft/KeePassDX/wiki/FAQ#why-a-libre-and-free-version) |
|--------|--------|---------|
| [Google Play](https://play.google.com/store/apps/details?id=com.kunzisoft.keepass.free) | ![Google Play Release](https://img.shields.io/endpoint?color=blue&logo=google-play&logoColor=green&url=https%3A%2F%2Fplay.cuzi.workers.dev%2Fplay%3Fi%3Dcom.kunzisoft.keepass.free%26gl%3DUS%26hl%3Den%26l%3DGoogle%2520Play%26m%3D%24version) | Free + [Pro](https://play.google.com/store/apps/details?id=com.kunzisoft.keepass.pro) |
| [F-Droid](https://f-droid.org/en/packages/com.kunzisoft.keepass.libre/) | ![F-Droid Version](https://img.shields.io/f-droid/v/com.kunzisoft.keepass.libre?logo=F-Droid&label=F-Droid) | Libre |
| [IzzyOnDroid](https://apt.izzysoft.de/fdroid/index/apk/com.kunzisoft.keepass.free) | ![IzzyOnDroid Version](https://img.shields.io/endpoint?&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAADAFBMVEUA0////wAA0v8A0v8A0////wD//wAFz/QA0/8A0/8A0/8A0/8A0v///wAA0/8A0/8A0/8A0/8A0//8/gEA0/8A0/8B0/4A0/8A0/8A0/+j5QGAwwIA0//C9yEA0/8A0/8A0/8A0/8A0/8A0/+n4SAA0/8A0/8A0/+o6gCw3lKt7QCv5SC+422b3wC19AC36zAA0/+d1yMA0/8A0/+W2gEA0/+w8ACz8gCKzgG7+QC+9CFLfwkA0/8A0////wAA0/8A0/8A0/8A0/+f2xym3iuHxCGq5BoA1P+m2joI0vONyiCz3mLO7oYA0/8M1Piq3Ei78CbB8EPe8LLj9Ly751G77zWQ1AC96UYC0fi37CL//wAA0/8A0////wD//wCp3jcA0/+j3SGj2i/I72Sx4zHE8FLB8zak1kYeycDI6nRl3qEA0/7V7psA0v6WzTa95mGi2RvB5XkPy9zH5YJ3uwGV1yxVihRLiwdxtQ1ZkAf//wD//wD//wD//wD//wCn5gf//wD//wD//wD//wD//wAA0/+h4A3R6p8A0/+X1w565OD6/ARg237n9csz2vPz+gNt37V/vifO8HW68B/L6ZOCwxXY8KRQsWRzhExAtG/E612a1Rd/pTBpmR9qjysduKVhmxF9mTY51aUozK+CsDSA52T//wD//wAA0////wD//wBJ1JRRxFWjzlxDyXRc0pGT1wCG0CWB3VGUzSTh8h6c0TSr5CCJ5FFxvl6s4H3m8xML0/DA5CvK51EX1N+Y2gSt4Dag3ChE3fax2ki68yO57NF10FRZnUPl88eJxhuCxgCz5EOLwEGf1DFutmahzGW98x0W1PGk3R154MHE6bOn69qv3gy92oG90o+Hn07B7rhCmiyMwECv1nO+0pQfwrCo57xF2daXsVhKrEdenQAduaee1Bsjr42z5D9RoCXy+QNovXpy2Z5MtWDO/TiSukaF3UtE1K6j3B4YwLc5wXlzpyIK0u5zy3uJqg4pu5RTpkZmpVKyAP8A0wBHcExHcEyBUSeEAAABAHRSTlP///9F9wjAAxD7FCEGzBjd08QyEL39abMd6///8P/ZWAnipIv/cC6B//7////////L/1Dz/0D///////86/vYnquY3/v///5T//v///17///////////////84S3QNB/8L/////////////7r/////NP////9l/////wPD4yis/x7Ym2lWSP+em////0n////////v///////////////////7//7pdGN3Urr6/+v/6aT////+//H/o2P/1v+7r7jp4PM/3p4g////g///K///481LxO///v////9w////8v/////9/p3J///a+P9v/5KR/+n///+p/xf//8P//wAAe7FyaAAABCZJREFUSMdj+E8iYKBUgwIHnwQ3N7cEHxcH+///VayoAE0Dh41qR7aBnCIQ8MsJKHH9/99czYYMWlA0cIkJGjMgAKfq//9RNYzIgLcBWYOTiCgDMhDn+B9bh6LebiWyH6L5UZQzONoAHWSHoqEpDkkDsyKqelv1//9rG1HUN9YihZK9AKp6BkG+/6xNqA5ajhSsCkrIipmYGGRa//9vQXVQXSySBnkWJOUMfn5Myuz/G3hR1NdEIUUchwiy+bkTsg4dbW/fu6W/e1c3XMMy5JiOZkFxUFZo74mgKTqaKXu0+2HqVwkja3BH9kFu361JwcHTfPJD4mdfe8ULAdVRyGlJAcVFfg+CQOozZ4XrJ85+JgwBsVXIGriQw5Tp4ZScezd8JiWnBupru30qwJZa+ZAjmWlC8fUZM4qB6kPnLNSPLMWqQQ5ZQ5aOzs1HmamBaQHzFs6y+qAmJCTE8f9/QgKSBg4DJPWc6zVDQkIC09JkZSPD38kukpExFpT4z67uYI/QwCOOCCK/izvu5CWl6AcEWMnKWml7LWbKZfH9/99UkknQHhGsynDz+65eWXv3/JmJrq5eXienVlRUfH/z8VvCf45soKQIH1yDEQsszrp6gwq9C73T87xcXadKl5TkFev4A/2tygmSBqYXqAYJmK+ZuoJydDR1vP09DA0NOy2kpdML81+U/heCpH1JU3jig7lJ5nKOT4i/t6ZHkqGzs4lJmIVHfrj+JR4HqLQSD0yDkCNEpGNn5ix9D03/eJdElTZdKV2TpNOhkwt8YUlNUgimgV0dLMBvf1gz1MolPd5FRcVNSkpDQ8owJeBCDyIhrIDnOD5QcuIU+3/2QKSs9laQ+noNLS0zLWdtqyP7mBAFAw88TwsJgMuJYweBGjYngtWbmeuZOW+bvNQToUFOAlFqOBk4Ov3/L7Z60/aN0p1tUhpa5nqWlub7C3p2I9QzyAghlUvczOz/1fhzPT3XSIfpSmmYAdVbmm1gV0dSz8DSilpUQsqCddIWIA3meuZaJqdMJZEzl6gRqgZIWZAxUdoizERXN8yi5MltcZTChzMaRQM3JNUWHS8rL/+yaPGvMmvr5ywoGoxtkDWwQ+Pb89ycBeWfGSJeL/la+RS1eOPnRtbQKgMRjZg+t8x6PkP273nWQAoFOPAgaeAThKXAmXMrK39Kmr5fsuBlBqoXfJGLe3VbmHjG9Mczi9T//3h7vygXtcDlQtJg44iQiIjIBRbGPO7gghPJy0ZIxT2HOLIUgwxQzsgYrUR350HSIMaJLidhgKY+mw+pflBDrX8E7OGBjPCAPc76gQFSTqAIiYrb/8dRP4CyosJ/rmwU5XIxHMilt4QBJwsSkBMClxOQULBlkRRwEONmR2kJcDGjADX2/+xO8r5iqjExqmLyrWpcPFRta1BfAwCtyN3XpuJ4RgAAAABJRU5ErkJggg==&url=https://apt.izzysoft.de/fdroid/api/v1/shield/com.kunzisoft.keepass.free&label=IzzyOnDroid) | Free |
| [GitHub](https://github.com/Kunzisoft/KeePassDX/releases) / [Obtainium](https://github.com/ImranR98/Obtainium) | ![GitHub Release](https://img.shields.io/github/v/release/Kunzisoft/KeePassDX?include_prereleases&logo=GitHub&label=GitHub) | Free & Libre |
## Package authenticity from GitHub
- Download the app from [GitHub releases](https://github.com/Kunzisoft/KeePassDX/releases/latest)
- Install [`apksigner`](https://developer.android.com/tools/apksigner) from [Android Studio](https://developer.android.com/studio)
- Open the directory where you saved the downloaded file in the Terminal
- Make sure that you have `apksigner` installed by running:
```shell
apksigner --version
```
- Depending on the APK file you downloaded, run:
```shell
apksigner verify --verbose --print-certs -min-sdk-version 24 KeePassDX-*.apk
```
You should get this output :
```shell
Verified using v2 scheme (APK Signature Scheme v2): true
...
Number of signers: 1
Signer #1 certificate SHA-256 digest: 7d55b8af210381aabf960f07e17cf7857b6d2a642ca2da6bf0bdf1b200362f04
...
Signer #1 public key SHA-256 digest: 5d261d3176db1e077b80112824d9390167f3be0561827e42112ed6b71192db81
```
If it's the case, this means that the APK was well built by the author of KeePassDX.
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.kunzisoft.keepass.libre/)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=com.kunzisoft.keepass.free)
[<img src="https://raw.githubusercontent.com/Kunzisoft/Github-badge/main/get-it-on-github.png"
alt="Get it on Github"
height="80">](https://github.com/Kunzisoft/KeePassDX/releases)
## Frequently Asked Questions
Other questions? You can read the [FAQ](https://github.com/Kunzisoft/KeePassDX/wiki/FAQ)
@@ -74,7 +96,7 @@ Other questions? You can read the [FAQ](https://github.com/Kunzisoft/KeePassDX/w
## License
Copyright © 2023 Jeremy Jamet / [Kunzisoft](https://www.kunzisoft.com).
Copyright © 2024 Jeremy Jamet / [Kunzisoft](https://www.kunzisoft.com).
This file is part of KeePassDX.

View File

@@ -5,15 +5,14 @@ apply plugin: 'kotlin-kapt'
android {
namespace 'com.kunzisoft.keepass'
compileSdkVersion 33
buildToolsVersion "33.0.2"
compileSdkVersion 34
defaultConfig {
applicationId "com.kunzisoft.keepass"
minSdkVersion 15
targetSdkVersion 33
versionCode = 122
versionName = "4.0.0_beta02"
targetSdkVersion 34
versionCode = 133
versionName = "4.1.1"
multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests"
@@ -36,6 +35,13 @@ android {
}
}
dependenciesInfo {
// Disables dependency metadata when building APKs.
includeInApk = false
// Disables dependency metadata when building Android App Bundles.
includeInBundle = false
}
flavorDimensions "version"
productFlavors {
libre {
@@ -120,7 +126,7 @@ dependencies {
// Autofill
implementation "androidx.autofill:autofill:1.1.0"
// Time
implementation 'joda-time:joda-time:2.10.13'
implementation 'joda-time:joda-time:2.13.0'
// Color
implementation 'com.github.Kunzisoft:AndroidClearChroma:2.6'
// Education

View File

@@ -7,10 +7,6 @@
<group
android:translateX="-12"
android:translateY="-12">
<path
android:fillColor="#ffa726"
android:strokeWidth="1.99999297"
android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
<path
android:fillColor="#ffffff"
android:strokeWidth="1.99999297"

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="84"
android:viewportHeight="84">
<group
android:translateX="-12"
android:translateY="-12">
<path
android:fillColor="#ffffff"
android:strokeWidth="1.99999297"
android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
</group>
</vector>

View File

@@ -7,10 +7,6 @@
<group
android:translateX="-12"
android:translateY="-12">
<path
android:fillColor="#ffa726"
android:strokeWidth="1.99999297"
android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
<path
android:fillColor="#ffffff"
android:strokeWidth="1.99999297"

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="84"
android:viewportHeight="84">
<group
android:translateX="-12"
android:translateY="-12">
<path
android:fillColor="#ffffff"
android:strokeWidth="1.99999297"
android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
</group>
</vector>

View File

@@ -9,6 +9,10 @@
android:anyDensity="true" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission
android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<uses-permission
android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission
@@ -118,7 +122,7 @@
android:name="com.kunzisoft.keepass.activities.GroupActivity"
android:exported="false"
android:configChanges="keyboardHidden"
android:windowSoftInputMode="adjustPan">
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="android.app.default_searchable"
android:value="com.kunzisoft.keepass.search.SearchResults"
@@ -197,18 +201,27 @@
<service
android:name="com.kunzisoft.keepass.services.DatabaseTaskNotificationService"
android:foregroundServiceType="dataSync"
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.services.AttachmentFileNotificationService"
android:foregroundServiceType="dataSync"
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.services.ClipboardEntryNotificationService"
android:foregroundServiceType="specialUse"
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.services.KeyboardEntryNotificationService"
android:foregroundServiceType="specialUse"
android:enabled="true"
android:exported="false" />
<service
android:name="com.kunzisoft.keepass.services.AdvancedUnlockNotificationService"
android:foregroundServiceType="specialUse"
android:enabled="true"
android:exported="false" />
<!-- Receiver for Autofill -->
@@ -235,10 +248,6 @@
<action android:name="android.view.InputMethod" />
</intent-filter>
</service>
<service
android:name="com.kunzisoft.keepass.services.KeyboardEntryNotificationService"
android:enabled="true"
android:exported="false" />
<receiver
android:name="com.kunzisoft.keepass.receivers.DexModeReceiver"
android:exported="true">

View File

@@ -38,7 +38,11 @@ import android.graphics.RectF
import android.graphics.drawable.BitmapDrawable
import android.os.Build
import android.util.TypedValue
import android.view.*
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.DecelerateInterpolator
import android.view.animation.Interpolator
@@ -202,7 +206,7 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
override fun onDown(e: MotionEvent): Boolean = true
override fun onScroll(
e1: MotionEvent,
e1: MotionEvent?,
e2: MotionEvent,
distanceX: Float,
distanceY: Float
@@ -220,7 +224,7 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
}
override fun onFling(
e1: MotionEvent,
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float

View File

@@ -25,6 +25,7 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.RequiresApi
@@ -44,6 +45,7 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.utils.WebDomain
import java.lang.RuntimeException
@RequiresApi(api = Build.VERSION_CODES.O)
class AutofillLauncherActivity : DatabaseModeActivity() {
@@ -216,6 +218,8 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
companion object {
private val TAG = AutofillLauncherActivity::class.java.name
private const val KEY_SELECTION_BUNDLE = "KEY_SELECTION_BUNDLE"
private const val KEY_SEARCH_INFO = "KEY_SEARCH_INFO"
private const val KEY_INLINE_SUGGESTION = "KEY_INLINE_SUGGESTION"
@@ -224,37 +228,51 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
fun getPendingIntentForSelection(context: Context,
searchInfo: SearchInfo? = null,
compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest? = null): PendingIntent {
return PendingIntent.getActivity(context, 0,
// Doesn't work with direct extra Parcelable (don't know why?)
// Wrap into a bundle to bypass the problem
Intent(context, AutofillLauncherActivity::class.java).apply {
putExtra(KEY_SELECTION_BUNDLE, Bundle().apply {
putParcelable(KEY_SEARCH_INFO, searchInfo)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
putParcelable(KEY_INLINE_SUGGESTION, compatInlineSuggestionsRequest)
}
})
},
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
} else {
PendingIntent.FLAG_CANCEL_CURRENT
})
compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest? = null): PendingIntent? {
try {
return PendingIntent.getActivity(
context, 0,
// Doesn't work with direct extra Parcelable (don't know why?)
// Wrap into a bundle to bypass the problem
Intent(context, AutofillLauncherActivity::class.java).apply {
putExtra(KEY_SELECTION_BUNDLE, Bundle().apply {
putParcelable(KEY_SEARCH_INFO, searchInfo)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
putParcelable(KEY_INLINE_SUGGESTION, compatInlineSuggestionsRequest)
}
})
},
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
} else {
PendingIntent.FLAG_CANCEL_CURRENT
}
)
} catch (e: RuntimeException) {
Log.e(TAG, "Unable to create pending intent for selection", e)
return null
}
}
fun getPendingIntentForRegistration(context: Context,
registerInfo: RegisterInfo): PendingIntent {
return PendingIntent.getActivity(context, 0,
Intent(context, AutofillLauncherActivity::class.java).apply {
EntrySelectionHelper.addSpecialModeInIntent(this, SpecialMode.REGISTRATION)
putExtra(KEY_REGISTER_INFO, registerInfo)
},
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
} else {
PendingIntent.FLAG_CANCEL_CURRENT
})
registerInfo: RegisterInfo): PendingIntent? {
try {
return PendingIntent.getActivity(
context, 0,
Intent(context, AutofillLauncherActivity::class.java).apply {
EntrySelectionHelper.addSpecialModeInIntent(this, SpecialMode.REGISTRATION)
putExtra(KEY_REGISTER_INFO, registerInfo)
},
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
} else {
PendingIntent.FLAG_CANCEL_CURRENT
}
)
} catch (e: RuntimeException) {
Log.e(TAG, "Unable to create pending intent for registration", e)
return null
}
}
fun launchForRegistration(context: Context,

View File

@@ -23,6 +23,7 @@ import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@@ -30,15 +31,20 @@ import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import androidx.core.graphics.ColorUtils
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout
@@ -69,15 +75,19 @@ import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.UuidUtil
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.view.WindowInsetPosition
import com.kunzisoft.keepass.view.applyWindowInsets
import com.kunzisoft.keepass.view.changeControlColor
import com.kunzisoft.keepass.view.changeTitleColor
import com.kunzisoft.keepass.view.hideByFading
import com.kunzisoft.keepass.view.setTransparentNavigationBar
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.viewmodels.EntryViewModel
import java.util.UUID
class EntryActivity : DatabaseLockActivity() {
private var footer: ViewGroup? = null
private var coordinatorLayout: CoordinatorLayout? = null
private var collapsingToolbarLayout: CollapsingToolbarLayout? = null
private var appBarLayout: AppBarLayout? = null
@@ -128,6 +138,7 @@ class EntryActivity : DatabaseLockActivity() {
supportActionBar?.setDisplayShowHomeEnabled(true)
// Get views
footer = findViewById(R.id.activity_entry_footer)
coordinatorLayout = findViewById(R.id.toolbar_coordinator)
collapsingToolbarLayout = findViewById(R.id.toolbar_layout)
appBarLayout = findViewById(R.id.app_bar)
@@ -139,6 +150,14 @@ class EntryActivity : DatabaseLockActivity() {
lockView = findViewById(R.id.lock_button)
loadingView = findViewById(R.id.loading)
// To apply fit window with transparency
setTransparentNavigationBar {
// To fix margin with API 27
ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout!!, null)
coordinatorLayout?.applyWindowInsets(WindowInsetPosition.TOP)
footer?.applyWindowInsets(WindowInsetPosition.BOTTOM)
}
// Empty title
collapsingToolbarLayout?.title = " "
toolbar?.title = " "

View File

@@ -72,6 +72,7 @@ import com.kunzisoft.keepass.database.element.template.Template
import com.kunzisoft.keepass.education.EntryEditActivityEducation
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.DataTime
import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
@@ -86,11 +87,15 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.TimeUtil.datePickerToDataDate
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.view.ToolbarAction
import com.kunzisoft.keepass.view.WindowInsetPosition
import com.kunzisoft.keepass.view.applyWindowInsets
import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.hideByFading
import com.kunzisoft.keepass.view.setTransparentNavigationBar
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.view.updateLockPaddingLeft
import com.kunzisoft.keepass.viewmodels.ColorPickerViewModel
@@ -104,6 +109,8 @@ class EntryEditActivity : DatabaseLockActivity(),
ReplaceFileDialogFragment.ActionChooseListener {
// Views
private var footer: View? = null
private var container: View? = null
private var coordinatorLayout: CoordinatorLayout? = null
private var scrollView: NestedScrollView? = null
private var templateSelectorSpinner: Spinner? = null
@@ -156,10 +163,8 @@ class EntryEditActivity : DatabaseLockActivity(),
// Bottom Bar
entryEditAddToolBar = findViewById(R.id.entry_edit_bottom_bar)
setSupportActionBar(entryEditAddToolBar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
footer = findViewById(R.id.activity_entry_edit_footer)
container = findViewById(R.id.activity_entry_edit_container)
coordinatorLayout = findViewById(R.id.entry_edit_coordinator_layout)
scrollView = findViewById(R.id.entry_edit_scroll)
scrollView?.scrollBarStyle = View.SCROLLBARS_INSIDE_INSET
@@ -168,6 +173,17 @@ class EntryEditActivity : DatabaseLockActivity(),
validateButton = findViewById(R.id.entry_edit_validate)
loadingView = findViewById(R.id.loading)
setSupportActionBar(entryEditAddToolBar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
// To apply fit window with transparency
setTransparentNavigationBar(applyToStatusBar = true) {
container?.applyWindowInsets(WindowInsetPosition.TOP_BOTTOM_IME)
footer?.applyWindowInsets(WindowInsetPosition.BOTTOM_IME)
}
stopService(Intent(this, ClipboardEntryNotificationService::class.java))
stopService(Intent(this, KeyboardEntryNotificationService::class.java))
@@ -286,7 +302,7 @@ class EntryEditActivity : DatabaseLockActivity(),
// Launch the time picker
MaterialTimePicker.Builder().build().apply {
addOnPositiveButtonClickListener {
mEntryEditViewModel.selectTime(this.hour, this.minute)
mEntryEditViewModel.selectTime(DataTime(this.hour, this.minute))
}
show(supportFragmentManager, "TimePickerFragment")
}
@@ -294,7 +310,7 @@ class EntryEditActivity : DatabaseLockActivity(),
// Launch the date picker
MaterialDatePicker.Builder.datePicker().build().apply {
addOnPositiveButtonClickListener {
mEntryEditViewModel.selectDate(it)
mEntryEditViewModel.selectDate(datePickerToDataDate(it))
}
show(supportFragmentManager, "DatePickerFragment")
}
@@ -691,16 +707,16 @@ class EntryEditActivity : DatabaseLockActivity(),
return true
}
android.R.id.home -> {
onBackPressed()
onDatabaseBackPressed()
}
}
return super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
override fun onDatabaseBackPressed() {
onApprovedBackPressed {
super@EntryEditActivity.onBackPressed()
super@EntryEditActivity.onDatabaseBackPressed()
}
}

View File

@@ -68,11 +68,10 @@ import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.DexUtil
import com.kunzisoft.keepass.utils.MagikeyboardUtil
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.parseUri
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.allowCreateDocumentByStorageAccessFramework
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.viewmodels.DatabaseFilesViewModel
@@ -180,17 +179,9 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
}
fileDatabaseHistoryRecyclerView.adapter = mAdapterDatabaseHistory
// Load default database if not an orientation change
if (!(savedInstanceState != null
&& savedInstanceState.containsKey(EXTRA_STAY)
&& savedInstanceState.getBoolean(EXTRA_STAY, false))) {
val databasePath = PreferencesUtil.getDefaultDatabasePath(this)
databasePath?.parseUri()?.let { databaseFileUri ->
launchPasswordActivityWithPath(databaseFileUri)
} ?: run {
Log.i(TAG, "No default database to prepare")
}
// Load default database the first time
databaseFilesViewModel.doForDefaultDatabase { databaseFileUri ->
launchPasswordActivityWithPath(databaseFileUri)
}
// Retrieve the database URI provided by file manager after an orientation change
@@ -366,8 +357,6 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// only to keep the current activity
outState.putBoolean(EXTRA_STAY, true)
// to retrieve the URI of a created database after an orientation change
outState.putParcelable(EXTRA_DATABASE_URI, mDatabaseFileUri)
}
@@ -442,7 +431,6 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
companion object {
private const val TAG = "FileDbSelectActivity"
private const val EXTRA_STAY = "EXTRA_STAY"
private const val EXTRA_DATABASE_URI = "EXTRA_DATABASE_URI"
/*

View File

@@ -35,6 +35,7 @@ import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
@@ -83,6 +84,7 @@ import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.database.search.SearchParameters
import com.kunzisoft.keepass.education.GroupActivityEducation
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.model.DataTime
import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
@@ -95,6 +97,7 @@ import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.BACK_PREVIOUS_KEYBOARD_ACTION
import com.kunzisoft.keepass.utils.KeyboardUtil.showKeyboard
import com.kunzisoft.keepass.utils.TimeUtil.datePickerToDataDate
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
@@ -105,11 +108,15 @@ import com.kunzisoft.keepass.view.AddNodeButtonView
import com.kunzisoft.keepass.view.NavigationDatabaseView
import com.kunzisoft.keepass.view.SearchFiltersView
import com.kunzisoft.keepass.view.ToolbarAction
import com.kunzisoft.keepass.view.WindowInsetPosition
import com.kunzisoft.keepass.view.applyWindowInsets
import com.kunzisoft.keepass.view.hideByFading
import com.kunzisoft.keepass.view.setTransparentNavigationBar
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.view.updateLockPaddingLeft
import com.kunzisoft.keepass.viewmodels.GroupEditViewModel
import com.kunzisoft.keepass.viewmodels.GroupViewModel
import org.joda.time.Instant
class GroupActivity : DatabaseLockActivity(),
@@ -121,6 +128,8 @@ class GroupActivity : DatabaseLockActivity(),
MainCredentialDialogFragment.AskMainCredentialDialogListener {
// Views
private var header: ViewGroup? = null
private var footer: ViewGroup? = null
private var drawerLayout: DrawerLayout? = null
private var databaseNavView: NavigationDatabaseView? = null
private var coordinatorLayout: CoordinatorLayout? = null
@@ -267,6 +276,8 @@ class GroupActivity : DatabaseLockActivity(),
setContentView(layoutInflater.inflate(R.layout.activity_group, null))
// Initialize views
header = findViewById(R.id.activity_group_header)
footer = findViewById(R.id.activity_group_footer)
drawerLayout = findViewById(R.id.drawer_layout)
databaseNavView = findViewById(R.id.database_nav_view)
coordinatorLayout = findViewById(R.id.group_coordinator)
@@ -283,6 +294,12 @@ class GroupActivity : DatabaseLockActivity(),
lockView = findViewById(R.id.lock_button)
loadingView = findViewById(R.id.loading)
// To apply fit window with transparency
setTransparentNavigationBar(applyToStatusBar = true) {
drawerLayout?.applyWindowInsets(WindowInsetPosition.TOP_BOTTOM_IME)
footer?.applyWindowInsets(WindowInsetPosition.BOTTOM_IME)
}
lockView?.setOnClickListener {
lockAndExit()
}
@@ -325,8 +342,9 @@ class GroupActivity : DatabaseLockActivity(),
R.id.menu_save_copy_to -> {
mExternalFileHelper?.createDocument(
getString(R.string.database_file_name_default) +
getString(R.string.database_file_name_copy) +
mDatabase?.defaultFileExtension)
"_" +
Instant.now().toString() +
mDatabase?.defaultFileExtension)
}
R.id.menu_lock_all -> {
lockAndExit()
@@ -344,43 +362,6 @@ class GroupActivity : DatabaseLockActivity(),
searchFiltersView?.closeAdvancedFilters()
mBreadcrumbAdapter = BreadcrumbAdapter(this).apply {
// Open group on breadcrumb click
onItemClickListener = { node, _ ->
// If last item & not a virtual root group
val currentGroup = mMainGroup
if (currentGroup != null && node == currentGroup
&& (currentGroup != mDatabase?.rootGroup
|| mDatabase?.rootGroupIsVirtual == false)
) {
finishNodeAction()
launchDialogToShowGroupInfo(currentGroup)
} else {
if (mGroupFragment?.nodeActionSelectionMode == true) {
finishNodeAction()
}
mDatabase?.let { database ->
onNodeClick(database, node)
}
}
}
onLongItemClickListener = { node, position ->
val currentGroup = mMainGroup
if (currentGroup != null && node == currentGroup
&& (currentGroup != mDatabase?.rootGroup
|| mDatabase?.rootGroupIsVirtual == false)
) {
finishNodeAction()
launchDialogForGroupUpdate(currentGroup)
} else {
onItemClickListener?.invoke(node, position)
}
}
}
breadcrumbListView?.apply {
adapter = mBreadcrumbAdapter
}
// Retrieve group if defined at launch
manageIntent(intent)
@@ -461,7 +442,7 @@ class GroupActivity : DatabaseLockActivity(),
// Launch the time picker
MaterialTimePicker.Builder().build().apply {
addOnPositiveButtonClickListener {
mGroupEditViewModel.selectTime(this.hour, this.minute)
mGroupEditViewModel.selectTime(DataTime(this.hour, this.minute))
}
show(supportFragmentManager, "TimePickerFragment")
}
@@ -469,7 +450,7 @@ class GroupActivity : DatabaseLockActivity(),
// Launch the date picker
MaterialDatePicker.Builder.datePicker().build().apply {
addOnPositiveButtonClickListener {
mGroupEditViewModel.selectDate(it)
mGroupEditViewModel.selectDate(datePickerToDataDate(it))
}
show(supportFragmentManager, "DatePickerFragment")
}
@@ -602,6 +583,43 @@ class GroupActivity : DatabaseLockActivity(),
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mBreadcrumbAdapter = BreadcrumbAdapter(this, database).apply {
// Open group on breadcrumb click
onItemClickListener = { node, _ ->
// If last item & not a virtual root group
val currentGroup = mMainGroup
if (currentGroup != null && node == currentGroup
&& (currentGroup != mDatabase?.rootGroup
|| mDatabase?.rootGroupIsVirtual == false)
) {
finishNodeAction()
launchDialogToShowGroupInfo(currentGroup)
} else {
if (mGroupFragment?.nodeActionSelectionMode == true) {
finishNodeAction()
}
mDatabase?.let { database ->
onNodeClick(database, node)
}
}
}
onLongItemClickListener = { node, position ->
val currentGroup = mMainGroup
if (currentGroup != null && node == currentGroup
&& (currentGroup != mDatabase?.rootGroup
|| mDatabase?.rootGroupIsVirtual == false)
) {
finishNodeAction()
launchDialogForGroupUpdate(currentGroup)
} else {
onItemClickListener?.invoke(node, position)
}
}
}
breadcrumbListView?.apply {
adapter = mBreadcrumbAdapter
}
mGroupEditViewModel.setGroupNamesNotAllowed(database?.groupNamesNotAllowed)
mRecyclingBinEnabled = !mDatabaseReadOnly
@@ -1339,7 +1357,7 @@ class GroupActivity : DatabaseLockActivity(),
}
}
override fun onBackPressed() {
override fun onDatabaseBackPressed() {
if (mGroupFragment?.nodeActionSelectionMode == true) {
finishNodeAction()
} else {

View File

@@ -239,7 +239,7 @@ class IconPickerActivity : DatabaseLockActivity() {
if (mCustomIconsSelectionMode) {
iconPickerViewModel.deselectAllCustomIcons()
} else {
onBackPressed()
onDatabaseBackPressed()
}
}
R.id.menu_edit -> {
@@ -329,9 +329,9 @@ class IconPickerActivity : DatabaseLockActivity() {
})
}
override fun onBackPressed() {
override fun onDatabaseBackPressed() {
setResult()
super.onBackPressed()
super.onDatabaseBackPressed()
}
companion object {

View File

@@ -96,7 +96,7 @@ class KeyGeneratorActivity : DatabaseLockActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
onBackPressed()
onDatabaseBackPressed()
}
R.id.menu_generate -> {
keyGeneratorViewModel.requireKeyGeneration()
@@ -106,9 +106,9 @@ class KeyGeneratorActivity : DatabaseLockActivity() {
return super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
override fun onDatabaseBackPressed() {
setResult(Activity.RESULT_CANCELED, Intent())
super.onBackPressed()
super.onDatabaseBackPressed()
}
companion object {

View File

@@ -165,18 +165,6 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
startActivity(Intent(this, AppearanceSettingsActivity::class.java))
}
// Init Biometric elements
advancedUnlockFragment = supportFragmentManager
.findFragmentByTag(UNLOCK_FRAGMENT_TAG) as? AdvancedUnlockFragment?
if (advancedUnlockFragment == null) {
advancedUnlockFragment = AdvancedUnlockFragment()
supportFragmentManager.commit {
replace(R.id.fragment_advanced_unlock_container_view,
advancedUnlockFragment!!,
UNLOCK_FRAGMENT_TAG)
}
}
// Listen password checkbox to init advanced unlock and confirmation button
mainCredentialView?.onPasswordChecked =
CompoundButton.OnCheckedChangeListener { _, _ ->
@@ -245,6 +233,23 @@ class MainCredentialActivity : DatabaseModeActivity(), AdvancedUnlockFragment.Bu
override fun onResume() {
super.onResume()
// Init Biometric elements only if allowed
if (PreferencesUtil.isAdvancedUnlockEnable(this)) {
advancedUnlockFragment = supportFragmentManager
.findFragmentByTag(UNLOCK_FRAGMENT_TAG) as? AdvancedUnlockFragment?
if (advancedUnlockFragment == null) {
advancedUnlockFragment = AdvancedUnlockFragment().also {
supportFragmentManager.commit {
replace(
R.id.fragment_advanced_unlock_container_view,
it,
UNLOCK_FRAGMENT_TAG
)
}
}
}
}
mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this@MainCredentialActivity)
mRememberHardwareKey = PreferencesUtil.rememberHardwareKey(this@MainCredentialActivity)

View File

@@ -43,6 +43,7 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
val oldSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelableCompat(OLD_FILE_DATABASE_INFO)
val newSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelableCompat(NEW_FILE_DATABASE_INFO)
val readOnlyDatabase: Boolean = arguments?.getBoolean(READ_ONLY_DATABASE) ?: true
if (oldSnapFileDatabaseInfo != null && newSnapFileDatabaseInfo != null) {
// Use the Builder class for convenient dialog construction
@@ -54,7 +55,13 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
stringBuilder.append("\n\n" +oldSnapFileDatabaseInfo.toString(activity)
+ "\n\n" +
newSnapFileDatabaseInfo.toString(activity) + "\n\n")
stringBuilder.append(getString(R.string.warning_database_info_changed_options))
stringBuilder.append(getString(
if (readOnlyDatabase) {
R.string.warning_database_info_changed_options_read_only
} else {
R.string.warning_database_info_changed_options
}
))
} else {
stringBuilder.append(getString(R.string.warning_database_revoked))
}
@@ -77,15 +84,18 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
const val DATABASE_CHANGED_DIALOG_TAG = "databaseChangedDialogFragment"
private const val OLD_FILE_DATABASE_INFO = "OLD_FILE_DATABASE_INFO"
private const val NEW_FILE_DATABASE_INFO = "NEW_FILE_DATABASE_INFO"
private const val READ_ONLY_DATABASE = "READ_ONLY_DATABASE"
fun getInstance(oldSnapFileDatabaseInfo: SnapFileDatabaseInfo,
newSnapFileDatabaseInfo: SnapFileDatabaseInfo
newSnapFileDatabaseInfo: SnapFileDatabaseInfo,
readOnly: Boolean
)
: DatabaseChangedDialogFragment {
val fragment = DatabaseChangedDialogFragment()
fragment.arguments = Bundle().apply {
putParcelable(OLD_FILE_DATABASE_INFO, oldSnapFileDatabaseInfo)
putParcelable(NEW_FILE_DATABASE_INFO, newSnapFileDatabaseInfo)
putBoolean(READ_ONLY_DATABASE, readOnly)
}
return fragment
}

View File

@@ -1,11 +1,14 @@
package com.kunzisoft.keepass.activities.dialogs
import android.os.Bundle
import android.view.View
import android.view.WindowManager.LayoutParams.FLAG_SECURE
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
@@ -29,6 +32,18 @@ abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Screenshot mode or hide views
context?.let {
if (PreferencesUtil.isScreenshotModeEnabled(it)) {
dialog?.window?.clearFlags(FLAG_SECURE)
} else {
dialog?.window?.setFlags(FLAG_SECURE, FLAG_SECURE)
}
}
}
@Suppress("DEPRECATION")
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)

View File

@@ -45,7 +45,6 @@ import com.kunzisoft.keepass.view.InheritedCompletionView
import com.kunzisoft.keepass.view.TagsCompletionView
import com.kunzisoft.keepass.viewmodels.GroupEditViewModel
import com.tokenautocomplete.FilteredArrayAdapter
import org.joda.time.DateTime
class GroupEditDialogFragment : DatabaseDialogFragment() {
@@ -90,27 +89,21 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
mPopulateIconMethod?.invoke(iconButtonView, mGroupInfo.icon)
}
mGroupEditViewModel.onDateSelected.observe(this) { dateMilliseconds ->
mGroupEditViewModel.onDateSelected.observe(this) { date ->
// Save the date
mGroupInfo.expiryTime = DateInstant(
DateTime(mGroupInfo.expiryTime.date)
.withMillis(dateMilliseconds)
.toDate())
mGroupInfo.expiryTime.setDate(date.year, date.month, date.day)
expirationView.dateTime = mGroupInfo.expiryTime
if (expirationView.dateTime.type == DateInstant.Type.DATE_TIME) {
val instantTime = DateInstant(mGroupInfo.expiryTime.date, DateInstant.Type.TIME)
// Trick to recall selection with time
mGroupEditViewModel.requestDateTimeSelection(instantTime)
mGroupEditViewModel.requestDateTimeSelection(
DateInstant(mGroupInfo.expiryTime.instant, DateInstant.Type.TIME)
)
}
}
mGroupEditViewModel.onTimeSelected.observe(this) { viewModelTime ->
// Save the time
mGroupInfo.expiryTime = DateInstant(
DateTime(mGroupInfo.expiryTime.date)
.withHourOfDay(viewModelTime.hours)
.withMinuteOfHour(viewModelTime.minutes)
.toDate(), mGroupInfo.expiryTime.type)
mGroupInfo.expiryTime.setTime(viewModelTime.hour, viewModelTime.minute)
expirationView.dateTime = mGroupInfo.expiryTime
}

View File

@@ -43,8 +43,13 @@ import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.view.HardwareKeySelectionView
import com.kunzisoft.keepass.view.KeyFileSelectionView
import com.kunzisoft.keepass.view.PassKeyView
import com.kunzisoft.keepass.view.PasswordEditView
import com.kunzisoft.keepass.view.applyFontVisibility
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.security.SecureRandom
class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
@@ -55,11 +60,12 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
private lateinit var rootView: View
private lateinit var passwordCheckBox: CompoundButton
private lateinit var passwordView: PassKeyView
private lateinit var passwordEditView: PasswordEditView
private lateinit var passwordRepeatTextInputLayout: TextInputLayout
private lateinit var passwordRepeatView: TextView
private lateinit var keyFileCheckBox: CompoundButton
private lateinit var keyFileGenerateButton: View
private lateinit var keyFileSelectionView: KeyFileSelectionView
private lateinit var hardwareKeyCheckBox: CompoundButton
@@ -141,30 +147,40 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
}
passwordCheckBox = rootView.findViewById(R.id.password_checkbox)
passwordView = rootView.findViewById(R.id.password_view)
passwordEditView = rootView.findViewById(R.id.password_view)
passwordRepeatTextInputLayout = rootView.findViewById(R.id.password_repeat_input_layout)
passwordRepeatView = rootView.findViewById(R.id.password_confirmation)
passwordRepeatView.applyFontVisibility()
keyFileCheckBox = rootView.findViewById(R.id.keyfile_checkbox)
keyFileGenerateButton = rootView.findViewById(R.id.keyfile_generate)
keyFileSelectionView = rootView.findViewById(R.id.keyfile_selection)
hardwareKeyCheckBox = rootView.findViewById(R.id.hardware_key_checkbox)
hardwareKeySelectionView = rootView.findViewById(R.id.hardware_key_selection)
mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildCreateDocument { createdFileUri ->
createdFileUri?.let { uri ->
createKeyFile(uri)
keyFileSelectionView.error = null
keyFileCheckBox.isChecked = true
keyFileSelectionView.uri = uri
}
}
mExternalFileHelper?.buildOpenDocument { uri ->
uri?.let { pathUri ->
pathUri.getDocumentFile(requireContext())?.length()?.let { lengthFile ->
keyFileSelectionView.error = null
keyFileCheckBox.isChecked = true
keyFileSelectionView.uri = pathUri
if (lengthFile <= 0L) {
showEmptyKeyFileConfirmationDialog()
}
showLengthKeyFileConfirmationDialog(lengthFile)
}
}
}
keyFileGenerateButton.setOnClickListener {
mExternalFileHelper?.createDocument(DEFAULT_KEYFILE_NAME)
}
keyFileSelectionView.setOpenDocumentClickListener(mExternalFileHelper)
hardwareKeySelectionView.selectionListener = { hardwareKey ->
@@ -202,6 +218,16 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
return super.onCreateDialog(savedInstanceState)
}
private fun createKeyFile(uri: Uri) {
CoroutineScope(Dispatchers.IO).launch {
activity?.contentResolver?.openOutputStream(uri)?.use { outputStream ->
val randomBytes = ByteArray(DEFAULT_KEYFILE_SIZE)
SecureRandom().nextBytes(randomBytes)
outputStream.write(randomBytes)
}
}
}
private fun approveMainCredential() {
val errorPassword = verifyPassword()
val errorKeyFile = verifyKeyFile()
@@ -250,7 +276,7 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
var error = false
passwordRepeatTextInputLayout.error = null
if (passwordCheckBox.isChecked) {
mMasterPassword = passwordView.passwordString
mMasterPassword = passwordEditView.passwordString
val confPassword = passwordRepeatView.text.toString()
// Verify that passwords match
@@ -302,13 +328,13 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
super.onResume()
// To check checkboxes if a text is present
passwordView.addTextChangedListener(passwordTextWatcher)
passwordEditView.addTextChangedListener(passwordTextWatcher)
}
override fun onPause() {
super.onPause()
passwordView.removeTextChangedListener(passwordTextWatcher)
passwordEditView.removeTextChangedListener(passwordTextWatcher)
}
private fun showEmptyPasswordConfirmationDialog() {
@@ -339,21 +365,31 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
}
}
private fun showEmptyKeyFileConfirmationDialog() {
private fun showLengthKeyFileConfirmationDialog(length: Long) {
activity?.let {
val builder = AlertDialog.Builder(it)
builder.setMessage(SpannableStringBuilder().apply {
append(getString(R.string.warning_empty_keyfile))
append("\n\n")
append(getString(R.string.warning_empty_keyfile_explanation))
append("\n\n")
append(getString(R.string.warning_sure_add_file))
})
.setPositiveButton(android.R.string.ok) { _, _ -> }
.setNegativeButton(android.R.string.cancel) { _, _ ->
keyFileCheckBox.isChecked = false
keyFileSelectionView.uri = null
}
var warning = false
if (length <= 0L) {
warning = true
append("\n\n")
append(getString(R.string.warning_empty_keyfile))
} else if (length > 10485760L) {
warning = true
append("\n\n")
append(getString(R.string.warning_large_keyfile))
}
if (warning) {
append("\n\n")
append(getString(R.string.warning_sure_add_file))
}
})
.setPositiveButton(android.R.string.ok) { _, _ -> }
.setNegativeButton(android.R.string.cancel) { _, _ ->
keyFileCheckBox.isChecked = false
keyFileSelectionView.uri = null
}
mEmptyKeyFileConfirmationDialog = builder.create()
mEmptyKeyFileConfirmationDialog?.show()
}
@@ -362,6 +398,8 @@ class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
companion object {
private const val ALLOW_NO_MASTER_KEY_ARG = "ALLOW_NO_MASTER_KEY_ARG"
private const val DEFAULT_KEYFILE_NAME = "keyfile.bin"
private const val DEFAULT_KEYFILE_SIZE = 128
fun getInstance(allowNoMasterKey: Boolean): SetMainCredentialDialogFragment {
val fragment = SetMainCredentialDialogFragment()

View File

@@ -34,12 +34,12 @@ import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.password.PassphraseGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.view.PassKeyView
import com.kunzisoft.keepass.view.PasswordEditView
import com.kunzisoft.keepass.viewmodels.KeyGeneratorViewModel
class PassphraseGeneratorFragment : DatabaseFragment() {
private lateinit var passKeyView: PassKeyView
private lateinit var passwordEditView: PasswordEditView
private lateinit var sliderWordCount: Slider
private lateinit var wordCountText: EditText
@@ -62,7 +62,7 @@ class PassphraseGeneratorFragment : DatabaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
passKeyView = view.findViewById(R.id.passphrase_view)
passwordEditView = view.findViewById(R.id.passphrase_view)
val passphraseCopyView: ImageView? = view.findViewById(R.id.passphrase_copy_button)
sliderWordCount = view.findViewById(R.id.slider_word_count)
wordCountText = view.findViewById(R.id.word_count)
@@ -80,7 +80,7 @@ class PassphraseGeneratorFragment : DatabaseFragment() {
passphraseCopyView?.setOnClickListener {
clipboardHelper.timeoutCopyToClipboard(
getString(R.string.passphrase),
passKeyView.passwordString,
passwordEditView.passwordString,
true
)
}
@@ -146,7 +146,7 @@ class PassphraseGeneratorFragment : DatabaseFragment() {
generatePassphrase()
mKeyGeneratorViewModel.passphraseGeneratedValidated.observe(viewLifecycleOwner) {
mKeyGeneratorViewModel.setKeyGenerated(passKeyView.passwordString)
mKeyGeneratorViewModel.setKeyGenerated(passwordEditView.passwordString)
}
mKeyGeneratorViewModel.requirePassphraseGeneration.observe(viewLifecycleOwner) {
@@ -219,7 +219,7 @@ class PassphraseGeneratorFragment : DatabaseFragment() {
} catch (e: Exception) {
Log.e(TAG, "Unable to generate a passphrase", e)
}
passKeyView.passwordString = passphrase
passwordEditView.passwordString = passphrase
charactersCountText.text = getString(R.string.character_count, passphrase.length)
}

View File

@@ -36,12 +36,12 @@ import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.view.PassKeyView
import com.kunzisoft.keepass.view.PasswordEditView
import com.kunzisoft.keepass.viewmodels.KeyGeneratorViewModel
class PasswordGeneratorFragment : DatabaseFragment() {
private lateinit var passKeyView: PassKeyView
private lateinit var passwordEditView: PasswordEditView
private lateinit var sliderLength: Slider
private lateinit var lengthEditView: EditText
@@ -74,7 +74,7 @@ class PasswordGeneratorFragment : DatabaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
passKeyView = view.findViewById(R.id.password_view)
passwordEditView = view.findViewById(R.id.password_view)
val passwordCopyView: ImageView? = view.findViewById(R.id.password_copy_button)
sliderLength = view.findViewById(R.id.slider_length)
@@ -101,7 +101,7 @@ class PasswordGeneratorFragment : DatabaseFragment() {
passwordCopyView?.setOnClickListener {
clipboardHelper.timeoutCopyToClipboard(
getString(R.string.password),
passKeyView.passwordString,
passwordEditView.passwordString,
true
)
}
@@ -195,7 +195,7 @@ class PasswordGeneratorFragment : DatabaseFragment() {
generatePassword()
mKeyGeneratorViewModel.passwordGeneratedValidated.observe(viewLifecycleOwner) {
mKeyGeneratorViewModel.setKeyGenerated(passKeyView.passwordString)
mKeyGeneratorViewModel.setKeyGenerated(passwordEditView.passwordString)
}
mKeyGeneratorViewModel.requirePasswordGeneration.observe(viewLifecycleOwner) {
@@ -310,7 +310,7 @@ class PasswordGeneratorFragment : DatabaseFragment() {
} catch (e: Exception) {
Log.e(TAG, "Unable to generate a password", e)
}
passKeyView.passwordString = password
passwordEditView.passwordString = password
}
override fun onDestroy() {

View File

@@ -463,14 +463,14 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabase?.loaded ?: false)
}
override fun onBackPressed() {
override fun onDatabaseBackPressed() {
if (mTimeoutEnable) {
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(this,
mDatabase?.loaded == true) {
super.onBackPressed()
super.onDatabaseBackPressed()
}
} else {
super.onBackPressed()
super.onDatabaseBackPressed()
}
}

View File

@@ -3,6 +3,7 @@ package com.kunzisoft.keepass.activities.legacy
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode
@@ -22,18 +23,20 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
private var mToolbarSpecial: ToolbarSpecial? = null
override fun onBackPressed() {
open fun onDatabaseBackPressed() {
if (mSpecialMode != SpecialMode.DEFAULT)
onCancelSpecialMode()
else
super.onBackPressed()
onRegularBackPressed()
}
/**
* To call the regular onBackPressed() method in special mode
*/
protected fun onRegularBackPressed() {
super.onBackPressed()
// Do not call onBackPressedDispatcher.onBackPressed() to avoid loop
// Calling onBackPressed() is now deprecated, directly finish the activity
finish()
}
/**
@@ -72,7 +75,7 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
open fun onCancelSpecialMode() {
if (isIntentSender()) {
// To get the app caller, only for IntentSender
super.onBackPressed()
onRegularBackPressed()
} else {
EntrySelectionHelper.removeModesFromIntent(intent)
EntrySelectionHelper.removeInfoFromIntent(intent)
@@ -85,7 +88,7 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
protected fun backToTheAppCaller() {
if (isIntentSender()) {
// To get the app caller, only for IntentSender
super.onBackPressed()
onRegularBackPressed()
} else {
backToTheMainAppAndFinish()
}
@@ -100,6 +103,12 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
onDatabaseBackPressed()
}
})
mSpecialMode = EntrySelectionHelper.retrieveSpecialModeFromIntent(intent)
mTypeMode = EntrySelectionHelper.retrieveTypeModeFromIntent(intent)
}

View File

@@ -10,6 +10,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.Type
@@ -17,7 +18,7 @@ import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.view.strikeOut
class BreadcrumbAdapter(val context: Context)
class BreadcrumbAdapter(val context: Context, val database: Database?)
: RecyclerView.Adapter<BreadcrumbAdapter.BreadcrumbGroupViewHolder>() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
@@ -31,6 +32,8 @@ class BreadcrumbAdapter(val context: Context)
var onItemClickListener: ((item: Node, position: Int)->Unit)? = null
var onLongItemClickListener: ((item: Node, position: Int)->Unit)? = null
private var mNodeFilter: NodeFilter = NodeFilter(context, database)
private var mShowNumberEntries = false
private var mShowUUID = false
private var mIconColor: Int = 0
@@ -112,12 +115,10 @@ class BreadcrumbAdapter(val context: Context)
holder.groupNumbersView?.apply {
if (mShowNumberEntries) {
group.refreshNumberOfChildEntries(
Group.ChildFilter.getDefaults(
PreferencesUtil.showExpiredEntries(context)
)
)
text = group.numberOfChildEntries.toString()
text = group.getNumberOfChildEntries(
mNodeFilter.recursiveNumberOfEntries,
mNodeFilter.filter
).toString()
visibility = View.VISIBLE
} else {
visibility = View.GONE

View File

@@ -0,0 +1,30 @@
package com.kunzisoft.keepass.adapters
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.settings.PreferencesUtil
class NodeFilter(
context: Context,
var database: Database? = null
) {
var recursiveNumberOfEntries = PreferencesUtil.recursiveNumberEntries(context)
private set
private var showExpired = PreferencesUtil.showExpiredEntries(context)
private var showTemplate = PreferencesUtil.showTemplates(context)
val filter: (Node) -> Boolean = { node ->
when (node) {
is Entry -> {
node.entryKDB?.isMetaStream() != true
}
is Group -> {
showTemplate || database?.templatesGroup != node
}
else -> true
} && (showExpired || !node.isCurrentlyExpires)
}
}

View File

@@ -66,6 +66,7 @@ class NodesAdapter (
private val mNodeSortedListCallback: NodeSortedListCallback
private val mNodeSortedList: SortedList<Node>
private val mInflater: LayoutInflater = LayoutInflater.from(context)
private val mNodeFilter: NodeFilter = NodeFilter(context, database)
private var mCalculateViewTypeTextSize = Array(2) { true } // number of view type
private var mTextSizeUnit: Int = TypedValue.COMPLEX_UNIT_PX
@@ -82,7 +83,7 @@ class NodesAdapter (
private var mShowNumberEntries: Boolean = true
private var mShowOTP: Boolean = false
private var mShowUUID: Boolean = false
private var mEntryFilters = arrayOf<Group.ChildFilter>()
private var mNodeFilters: NodeFilter? = null
private var mOldVirtualGroup = false
private var mVirtualGroup = false
@@ -161,9 +162,7 @@ class NodesAdapter (
this.mShowOTP = PreferencesUtil.showOTPToken(context)
this.mShowUUID = PreferencesUtil.showUUID(context)
this.mEntryFilters = Group.ChildFilter.getDefaults(
PreferencesUtil.showExpiredEntries(context)
)
this.mNodeFilters = NodeFilter(context, database)
// Reinit textSize for all view type
mCalculateViewTypeTextSize.forEachIndexed { index, _ -> mCalculateViewTypeTextSize[index] = true }
@@ -176,7 +175,7 @@ class NodesAdapter (
mOldVirtualGroup = mVirtualGroup
mVirtualGroup = group.isVirtual
assignPreferences()
mNodeSortedList.replaceAll(group.getFilteredChildren(mEntryFilters))
mNodeSortedList.replaceAll(group.getChildren(mNodeFilter.filter))
}
private inner class NodeSortedListCallback: SortedListAdapterCallback<Node>(this) {
@@ -197,6 +196,7 @@ class NodesAdapter (
&& oldItem.containsAttachment() == newItem.containsAttachment()
} else if (oldItem is Group && newItem is Group) {
typeContentTheSame = oldItem.numberOfChildEntries == newItem.numberOfChildEntries
&& oldItem.recursiveNumberOfChildEntries == newItem.recursiveNumberOfChildEntries
&& oldItem.notes == newItem.notes
}
return typeContentTheSame
@@ -204,6 +204,11 @@ class NodesAdapter (
&& oldItem.type == newItem.type
&& oldItem.title == newItem.title
&& oldItem.icon == newItem.icon
&& oldItem.creationTime == newItem.creationTime
&& oldItem.lastModificationTime == newItem.lastModificationTime
&& oldItem.lastAccessTime == newItem.lastAccessTime
&& oldItem.expiryTime == newItem.expiryTime
&& oldItem.expires == newItem.expires
&& oldItem.isCurrentlyExpires == newItem.isCurrentlyExpires
}
@@ -472,7 +477,10 @@ class NodesAdapter (
if (mShowNumberEntries) {
holder.numberChildren?.apply {
text = (subNode as Group)
.numberOfChildEntries
.getNumberOfChildEntries(
mNodeFilter.recursiveNumberOfEntries,
mNodeFilter.filter
)
.toString()
setTextSize(mTextSizeUnit, mNumberChildrenTextDefaultDimension, mPrefSizeMultiplier)
visibility = View.VISIBLE

View File

@@ -27,6 +27,7 @@ import android.net.Uri
import android.os.IBinder
import android.util.Base64
import android.util.Log
import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.database.element.binary.BinaryData.Companion.BASE64_FLAG
import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.services.AdvancedUnlockNotificationService
@@ -69,9 +70,11 @@ class CipherDatabaseAction(context: Context) {
@Synchronized
private fun attachService(performedAction: () -> Unit) {
applicationContext.registerReceiver(mAdvancedUnlockBroadcastReceiver, IntentFilter().apply {
addAction(AdvancedUnlockNotificationService.REMOVE_ADVANCED_UNLOCK_KEY_ACTION)
})
ContextCompat.registerReceiver(applicationContext, mAdvancedUnlockBroadcastReceiver,
IntentFilter().apply {
addAction(AdvancedUnlockNotificationService.REMOVE_ADVANCED_UNLOCK_KEY_ACTION)
}, ContextCompat.RECEIVER_EXPORTED
)
mServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, serviceBinder: IBinder?) {
@@ -97,7 +100,7 @@ class CipherDatabaseAction(context: Context) {
private fun detachService() {
try {
applicationContext.unregisterReceiver(mAdvancedUnlockBroadcastReceiver)
} catch (e: Exception) {}
} catch (_: Exception) {}
mServiceConnection?.let {
AdvancedUnlockNotificationService.unbindService(applicationContext, it)
@@ -181,6 +184,14 @@ class CipherDatabaseAction(context: Context) {
}
}
fun resetCipherParameters(databaseUri: Uri) {
containsCipherDatabase(databaseUri) { contains ->
if (contains) {
mBinder?.resetTimer()
}
}
}
fun addOrUpdateCipherDatabase(cipherEncryptDatabase: CipherEncryptDatabase,
cipherDatabaseResultListener: (() -> Unit)? = null) {
cipherEncryptDatabase.databaseUri?.let { databaseUri ->

View File

@@ -1,7 +1,6 @@
package com.kunzisoft.keepass.autofill
import android.app.assist.AssistStructure
import android.view.inputmethod.InlineSuggestionsRequest
data class AutofillComponent(val assistStructure: AssistStructure,
val compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest?)

View File

@@ -29,9 +29,12 @@ import android.graphics.BlendMode
import android.graphics.drawable.Icon
import android.os.Build
import android.service.autofill.Dataset
import android.service.autofill.Field
import android.service.autofill.FillResponse
import android.service.autofill.InlinePresentation
import android.service.autofill.Presentations
import android.util.Log
import android.view.autofill.AutofillId
import android.view.autofill.AutofillManager
import android.view.autofill.AutofillValue
import android.widget.RemoteViews
@@ -57,6 +60,7 @@ import com.kunzisoft.keepass.settings.AutofillSettingsActivity
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.LOCK_ACTION
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import kotlin.math.min
@RequiresApi(api = Build.VERSION_CODES.O)
@@ -93,41 +97,87 @@ object AutofillHelper {
database: ContextualDatabase,
remoteViewsText: String,
remoteViewsIcon: IconImage? = null): RemoteViews {
val presentation = RemoteViews(context.packageName, R.layout.item_autofill_entry)
presentation.setTextViewText(R.id.autofill_entry_text, remoteViewsText)
val remoteViews = RemoteViews(context.packageName, R.layout.item_autofill_entry)
remoteViews.setTextViewText(R.id.autofill_entry_text, remoteViewsText)
if (remoteViewsIcon != null) {
try {
database.iconDrawableFactory.getBitmapFromIcon(context,
remoteViewsIcon, ContextCompat.getColor(context, R.color.green))?.let { bitmap ->
presentation.setImageViewBitmap(R.id.autofill_entry_icon, bitmap)
remoteViews.setImageViewBitmap(R.id.autofill_entry_icon, bitmap)
}
} catch (e: Exception) {
Log.e(RemoteViews::class.java.name, "Unable to assign icon in remote view", e)
}
}
return presentation
return remoteViews
}
private fun buildDataset(context: Context,
database: ContextualDatabase,
entryInfo: EntryInfo,
struct: StructureParser.Result,
additionalBuild: ((build: Dataset.Builder) -> Unit)? = null): Dataset? {
val title = makeEntryTitle(entryInfo)
val views = newRemoteViews(context, database, title, entryInfo.icon)
val builder = Dataset.Builder(views)
builder.setId(entryInfo.id.toString())
private fun Dataset.Builder.addValueToDatasetBuilder(
id: AutofillId,
autofillValue: AutofillValue?
): Dataset.Builder {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setField(
id, autofillValue?.let {
Field.Builder()
.setValue(it)
.build()
}
)
} else {
@Suppress("DEPRECATION")
setValue(id, autofillValue)
}
Log.d(TAG, "Set Autofill value $autofillValue for id $id")
return this
}
private fun buildDatasetForEntry(context: Context,
database: ContextualDatabase,
entryInfo: EntryInfo,
struct: StructureParser.Result,
inlinePresentation: InlinePresentation?): Dataset {
val remoteViews: RemoteViews = newRemoteViews(context, database, makeEntryTitle(entryInfo), entryInfo.icon)
val datasetBuilder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Dataset.Builder(Presentations.Builder()
.apply {
inlinePresentation?.let {
setInlinePresentation(inlinePresentation)
}
}
.setDialogPresentation(remoteViews)
.setMenuPresentation(remoteViews)
.build())
} else {
@Suppress("DEPRECATION")
Dataset.Builder(remoteViews).apply {
inlinePresentation?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
setInlinePresentation(inlinePresentation)
}
}
}
}
datasetBuilder.setId(entryInfo.id.toString())
struct.usernameId?.let { usernameId ->
builder.setValue(usernameId, AutofillValue.forText(entryInfo.username))
datasetBuilder.addValueToDatasetBuilder(
usernameId,
AutofillValue.forText(entryInfo.username)
)
}
struct.passwordId?.let { passwordId ->
builder.setValue(passwordId, AutofillValue.forText(entryInfo.password))
datasetBuilder.addValueToDatasetBuilder(
passwordId,
AutofillValue.forText(entryInfo.password)
)
}
if (entryInfo.expires) {
val year = entryInfo.expiryTime.getYearInt()
val month = entryInfo.expiryTime.getMonthInt()
val year = entryInfo.expiryTime.getYear()
val month = entryInfo.expiryTime.getMonth()
val monthString = month.toString().padStart(2, '0')
val day = entryInfo.expiryTime.getDay()
val dayString = day.toString().padStart(2, '0')
@@ -135,9 +185,15 @@ object AutofillHelper {
struct.creditCardExpirationDateId?.let {
if (struct.isWebView) {
// set date string as defined in https://html.spec.whatwg.org
builder.setValue(it, AutofillValue.forText("$year\u002D$monthString"))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText("$year\u002D$monthString")
)
} else {
builder.setValue(it, AutofillValue.forDate(entryInfo.expiryTime.date.time))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forDate(entryInfo.expiryTime.toMilliseconds())
)
}
}
struct.creditCardExpirationYearId?.let {
@@ -151,34 +207,58 @@ object AutofillHelper {
}
if (yearIndex != -1) {
autofillValue = AutofillValue.forList(yearIndex)
builder.setValue(it, autofillValue)
datasetBuilder.addValueToDatasetBuilder(
it,
autofillValue
)
}
}
if (autofillValue == null) {
builder.setValue(it, AutofillValue.forText(year.toString()))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(year.toString())
)
}
}
struct.creditCardExpirationMonthId?.let {
if (struct.isWebView) {
builder.setValue(it, AutofillValue.forText(monthString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(monthString)
)
} else {
if (struct.creditCardExpirationMonthOptions != null) {
// index starts at 0
builder.setValue(it, AutofillValue.forList(month - 1))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forList(month - 1)
)
} else {
builder.setValue(it, AutofillValue.forText(monthString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(monthString)
)
}
}
}
struct.creditCardExpirationDayId?.let {
if (struct.isWebView) {
builder.setValue(it, AutofillValue.forText(dayString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(dayString)
)
} else {
if (struct.creditCardExpirationDayOptions != null) {
builder.setValue(it, AutofillValue.forList(day - 1))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forList(day - 1)
)
} else {
builder.setValue(it, AutofillValue.forText(dayString))
datasetBuilder.addValueToDatasetBuilder(
it,
AutofillValue.forText(dayString)
)
}
}
}
@@ -186,29 +266,32 @@ object AutofillHelper {
for (field in entryInfo.customFields) {
if (field.name == TemplateField.LABEL_HOLDER) {
struct.creditCardHolderId?.let { ccNameId ->
builder.setValue(ccNameId, AutofillValue.forText(field.protectedValue.stringValue))
datasetBuilder.addValueToDatasetBuilder(
ccNameId,
AutofillValue.forText(field.protectedValue.stringValue)
)
}
}
if (field.name == TemplateField.LABEL_NUMBER) {
struct.creditCardNumberId?.let { ccnId ->
builder.setValue(ccnId, AutofillValue.forText(field.protectedValue.stringValue))
datasetBuilder.addValueToDatasetBuilder(
ccnId,
AutofillValue.forText(field.protectedValue.stringValue)
)
}
}
if (field.name == TemplateField.LABEL_CVV) {
struct.cardVerificationValueId?.let { cvvId ->
builder.setValue(cvvId, AutofillValue.forText(field.protectedValue.stringValue))
datasetBuilder.addValueToDatasetBuilder(
cvvId,
AutofillValue.forText(field.protectedValue.stringValue)
)
}
}
}
additionalBuild?.invoke(builder)
return try {
builder.build()
} catch (e: Exception) {
// at least one value must be set
null
}
val dataset = datasetBuilder.build()
Log.d(TAG, "Autofill Dataset $dataset created")
return dataset
}
/**
@@ -228,8 +311,8 @@ object AutofillHelper {
return null
}
@RequiresApi(Build.VERSION_CODES.R)
@SuppressLint("RestrictedApi")
@RequiresApi(Build.VERSION_CODES.R)
private fun buildInlinePresentationForEntry(context: Context,
database: ContextualDatabase,
compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest,
@@ -239,10 +322,11 @@ object AutofillHelper {
val inlinePresentationSpecs = inlineSuggestionsRequest.inlinePresentationSpecs
val maxSuggestion = inlineSuggestionsRequest.maxSuggestionCount
if (positionItem <= maxSuggestion - 1
&& inlinePresentationSpecs.size > positionItem
) {
val inlinePresentationSpec = inlinePresentationSpecs[positionItem]
if (positionItem <= maxSuggestion - 1) {
// If positionItem is larger than the number of specs in the list, then
// the last spec is used for the remainder of the suggestions
val inlinePresentationSpec = inlinePresentationSpecs[min(positionItem, inlinePresentationSpecs.size - 1)]
// Make sure that the IME spec claims support for v1 UI template.
val imeStyle = inlinePresentationSpec.style
@@ -335,25 +419,33 @@ object AutofillHelper {
}
}
}
}
entriesInfo.forEachIndexed { _, entry ->
if (numberInlineSuggestions > 0
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& compatInlineSuggestionsRequest != null) {
responseBuilder.addDataset(buildDataset(context, database, entry, parseResult) { builder ->
buildInlinePresentationForEntry(context, database,
compatInlineSuggestionsRequest, numberInlineSuggestions--, entry
)?.let { inlinePresentation ->
builder.setInlinePresentation(inlinePresentation)
}
})
} else {
responseBuilder.addDataset(buildDataset(context, database, entry, parseResult))
try {
// Build inline presentation for compatible keyboard
var inlinePresentation: InlinePresentation? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& numberInlineSuggestions > 0
&& compatInlineSuggestionsRequest != null) {
inlinePresentation = buildInlinePresentationForEntry(
context,
database,
compatInlineSuggestionsRequest,
numberInlineSuggestions--,
entry
)
}
// Create dataset for each entry
responseBuilder.addDataset(
buildDatasetForEntry(context, database, entry, parseResult, inlinePresentation)
)
} catch (e: Exception) {
Log.e(TAG, "Unable to add dataset")
}
}
// Add a new dataset for manual selection
if (PreferencesUtil.isAutofillManualSelectionEnable(context)) {
val searchInfo = SearchInfo().apply {
applicationId = parseResult.applicationId
@@ -362,25 +454,51 @@ object AutofillHelper {
manualSelection = true
}
val manualSelectionView = RemoteViews(context.packageName, R.layout.item_autofill_select_entry)
val pendingIntent = AutofillLauncherActivity.getPendingIntentForSelection(context,
searchInfo, compatInlineSuggestionsRequest)
AutofillLauncherActivity.getPendingIntentForSelection(context,
searchInfo, compatInlineSuggestionsRequest)?.let { pendingIntent ->
parseResult.allAutofillIds().let { autofillIds ->
autofillIds.forEach { id ->
val builder = Dataset.Builder(manualSelectionView)
var inlinePresentation: InlinePresentation? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
compatInlineSuggestionsRequest?.inlineSuggestionsRequest?.let { inlineSuggestionsRequest ->
val inlinePresentationSpec =
inlineSuggestionsRequest.inlinePresentationSpecs[0]
inlinePresentation = buildInlinePresentationForManualSelection(
context,
inlinePresentationSpec,
pendingIntent
)
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
compatInlineSuggestionsRequest?.inlineSuggestionsRequest?.let { inlineSuggestionsRequest ->
val inlinePresentationSpec = inlineSuggestionsRequest.inlinePresentationSpecs[0]
val inlinePresentation = buildInlinePresentationForManualSelection(context, inlinePresentationSpec, pendingIntent)
val datasetBuilder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Dataset.Builder(Presentations.Builder()
.apply {
inlinePresentation?.let {
builder.setInlinePresentation(it)
setInlinePresentation(it)
}
}
.setDialogPresentation(manualSelectionView)
.setMenuPresentation(manualSelectionView)
.build())
} else {
@Suppress("DEPRECATION")
Dataset.Builder(manualSelectionView).apply {
inlinePresentation?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
setInlinePresentation(it)
}
}
}
builder.setValue(id, null)
builder.setAuthentication(pendingIntent.intentSender)
responseBuilder.addDataset(builder.build())
}
parseResult.allAutofillIds().let { autofillIds ->
autofillIds.forEach { id ->
datasetBuilder.addValueToDatasetBuilder(id, null)
datasetBuilder.setAuthentication(pendingIntent.intentSender)
}
val dataset = datasetBuilder.build()
Log.d(TAG, "Autofill Dataset for manual selection $dataset created")
responseBuilder.addDataset(dataset)
}
}
}
@@ -388,6 +506,7 @@ object AutofillHelper {
return try {
responseBuilder.build()
} catch (e: Exception) {
Log.e(TAG, "Unable to create Autofill response", e)
null
}
}
@@ -424,7 +543,7 @@ object AutofillHelper {
buildResponse(activity, database, entriesInfo, result, null)
}
val mReplyIntent = Intent()
Log.d(activity.javaClass.name, "Successed Autofill auth.")
Log.d(activity.javaClass.name, "Success Autofill auth.")
mReplyIntent.putExtra(
AutofillManager.EXTRA_AUTHENTICATION_RESULT,
response)
@@ -479,4 +598,6 @@ object AutofillHelper {
EntrySelectionHelper.addSearchInfoInIntent(intent, searchInfo)
activityResultLauncher?.launch(intent)
}
private val TAG = AutofillHelper::class.java.name
}

View File

@@ -45,7 +45,6 @@ import com.kunzisoft.keepass.settings.AutofillSettingsActivity
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.WebDomain
import org.joda.time.DateTime
import java.util.concurrent.atomic.AtomicBoolean
@RequiresApi(api = Build.VERSION_CODES.O)
@@ -57,7 +56,6 @@ class KeeAutofillService : AutofillService() {
private var webDomainBlocklist: Set<String>? = null
private var askToSaveData: Boolean = false
private var autofillInlineSuggestionsEnabled: Boolean = false
private var mLock = AtomicBoolean()
override fun onCreate() {
super.onCreate()
@@ -90,35 +88,37 @@ class KeeAutofillService : AutofillService() {
cancellationSignal.setOnCancelListener { Log.w(TAG, "Cancel autofill.") }
// Lock
if (!mLock.get()) {
mLock.set(true)
// Check user's settings for authenticating Responses and Datasets.
val latestStructure = request.fillContexts.last().structure
StructureParser(latestStructure).parse()?.let { parseResult ->
if (request.flags and FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST != 0) {
Log.d(TAG, "Autofill requested in compatibility mode")
} else {
Log.d(TAG, "Autofill requested in native mode")
}
// Build search info only if applicationId or webDomain are not blocked
if (autofillAllowedFor(parseResult.applicationId, applicationIdBlocklist)
&& autofillAllowedFor(parseResult.webDomain, webDomainBlocklist)) {
val searchInfo = SearchInfo().apply {
applicationId = parseResult.applicationId
webDomain = parseResult.webDomain
webScheme = parseResult.webScheme
}
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { webDomainWithoutSubDomain ->
searchInfo.webDomain = webDomainWithoutSubDomain
val inlineSuggestionsRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& autofillInlineSuggestionsEnabled) {
CompatInlineSuggestionsRequest(request)
} else {
null
}
launchSelection(mDatabase,
searchInfo,
parseResult,
inlineSuggestionsRequest,
callback)
// Check user's settings for authenticating Responses and Datasets.
val latestStructure = request.fillContexts.last().structure
StructureParser(latestStructure).parse()?.let { parseResult ->
// Build search info only if applicationId or webDomain are not blocked
if (autofillAllowedFor(parseResult.applicationId, applicationIdBlocklist)
&& autofillAllowedFor(parseResult.webDomain, webDomainBlocklist)) {
val searchInfo = SearchInfo().apply {
applicationId = parseResult.applicationId
webDomain = parseResult.webDomain
webScheme = parseResult.webScheme
}
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { webDomainWithoutSubDomain ->
searchInfo.webDomain = webDomainWithoutSubDomain
val inlineSuggestionsRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& autofillInlineSuggestionsEnabled) {
CompatInlineSuggestionsRequest(request)
} else {
null
}
launchSelection(mDatabase,
searchInfo,
parseResult,
inlineSuggestionsRequest,
callback)
}
}
}
@@ -157,139 +157,197 @@ class KeeAutofillService : AutofillService() {
searchInfo: SearchInfo,
inlineSuggestionsRequest: CompatInlineSuggestionsRequest?,
callback: FillCallback) {
var success = false
parseResult.allAutofillIds().let { autofillIds ->
if (autofillIds.isNotEmpty()) {
// If the entire Autofill Response is authenticated, AuthActivity is used
// to generate Response.
val intentSender = AutofillLauncherActivity.getPendingIntentForSelection(this,
searchInfo, inlineSuggestionsRequest).intentSender
val responseBuilder = FillResponse.Builder()
val remoteViewsUnlock: RemoteViews = if (database == null) {
if (!parseResult.webDomain.isNullOrEmpty()) {
RemoteViews(
packageName,
R.layout.item_autofill_unlock_web_domain
).apply {
setTextViewText(
R.id.autofill_web_domain_text,
parseResult.webDomain
)
}
} else if (!parseResult.applicationId.isNullOrEmpty()) {
RemoteViews(packageName, R.layout.item_autofill_unlock_app_id).apply {
setTextViewText(
R.id.autofill_app_id_text,
parseResult.applicationId
)
AutofillLauncherActivity.getPendingIntentForSelection(this,
searchInfo, inlineSuggestionsRequest)?.intentSender?.let { intentSender ->
val responseBuilder = FillResponse.Builder()
val remoteViewsUnlock: RemoteViews = if (database == null) {
if (!parseResult.webDomain.isNullOrEmpty()) {
RemoteViews(
packageName,
R.layout.item_autofill_unlock_web_domain
).apply {
setTextViewText(
R.id.autofill_web_domain_text,
parseResult.webDomain
)
}
} else if (!parseResult.applicationId.isNullOrEmpty()) {
RemoteViews(packageName, R.layout.item_autofill_unlock_app_id).apply {
setTextViewText(
R.id.autofill_app_id_text,
parseResult.applicationId
)
}
} else {
RemoteViews(packageName, R.layout.item_autofill_unlock)
}
} else {
RemoteViews(packageName, R.layout.item_autofill_unlock)
}
} else {
if (!parseResult.webDomain.isNullOrEmpty()) {
RemoteViews(
packageName,
R.layout.item_autofill_select_entry_web_domain
).apply {
setTextViewText(
R.id.autofill_web_domain_text,
parseResult.webDomain
)
if (!parseResult.webDomain.isNullOrEmpty()) {
RemoteViews(
packageName,
R.layout.item_autofill_select_entry_web_domain
).apply {
setTextViewText(
R.id.autofill_web_domain_text,
parseResult.webDomain
)
}
} else if (!parseResult.applicationId.isNullOrEmpty()) {
RemoteViews(
packageName,
R.layout.item_autofill_select_entry_app_id
).apply {
setTextViewText(
R.id.autofill_app_id_text,
parseResult.applicationId
)
}
} else {
RemoteViews(packageName, R.layout.item_autofill_select_entry)
}
} else if (!parseResult.applicationId.isNullOrEmpty()) {
RemoteViews(packageName, R.layout.item_autofill_select_entry_app_id).apply {
setTextViewText(
R.id.autofill_app_id_text,
parseResult.applicationId
)
}
} else {
RemoteViews(packageName, R.layout.item_autofill_select_entry)
}
}
// Tell the autofill framework the interest to save credentials
if (askToSaveData) {
var types: Int = SaveInfo.SAVE_DATA_TYPE_GENERIC
val requiredIds = ArrayList<AutofillId>()
val optionalIds = ArrayList<AutofillId>()
// Tell the autofill framework the interest to save credentials
if (askToSaveData) {
var types: Int = SaveInfo.SAVE_DATA_TYPE_GENERIC
val requiredIds = ArrayList<AutofillId>()
val optionalIds = ArrayList<AutofillId>()
// Only if at least a password
parseResult.passwordId?.let { passwordInfo ->
parseResult.usernameId?.let { usernameInfo ->
types = types or SaveInfo.SAVE_DATA_TYPE_USERNAME
requiredIds.add(usernameInfo)
// Only if at least a password
parseResult.passwordId?.let { passwordInfo ->
parseResult.usernameId?.let { usernameInfo ->
types = types or SaveInfo.SAVE_DATA_TYPE_USERNAME
requiredIds.add(usernameInfo)
}
types = types or SaveInfo.SAVE_DATA_TYPE_PASSWORD
requiredIds.add(passwordInfo)
}
types = types or SaveInfo.SAVE_DATA_TYPE_PASSWORD
requiredIds.add(passwordInfo)
}
// or a credit card form
if (requiredIds.isEmpty()) {
parseResult.creditCardNumberId?.let { numberId ->
types = types or SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD
requiredIds.add(numberId)
Log.d(TAG, "Asking to save credit card number")
// or a credit card form
if (requiredIds.isEmpty()) {
parseResult.creditCardNumberId?.let { numberId ->
types = types or SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD
requiredIds.add(numberId)
Log.d(TAG, "Asking to save credit card number")
}
parseResult.creditCardExpirationDateId?.let { id -> optionalIds.add(id) }
parseResult.creditCardExpirationYearId?.let { id -> optionalIds.add(id) }
parseResult.creditCardExpirationMonthId?.let { id -> optionalIds.add(id) }
parseResult.creditCardHolderId?.let { id -> optionalIds.add(id) }
parseResult.cardVerificationValueId?.let { id -> optionalIds.add(id) }
}
parseResult.creditCardExpirationDateId?.let { id -> optionalIds.add(id) }
parseResult.creditCardExpirationYearId?.let { id -> optionalIds.add(id) }
parseResult.creditCardExpirationMonthId?.let { id -> optionalIds.add(id) }
parseResult.creditCardHolderId?.let { id -> optionalIds.add(id) }
parseResult.cardVerificationValueId?.let { id -> optionalIds.add(id) }
}
if (requiredIds.isNotEmpty()) {
val builder = SaveInfo.Builder(types, requiredIds.toTypedArray())
if (optionalIds.isNotEmpty()) {
builder.setOptionalIds(optionalIds.toTypedArray())
if (requiredIds.isNotEmpty()) {
val builder = SaveInfo.Builder(types, requiredIds.toTypedArray())
if (optionalIds.isNotEmpty()) {
builder.setOptionalIds(optionalIds.toTypedArray())
}
responseBuilder.setSaveInfo(builder.build())
}
responseBuilder.setSaveInfo(builder.build())
}
}
// Build inline presentation
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& autofillInlineSuggestionsEnabled) {
var inlinePresentation: InlinePresentation? = null
inlineSuggestionsRequest?.inlineSuggestionsRequest?.let { inlineSuggestionsRequest ->
val inlinePresentationSpecs = inlineSuggestionsRequest.inlinePresentationSpecs
if (inlineSuggestionsRequest.maxSuggestionCount > 0
&& inlinePresentationSpecs.size > 0) {
val inlinePresentationSpec = inlinePresentationSpecs[0]
// Build inline presentation
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& autofillInlineSuggestionsEnabled
) {
var inlinePresentation: InlinePresentation? = null
inlineSuggestionsRequest?.inlineSuggestionsRequest?.let { inlineSuggestionsRequest ->
val inlinePresentationSpecs =
inlineSuggestionsRequest.inlinePresentationSpecs
if (inlineSuggestionsRequest.maxSuggestionCount > 0
&& inlinePresentationSpecs.size > 0
) {
val inlinePresentationSpec = inlinePresentationSpecs[0]
// Make sure that the IME spec claims support for v1 UI template.
val imeStyle = inlinePresentationSpec.style
if (UiVersions.getVersions(imeStyle).contains(UiVersions.INLINE_UI_VERSION_1)) {
// Build the content for IME UI
inlinePresentation = InlinePresentation(
// Make sure that the IME spec claims support for v1 UI template.
val imeStyle = inlinePresentationSpec.style
if (UiVersions.getVersions(imeStyle)
.contains(UiVersions.INLINE_UI_VERSION_1)
) {
// Build the content for IME UI
inlinePresentation = InlinePresentation(
InlineSuggestionUi.newContentBuilder(
PendingIntent.getActivity(this,
0,
Intent(this, AutofillSettingsActivity::class.java),
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE
} else {
0
})
PendingIntent.getActivity(
this,
0,
Intent(this, AutofillSettingsActivity::class.java),
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE
} else {
0
}
)
).apply {
setContentDescription(getString(R.string.autofill_sign_in_prompt))
setTitle(getString(R.string.autofill_sign_in_prompt))
setStartIcon(Icon.createWithResource(this@KeeAutofillService, R.mipmap.ic_launcher_round).apply {
setTintBlendMode(BlendMode.DST)
})
}.build().slice, inlinePresentationSpec, false)
setStartIcon(
Icon.createWithResource(
this@KeeAutofillService,
R.mipmap.ic_launcher_round
).apply {
setTintBlendMode(BlendMode.DST)
})
}.build().slice, inlinePresentationSpec, false
)
}
}
}
// Build response
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
try {
// Buggy method on some API 33 devices
responseBuilder.setAuthentication(
autofillIds,
intentSender,
Presentations.Builder().apply {
inlinePresentation?.let {
setInlinePresentation(it)
}
setDialogPresentation(remoteViewsUnlock)
}.build()
)
} catch (e: Exception) {
Log.e(TAG, "Unable to use the new setAuthentication method.", e)
@Suppress("DEPRECATION")
responseBuilder.setAuthentication(
autofillIds,
intentSender,
remoteViewsUnlock,
inlinePresentation
)
}
} else {
@Suppress("DEPRECATION")
responseBuilder.setAuthentication(
autofillIds,
intentSender,
remoteViewsUnlock,
inlinePresentation
)
}
} else {
@Suppress("DEPRECATION")
responseBuilder.setAuthentication(
autofillIds,
intentSender,
remoteViewsUnlock
)
}
// Build response
responseBuilder.setAuthentication(autofillIds, intentSender, remoteViewsUnlock, inlinePresentation)
} else {
responseBuilder.setAuthentication(autofillIds, intentSender, remoteViewsUnlock)
success = true
callback.onSuccess(responseBuilder.build())
}
callback.onSuccess(responseBuilder.build())
}
}
if (!success)
callback.onFailure("Unable to get Autofill ids for UI selection")
}
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
var success = false
if (askToSaveData) {
val latestStructure = request.fillContexts.last().structure
StructureParser(latestStructure).parse(true)?.let { parseResult ->
@@ -332,14 +390,16 @@ class KeeAutofillService : AutofillService() {
// callback.onSuccess(AutofillLauncherActivity.getAuthIntentSenderForRegistration(this,
// registerInfo))
//} else {
AutofillLauncherActivity.launchForRegistration(this, registerInfo)
callback.onSuccess()
AutofillLauncherActivity.launchForRegistration(this, registerInfo)
success = true
callback.onSuccess()
//}
return
}
}
}
callback.onFailure("Saving form values is not allowed")
if (!success) {
callback.onFailure("Saving form values is not allowed")
}
}
override fun onConnected() {
@@ -348,7 +408,6 @@ class KeeAutofillService : AutofillService() {
}
override fun onDisconnected() {
mLock.set(false)
Log.d(TAG, "onDisconnected")
}

View File

@@ -37,7 +37,6 @@ import kotlin.collections.ArrayList
@RequiresApi(api = Build.VERSION_CODES.O)
class StructureParser(private val structure: AssistStructure) {
private var result: Result? = null
private var usernameNeeded = true
private var usernameIdCandidate: AutofillId? = null
private var usernameValueCandidate: AutofillValue? = null
@@ -105,7 +104,7 @@ class StructureParser(private val structure: AssistStructure) {
if (node.autofillId != null) {
// Parse methods
val hints = node.autofillHints
if (hints != null && hints.isNotEmpty()) {
if (!hints.isNullOrEmpty()) {
if (parseNodeByAutofillHint(node))
returnValue = true
} else if (parseNodeByHtmlAttributes(node))
@@ -134,16 +133,37 @@ class StructureParser(private val structure: AssistStructure) {
it.contains(View.AUTOFILL_HINT_USERNAME, true)
|| it.contains(View.AUTOFILL_HINT_EMAIL_ADDRESS, true)
|| it.contains("email", true)
|| it.contains(View.AUTOFILL_HINT_PHONE, true) -> {
result?.usernameId = autofillId
result?.usernameValue = node.autofillValue
Log.d(TAG, "Autofill username hint")
|| it.contains("login", true) -> {
// Replace username until we have a password
if (result?.passwordId == null) {
result?.usernameId = autofillId
result?.usernameValue = node.autofillValue
Log.d(TAG, "Autofill username hint if no password")
} else {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill username hint if password")
}
}
it.contains(View.AUTOFILL_HINT_PHONE, true) -> {
if (usernameIdCandidate == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill phone")
}
}
it.contains(View.AUTOFILL_HINT_PASSWORD, true) -> {
// Password Id changed if it's the second times we are here,
// So the last username candidate is most appropriate
if (result?.passwordId != null) {
result?.usernameId = usernameIdCandidate
result?.usernameValue = usernameValueCandidate
}
result?.passwordId = autofillId
result?.passwordValue = node.autofillValue
Log.d(TAG, "Autofill password hint")
return true
// Comment "return" to check all the tree
// return true
}
it.equals("cc-name", true) -> {
Log.d(TAG, "Autofill credit card name hint")
@@ -279,14 +299,19 @@ class StructureParser(private val structure: AssistStructure) {
"type" -> {
when (pairAttribute.second.lowercase(Locale.ENGLISH)) {
"tel", "email" -> {
result?.usernameId = autofillId
result?.usernameValue = node.autofillValue
Log.d(TAG, "Autofill username web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
if (result?.passwordId == null) {
result?.usernameId = autofillId
result?.usernameValue = node.autofillValue
Log.d(TAG, "Autofill username web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
}
}
"text" -> {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill username candidate web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
// Assume username is before password
if (result?.passwordId == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill username candidate web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
}
}
"password" -> {
result?.passwordId = autofillId
@@ -315,85 +340,128 @@ class StructureParser(private val structure: AssistStructure) {
return "0x${"%08x".format(inputType)}"
}
private fun manageTypeText(
node: AssistStructure.ViewNode,
autofillId: AutofillId?,
inputType: Int
): Boolean {
when {
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS) -> {
if (result?.passwordId == null) {
result?.usernameId = autofillId
result?.usernameValue = node.autofillValue
Log.d(TAG, "Autofill username android text type: ${showHexInputType(inputType)}")
}
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_NORMAL,
InputType.TYPE_TEXT_VARIATION_PERSON_NAME,
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) -> {
// Assume the username field is before the password field
if (result?.passwordId == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
}
Log.d(TAG, "Autofill username candidate android text type: ${showHexInputType(inputType)}")
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) -> {
// Some forms used visible password as username
if (result?.passwordId == null &&
usernameIdCandidate == null && usernameValueCandidate == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill visible password android text type (as username): ${showHexInputType(inputType)}")
} else if (result?.passwordId == null && result?.passwordValue == null) {
result?.passwordId = autofillId
result?.passwordValue = node.autofillValue
Log.d(TAG, "Autofill visible password android text type (as password): ${showHexInputType(inputType)}")
}
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_PASSWORD,
InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD) -> {
result?.passwordId = autofillId
result?.passwordValue = node.autofillValue
Log.d(TAG, "Autofill password android text type: ${showHexInputType(inputType)}")
return true
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT,
InputType.TYPE_TEXT_VARIATION_FILTER,
InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE,
InputType.TYPE_TEXT_VARIATION_PHONETIC,
InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS,
InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE,
InputType.TYPE_TEXT_VARIATION_URI) -> {
// Type not used
Log.d(TAG, "Autofill not used android text type: ${showHexInputType(inputType)}")
}
else -> {
Log.d(TAG, "Autofill unknown android text type: ${showHexInputType(inputType)}")
}
}
return false
}
private fun manageTypeNumber(
node: AssistStructure.ViewNode,
autofillId: AutofillId?,
inputType: Int
): Boolean {
when {
inputIsVariationType(inputType,
InputType.TYPE_NUMBER_VARIATION_NORMAL) -> {
if (usernameIdCandidate == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill username candidate android number type: ${showHexInputType(inputType)}")
}
}
inputIsVariationType(inputType,
InputType.TYPE_NUMBER_VARIATION_PASSWORD) -> {
result?.passwordId = autofillId
result?.passwordValue = node.autofillValue
Log.d(TAG, "Autofill password android number type: ${showHexInputType(inputType)}")
return true
}
else -> {
Log.d(TAG, "Autofill unknown android number type: ${showHexInputType(inputType)}")
}
}
return false
}
private fun manageTypeNull(
node: AssistStructure.ViewNode,
autofillId: AutofillId?,
inputType: Int
): Boolean {
if (node.className == "android.widget.EditText") {
Log.d(TAG, "Autofill null android input type class: ${showHexInputType(inputType)}" +
", get the EditText node class name!")
if (result?.passwordId == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
}
}
return false
}
private fun parseNodeByAndroidInput(node: AssistStructure.ViewNode): Boolean {
val autofillId = node.autofillId
val inputType = node.inputType
when (inputType and InputType.TYPE_MASK_CLASS) {
InputType.TYPE_CLASS_TEXT -> {
when {
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS) -> {
result?.usernameId = autofillId
result?.usernameValue = node.autofillValue
Log.d(TAG, "Autofill username android text type: ${showHexInputType(inputType)}")
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_NORMAL,
InputType.TYPE_TEXT_VARIATION_PERSON_NAME,
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) -> {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill username candidate android text type: ${showHexInputType(inputType)}")
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) -> {
// Some forms used visible password as username
if (usernameIdCandidate == null && usernameValueCandidate == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill visible password android text type (as username): ${showHexInputType(inputType)}")
} else if (result?.passwordId == null && result?.passwordValue == null) {
result?.passwordId = autofillId
result?.passwordValue = node.autofillValue
Log.d(TAG, "Autofill visible password android text type (as password): ${showHexInputType(inputType)}")
usernameNeeded = false
}
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_PASSWORD,
InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD) -> {
result?.passwordId = autofillId
result?.passwordValue = node.autofillValue
Log.d(TAG, "Autofill password android text type: ${showHexInputType(inputType)}")
return true
}
inputIsVariationType(inputType,
InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT,
InputType.TYPE_TEXT_VARIATION_FILTER,
InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE,
InputType.TYPE_TEXT_VARIATION_PHONETIC,
InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS,
InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE,
InputType.TYPE_TEXT_VARIATION_URI) -> {
// Type not used
}
else -> {
Log.d(TAG, "Autofill unknown android text type: ${showHexInputType(inputType)}")
}
}
return manageTypeText(node, autofillId, inputType)
}
InputType.TYPE_CLASS_NUMBER -> {
when {
inputIsVariationType(inputType,
InputType.TYPE_NUMBER_VARIATION_NORMAL) -> {
if (usernameIdCandidate == null) {
usernameIdCandidate = autofillId
usernameValueCandidate = node.autofillValue
Log.d(TAG, "Autofill username candidate android number type: ${showHexInputType(inputType)}")
}
}
inputIsVariationType(inputType,
InputType.TYPE_NUMBER_VARIATION_PASSWORD) -> {
result?.passwordId = autofillId
result?.passwordValue = node.autofillValue
Log.d(TAG, "Autofill password android number type: ${showHexInputType(inputType)}")
return true
}
else -> {
Log.d(TAG, "Autofill unknown android number type: ${showHexInputType(inputType)}")
}
}
return manageTypeNumber(node, autofillId, inputType)
}
InputType.TYPE_NULL -> {
return manageTypeNull(node, autofillId, inputType)
}
}
return false
@@ -422,58 +490,14 @@ class StructureParser(private val structure: AssistStructure) {
var creditCardExpirationDayOptions: Array<CharSequence>? = null
var usernameId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var passwordId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var creditCardHolderId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var creditCardNumberId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var creditCardExpirationDateId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var creditCardExpirationYearId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var creditCardExpirationMonthId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var creditCardExpirationDayId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
var cardVerificationValueId: AutofillId? = null
set(value) {
if (field == null)
field = value
}
fun allAutofillIds(): Array<AutofillId> {
val all = ArrayList<AutofillId>()
@@ -500,13 +524,13 @@ class StructureParser(private val structure: AssistStructure) {
var usernameValue: AutofillValue? = null
set(value) {
if (allowSaveValues && field == null)
if (allowSaveValues)
field = value
}
var passwordValue: AutofillValue? = null
set(value) {
if (allowSaveValues && field == null)
if (allowSaveValues)
field = value
}

View File

@@ -566,6 +566,7 @@ class AdvancedUnlockFragment: Fragment(), AdvancedUnlockManager.AdvancedUnlockCa
this.decryptedValue = decryptedValue
}
)
cipherDatabaseAction.resetCipherParameters(databaseUri)
}
}

View File

@@ -40,6 +40,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.RECEIVER_NOT_EXPORTED
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.kunzisoft.keepass.R
@@ -182,8 +183,11 @@ class DatabaseTaskProvider(
private var databaseInfoListener = object:
DatabaseTaskNotificationService.DatabaseInfoListener {
override fun onDatabaseInfoChanged(previousDatabaseInfo: SnapFileDatabaseInfo,
newDatabaseInfo: SnapFileDatabaseInfo) {
override fun onDatabaseInfoChanged(
previousDatabaseInfo: SnapFileDatabaseInfo,
newDatabaseInfo: SnapFileDatabaseInfo,
readOnlyDatabase: Boolean
) {
activity?.let { activity ->
activity.lifecycleScope.launch {
if (databaseChangedDialogFragment == null) {
@@ -195,7 +199,8 @@ class DatabaseTaskProvider(
if (progressTaskDialogFragment == null) {
databaseChangedDialogFragment = DatabaseChangedDialogFragment.getInstance(
previousDatabaseInfo,
newDatabaseInfo
newDatabaseInfo,
readOnlyDatabase
)
databaseChangedDialogFragment?.actionDatabaseListener =
mActionDatabaseListener
@@ -326,11 +331,11 @@ class DatabaseTaskProvider(
}
}
}
context.registerReceiver(databaseTaskBroadcastReceiver,
ContextCompat.registerReceiver(context, databaseTaskBroadcastReceiver,
IntentFilter().apply {
addAction(DATABASE_START_TASK_ACTION)
addAction(DATABASE_STOP_TASK_ACTION)
}
}, RECEIVER_NOT_EXPORTED
)
// Check if a service is currently running else do nothing

View File

@@ -44,14 +44,17 @@ open class SaveDatabaseRunnable(
override fun onActionRun() {
database.checkVersion()
if (saveDatabase && result.isSuccess) {
// Save database in all cases if it's a copy
if ((databaseCopyUri != null || saveDatabase) && result.isSuccess) {
try {
val contentResolver = context.contentResolver
// Build temp database file to avoid file corruption if error
database.saveData(
cacheFile = File(context.cacheDir, databaseCopyUri.hashCode().toString()),
databaseOutputStream = contentResolver
.getUriOutputStream(databaseCopyUri ?: database.fileUri),
databaseOutputStream = {
contentResolver
.getUriOutputStream(databaseCopyUri ?: database.fileUri)
},
isNewLocation = databaseCopyUri == null,
mainCredential?.toMasterCredential(contentResolver),
challengeResponseRetriever)

View File

@@ -0,0 +1,3 @@
package com.kunzisoft.keepass.model
data class DataDate(val year: Int, val month: Int, val day: Int)

View File

@@ -0,0 +1,3 @@
package com.kunzisoft.keepass.model
data class DataTime(val hour: Int, val minute: Int)

View File

@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.password
import android.content.res.Resources
import android.graphics.Color
import android.text.Editable
import android.text.Spannable
import android.text.SpannableString
import android.text.SpannableStringBuilder
@@ -253,51 +254,62 @@ class PasswordGenerator(private val resources: Resources) {
return charSet.toString()
}
fun colorizedPassword(editable: Editable?) {
editable.toString().forEachIndexed { index, char ->
colorFromChar(char)?.let { color ->
editable?.setSpan(
ForegroundColorSpan(color),
index,
index + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
fun getColorizedPassword(password: String): Spannable {
val spannableString = SpannableStringBuilder()
if (password.isNotEmpty()) {
password.forEach {
when {
UPPERCASE_CHARS.contains(it)||
LOWERCASE_CHARS.contains(it) -> {
spannableString.append(it)
}
DIGIT_CHARS.contains(it) -> {
// RED
spannableString.append(colorizeChar(it, Color.rgb(246, 79, 62)))
}
SPECIAL_CHARS.contains(it) -> {
// Blue
spannableString.append(colorizeChar(it, Color.rgb(39, 166, 228)))
}
MINUS_CHAR.contains(it)||
UNDERLINE_CHAR.contains(it)||
BRACKET_CHARS.contains(it) -> {
// Purple
spannableString.append(colorizeChar(it, Color.rgb(185, 38, 209)))
}
extendedChars().contains(it) -> {
// Green
spannableString.append(colorizeChar(it, Color.rgb(44, 181, 50)))
}
else -> {
spannableString.append(it)
}
}
password.forEach { char ->
colorFromChar(char)?.let { color ->
val spannableColorChar = SpannableString(char.toString())
spannableColorChar.setSpan(
ForegroundColorSpan(color),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
spannableString.append(spannableColorChar)
} ?: spannableString.append(char)
}
}
return spannableString
}
private fun colorizeChar(char: Char, color: Int): Spannable {
val spannableColorChar = SpannableString(char.toString())
spannableColorChar.setSpan(
ForegroundColorSpan(color),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
return spannableColorChar
private fun colorFromChar(char: Char): Int? {
return when {
DIGIT_CHARS.contains(char) -> {
// RED
Color.rgb(246, 79, 62)
}
SPECIAL_CHARS.contains(char) -> {
// Blue
Color.rgb(39, 166, 228)
}
MINUS_CHAR.contains(char)||
UNDERLINE_CHAR.contains(char)||
BRACKET_CHARS.contains(char) -> {
// Purple
Color.rgb(185, 38, 209)
}
extendedChars().contains(char) -> {
// Green
Color.rgb(44, 181, 50)
}
else -> {
null
}
}
}
}
}

View File

@@ -26,7 +26,9 @@ class AdvancedUnlockNotificationService : NotificationService() {
return mTempCipherDao.firstOrNull { it.databaseUri == databaseUri.toString()}
}
fun addOrUpdateCipherDatabase(cipherDatabaseEntity: CipherDatabaseEntity) {
val cipherDatabaseRetrieve = mTempCipherDao.firstOrNull { it.databaseUri == cipherDatabaseEntity.databaseUri }
val cipherDatabaseRetrieve = mTempCipherDao.firstOrNull {
it.databaseUri == cipherDatabaseEntity.databaseUri
}
cipherDatabaseRetrieve?.replaceContent(cipherDatabaseEntity)
?: mTempCipherDao.add(cipherDatabaseEntity)
}
@@ -35,6 +37,9 @@ class AdvancedUnlockNotificationService : NotificationService() {
mTempCipherDao.remove(it)
}
}
fun resetTimer() {
resetTimeJob()
}
fun deleteAll() {
mTempCipherDao.clear()
}
@@ -86,11 +91,19 @@ class AdvancedUnlockNotificationService : NotificationService() {
val notificationTimeoutMilliSecs = PreferencesUtil.getAdvancedUnlockTimeout(this)
// Not necessarily a foreground service
if (mTimerJob == null && notificationTimeoutMilliSecs != TimeoutHelper.NEVER) {
defineTimerJob(notificationBuilder, notificationTimeoutMilliSecs) {
defineTimerJob(
notificationBuilder,
NotificationServiceType.ADVANCED_UNLOCK,
notificationTimeoutMilliSecs
) {
sendBroadcast(Intent(REMOVE_ADVANCED_UNLOCK_KEY_ACTION))
}
} else {
startForeground(notificationId, notificationBuilder.build())
startForegroundCompat(
notificationId,
notificationBuilder,
NotificationServiceType.ADVANCED_UNLOCK
)
}
return mActionTaskBinder

View File

@@ -36,13 +36,13 @@ import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.*
import java.util.LinkedList
import java.util.concurrent.CopyOnWriteArrayList
@@ -282,15 +282,21 @@ class AttachmentFileNotificationService: LockNotificationService() {
AttachmentState.ERROR -> {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
try {
notificationManager?.notify(
attachmentNotification.notificationId,
builder.build()
)
checkNotificationsPermission(this) {
notificationManager?.notify(
attachmentNotification.notificationId,
builder.build()
)
}
} catch (e: SecurityException) {
Log.e(TAG, "Unable to notify the attachment state", e)
}
} else -> {
startForeground(attachmentNotification.notificationId, builder.build())
startForegroundCompat(
attachmentNotification.notificationId,
builder,
NotificationServiceType.ATTACHMENT
)
}
}
}

View File

@@ -19,16 +19,12 @@
*/
package com.kunzisoft.keepass.services
import android.Manifest
import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
@@ -196,23 +192,29 @@ class ClipboardEntryNotificationService : LockNotificationService() {
//Get settings
val notificationTimeoutMilliSecs = PreferencesUtil.getClipboardTimeout(this)
if (notificationTimeoutMilliSecs != NEVER) {
defineTimerJob(builder, notificationTimeoutMilliSecs, {
val newGeneratedValue = fieldToCopy.getGeneratedValue(mEntryInfo)
// New auto generated value
if (generatedValue != newGeneratedValue) {
generatedValue = newGeneratedValue
clipboardHelper?.copyToClipboard(
fieldToCopy.label,
generatedValue,
fieldToCopy.isSensitive
)
defineTimerJob(
builder,
NotificationServiceType.CLIPBOARD,
notificationTimeoutMilliSecs,
{
val newGeneratedValue = fieldToCopy.getGeneratedValue(mEntryInfo)
// New auto generated value
if (generatedValue != newGeneratedValue) {
generatedValue = newGeneratedValue
clipboardHelper?.copyToClipboard(
fieldToCopy.label,
generatedValue,
fieldToCopy.isSensitive
)
}
},
{
stopNotificationAndSendLockIfNeeded()
// Clean password only if no next field
if (nextFields.size <= 0)
clipboardHelper?.cleanClipboard()
}
}) {
stopNotificationAndSendLockIfNeeded()
// Clean password only if no next field
if (nextFields.size <= 0)
clipboardHelper?.cleanClipboard()
}
)
} else {
// No timer
checkNotificationsPermission {
@@ -226,12 +228,11 @@ class ClipboardEntryNotificationService : LockNotificationService() {
}
private fun checkNotificationsPermission(action: () -> Unit) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED) {
action.invoke()
} else {
showPermissionErrorIfNeeded(this)
}
checkNotificationsPermission(
this,
PreferencesUtil.isClipboardNotificationsEnable(this),
action
)
}
override fun onTaskRemoved(rootIntent: Intent?) {
@@ -255,26 +256,14 @@ class ClipboardEntryNotificationService : LockNotificationService() {
const val EXTRA_CLIPBOARD_FIELDS = "EXTRA_CLIPBOARD_FIELDS"
const val ACTION_CLEAN_CLIPBOARD = "ACTION_CLEAN_CLIPBOARD"
private fun showPermissionErrorIfNeeded(context: Context) {
if (PreferencesUtil.isClipboardNotificationsEnable(context)) {
Toast.makeText(context, R.string.warning_copy_permission, Toast.LENGTH_LONG).show()
}
}
fun checkAndLaunchNotification(
activity: Activity,
entry: EntryInfo
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
activity,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED) {
launchNotificationIfAllowed(activity, entry)
} else {
showPermissionErrorIfNeeded(activity)
}
} else {
checkNotificationsPermission(
activity,
PreferencesUtil.isClipboardNotificationsEnable(activity)
) {
launchNotificationIfAllowed(activity, entry)
}
}

View File

@@ -36,10 +36,24 @@ import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.ProgressMessage
import com.kunzisoft.keepass.database.action.*
import com.kunzisoft.keepass.database.action.CreateDatabaseRunnable
import com.kunzisoft.keepass.database.action.LoadDatabaseRunnable
import com.kunzisoft.keepass.database.action.MergeDatabaseRunnable
import com.kunzisoft.keepass.database.action.ReloadDatabaseRunnable
import com.kunzisoft.keepass.database.action.RemoveUnlinkedDataDatabaseRunnable
import com.kunzisoft.keepass.database.action.SaveDatabaseRunnable
import com.kunzisoft.keepass.database.action.UpdateCompressionBinariesDatabaseRunnable
import com.kunzisoft.keepass.database.action.history.DeleteEntryHistoryDatabaseRunnable
import com.kunzisoft.keepass.database.action.history.RestoreEntryHistoryDatabaseRunnable
import com.kunzisoft.keepass.database.action.node.*
import com.kunzisoft.keepass.database.action.node.ActionNodesValues
import com.kunzisoft.keepass.database.action.node.AddEntryRunnable
import com.kunzisoft.keepass.database.action.node.AddGroupRunnable
import com.kunzisoft.keepass.database.action.node.AfterActionNodesFinish
import com.kunzisoft.keepass.database.action.node.CopyNodesRunnable
import com.kunzisoft.keepass.database.action.node.DeleteNodesRunnable
import com.kunzisoft.keepass.database.action.node.MoveNodesRunnable
import com.kunzisoft.keepass.database.action.node.UpdateEntryRunnable
import com.kunzisoft.keepass.database.action.node.UpdateGroupRunnable
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
@@ -62,9 +76,17 @@ import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.utils.getParcelableList
import com.kunzisoft.keepass.utils.putParcelableList
import com.kunzisoft.keepass.viewmodels.FileDatabaseInfo
import kotlinx.coroutines.*
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import java.util.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.util.UUID
open class DatabaseTaskNotificationService : LockNotificationService(), ProgressTaskUpdater {
@@ -139,6 +161,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
fun onDatabaseInfoChanged(
previousDatabaseInfo: SnapFileDatabaseInfo,
newDatabaseInfo: SnapFileDatabaseInfo,
readOnlyDatabase: Boolean
)
}
@@ -197,8 +220,11 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
// Call listener to indicate a change in database info
if (!mSaveState && previousDatabaseInfo != null) {
mDatabaseInfoListeners.forEach { listener ->
listener.onDatabaseInfoChanged(previousDatabaseInfo,
lastFileDatabaseInfo)
listener.onDatabaseInfoChanged(
previousDatabaseInfo,
lastFileDatabaseInfo,
mDatabase?.isReadOnly ?: true
)
}
}
mSnapFileDatabaseInfo = lastFileDatabaseInfo
@@ -565,7 +591,11 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
}
// Create the notification
startForeground(notificationId, notificationBuilder.build())
startForegroundCompat(
notificationId,
notificationBuilder,
NotificationServiceType.DATABASE_TASK
)
}
private fun removeIntentData(intent: Intent?) {
@@ -831,6 +861,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
if (intent.hasExtra(MAIN_CREDENTIAL_KEY)) {
databaseToMergeMainCredential = intent.getParcelableExtraCompat(MAIN_CREDENTIAL_KEY)
}
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
return MergeDatabaseRunnable(
this,
databaseToMergeUri,
@@ -839,7 +870,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
retrieveResponseFromChallenge(hardwareKey, seed)
},
database,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
{ hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
},
@@ -932,12 +963,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
val parentId: NodeId<*>? = intent.getParcelableExtraCompat(PARENT_ID_KEY)
val newGroup: Group? = intent.getParcelableExtraCompat(GROUP_KEY)
if (parentId == null || newGroup == null) return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getGroupById(parentId)?.let { parent ->
AddGroupRunnable(this,
database,
newGroup,
parent,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
AfterActionNodesRunnable()
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -959,12 +991,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
val groupId: NodeId<*>? = intent.getParcelableExtraCompat(GROUP_ID_KEY)
val newGroup: Group? = intent.getParcelableExtraCompat(GROUP_KEY)
if (groupId == null || newGroup == null) return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getGroupById(groupId)?.let { oldGroup ->
UpdateGroupRunnable(this,
database,
oldGroup,
newGroup,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
AfterActionNodesRunnable()
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -986,12 +1019,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
val parentId: NodeId<*>? = intent.getParcelableExtraCompat(PARENT_ID_KEY)
val newEntry: Entry? = intent.getParcelableExtraCompat(ENTRY_KEY)
if (parentId == null || newEntry == null) return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getGroupById(parentId)?.let { parent ->
AddEntryRunnable(this,
database,
newEntry,
parent,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
AfterActionNodesRunnable()
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -1013,12 +1047,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
val entryId: NodeId<UUID>? = intent.getParcelableExtraCompat(ENTRY_ID_KEY)
val newEntry: Entry? = intent.getParcelableExtraCompat(ENTRY_KEY)
if (entryId == null || newEntry == null) return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getEntryById(entryId)?.let { oldEntry ->
UpdateEntryRunnable(this,
database,
oldEntry,
newEntry,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
AfterActionNodesRunnable()
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -1039,12 +1074,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
&& intent.hasExtra(SAVE_DATABASE_KEY)
) {
val parentId: NodeId<*> = intent.getParcelableExtraCompat(PARENT_ID_KEY) ?: return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getGroupById(parentId)?.let { newParent ->
CopyNodesRunnable(this,
database,
getListNodesFromBundle(database, intent.extras!!),
newParent,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
AfterActionNodesRunnable()
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -1065,12 +1101,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
&& intent.hasExtra(SAVE_DATABASE_KEY)
) {
val parentId: NodeId<*> = intent.getParcelableExtraCompat(PARENT_ID_KEY) ?: return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getGroupById(parentId)?.let { newParent ->
MoveNodesRunnable(this,
database,
getListNodesFromBundle(database, intent.extras!!),
newParent,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
AfterActionNodesRunnable()
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -1089,11 +1126,12 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
&& intent.hasExtra(ENTRIES_ID_KEY)
&& intent.hasExtra(SAVE_DATABASE_KEY)
) {
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
DeleteNodesRunnable(this,
database,
getListNodesFromBundle(database, intent.extras!!),
resources.getString(R.string.recycle_bin),
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
AfterActionNodesRunnable()
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -1112,12 +1150,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
&& intent.hasExtra(SAVE_DATABASE_KEY)
) {
val entryId: NodeId<UUID> = intent.getParcelableExtraCompat(ENTRY_ID_KEY) ?: return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getEntryById(entryId)?.let { mainEntry ->
RestoreEntryHistoryDatabaseRunnable(this,
database,
mainEntry,
intent.getIntExtra(ENTRY_HISTORY_POSITION_KEY, -1),
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
!database.isReadOnly && saveDatabase
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
}
@@ -1136,12 +1175,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
&& intent.hasExtra(SAVE_DATABASE_KEY)
) {
val entryId: NodeId<UUID> = intent.getParcelableExtraCompat(ENTRY_ID_KEY) ?: return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
database.getEntryById(entryId)?.let { mainEntry ->
DeleteEntryHistoryDatabaseRunnable(this,
database,
mainEntry,
intent.getIntExtra(ENTRY_HISTORY_POSITION_KEY, -1),
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
!database.isReadOnly && saveDatabase
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
}
@@ -1162,11 +1202,12 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
val oldElement: CompressionAlgorithm? = intent.getParcelableExtraCompat(OLD_ELEMENT_KEY)
val newElement: CompressionAlgorithm? = intent.getParcelableExtraCompat(NEW_ELEMENT_KEY)
if (oldElement == null || newElement == null) return null
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
return UpdateCompressionBinariesDatabaseRunnable(this,
database,
oldElement,
newElement,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
!database.isReadOnly && saveDatabase
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
}.apply {
@@ -1184,9 +1225,10 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
database: ContextualDatabase,
): ActionRunnable? {
return if (intent.hasExtra(SAVE_DATABASE_KEY)) {
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
return RemoveUnlinkedDataDatabaseRunnable(this,
database,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
!database.isReadOnly && saveDatabase
) { hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
}.apply {
@@ -1204,9 +1246,10 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
database: ContextualDatabase,
): ActionRunnable? {
return if (intent.hasExtra(SAVE_DATABASE_KEY)) {
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
return SaveDatabaseRunnable(this,
database,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
null,
{ hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)
@@ -1229,13 +1272,14 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
database: ContextualDatabase
): ActionRunnable? {
return if (intent.hasExtra(SAVE_DATABASE_KEY)) {
val saveDatabase = intent.getBooleanExtra(SAVE_DATABASE_KEY, false)
var databaseCopyUri: Uri? = null
if (intent.hasExtra(DATABASE_URI_KEY)) {
databaseCopyUri = intent.getParcelableExtraCompat(DATABASE_URI_KEY)
}
SaveDatabaseRunnable(this,
database,
!database.isReadOnly && intent.getBooleanExtra(SAVE_DATABASE_KEY, false),
!database.isReadOnly && saveDatabase,
null,
{ hardwareKey, seed ->
retrieveResponseFromChallenge(hardwareKey, seed)

View File

@@ -111,13 +111,18 @@ class KeyboardEntryNotificationService : LockNotificationService() {
.setContentIntent(null)
.setDeleteIntent(pendingDeleteIntent)
notificationManager?.cancel(notificationId)
notificationManager?.notify(notificationId, builder.build())
checkNotificationsPermission(this, PreferencesUtil.isKeyboardNotificationEntryEnable(this)) {
notificationManager?.notify(notificationId, builder.build())
}
// Timeout only if notification clear is available
if (PreferencesUtil.isClearKeyboardNotificationEnable(this)) {
if (mNotificationTimeoutMilliSecs != TimeoutHelper.NEVER) {
defineTimerJob(builder, mNotificationTimeoutMilliSecs) {
defineTimerJob(
builder,
NotificationServiceType.KEYBOARD,
mNotificationTimeoutMilliSecs
) {
stopNotificationAndSendLockIfNeeded()
}
}

View File

@@ -1,17 +1,31 @@
package com.kunzisoft.keepass.services
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
import android.os.Build
import android.os.IBinder
import android.util.TypedValue
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.Stylish
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.joda.time.Instant
abstract class NotificationService : Service() {
@@ -20,6 +34,7 @@ abstract class NotificationService : Service() {
private var colorNotificationAccent: Int = 0
protected var mTimerJob: Job? = null
private var mReset: Boolean = false
protected abstract val notificationId: Int
@@ -74,21 +89,55 @@ abstract class NotificationService : Service() {
}
}
protected fun startForegroundCompat(notificationId: Int,
builder: NotificationCompat.Builder,
type: NotificationServiceType
) {
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val foregroundServiceTimer = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
FOREGROUND_SERVICE_TYPE_SPECIAL_USE
} else {
FOREGROUND_SERVICE_TYPE_NONE
}
val foregroundType = when (type) {
NotificationServiceType.DATABASE_TASK -> FOREGROUND_SERVICE_TYPE_DATA_SYNC
NotificationServiceType.ATTACHMENT -> FOREGROUND_SERVICE_TYPE_DATA_SYNC
NotificationServiceType.CLIPBOARD -> foregroundServiceTimer
NotificationServiceType.KEYBOARD -> foregroundServiceTimer
NotificationServiceType.ADVANCED_UNLOCK -> foregroundServiceTimer
}
startForeground(notificationId, builder.build(), foregroundType)
} else {
startForeground(notificationId, builder.build())
}
}
protected fun defineTimerJob(builder: NotificationCompat.Builder,
type: NotificationServiceType,
timeoutMilliseconds: Long,
actionAfterASecond: (() -> Unit)? = null,
actionEnd: () -> Unit) {
mTimerJob?.cancel()
mTimerJob = CoroutineScope(Dispatchers.Main).launch {
if (timeoutMilliseconds > 0) {
val timeoutInSeconds = timeoutMilliseconds / 1000L
for (currentTime in timeoutInSeconds downTo 0) {
var startInstant = Instant.now().millis
var currentTime = timeoutMilliseconds
while (currentTime >= 0) {
// Reset the timer if needed
if (mReset) {
mReset = false
startInstant = Instant.now().millis
currentTime = timeoutMilliseconds
}
// Update every second
actionAfterASecond?.invoke()
builder.setProgress(100,
(currentTime * 100 / timeoutInSeconds).toInt(),
false)
startForeground(notificationId, builder.build())
(currentTime * 100 / timeoutMilliseconds).toInt(),
false)
startForegroundCompat(notificationId, builder, type)
delay(1000)
currentTime = timeoutMilliseconds - (Instant.now().millis - startInstant)
if (currentTime <= 0) {
actionEnd()
}
@@ -103,6 +152,10 @@ abstract class NotificationService : Service() {
}
}
protected fun resetTimeJob() {
mReset = true
}
override fun onDestroy() {
mTimerJob?.cancel()
mTimerJob = null
@@ -114,5 +167,25 @@ abstract class NotificationService : Service() {
companion object {
private const val CHANNEL_ID = "com.kunzisoft.keepass.notification.channel"
private const val CHANNEL_NAME = "KeePassDX notification"
fun checkNotificationsPermission(
context: Context,
showError: Boolean = true,
action: () -> Unit
) {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED) {
action.invoke()
} else {
if (showError) {
Toast.makeText(
context,
R.string.warning_copy_permission,
Toast.LENGTH_LONG
).show()
}
}
}
}
}

View File

@@ -0,0 +1,9 @@
package com.kunzisoft.keepass.services
enum class NotificationServiceType {
DATABASE_TASK,
ATTACHMENT,
CLIPBOARD,
KEYBOARD,
ADVANCED_UNLOCK
}

View File

@@ -19,35 +19,16 @@
*/
package com.kunzisoft.keepass.settings
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.widget.Toolbar
import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
class AutofillSettingsActivity : DatabaseModeActivity() {
class AutofillSettingsActivity : ExternalSettingsActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_toolbar)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setTitle(R.string.autofill_preference_title)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, AutofillSettingsFragment())
.commit()
}
override fun retrieveTitle(): Int {
return R.string.autofill_preference_title
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> onBackPressed()
}
return super.onOptionsItemSelected(item)
override fun retrievePreferenceFragment(): PreferenceFragmentCompat {
return AutofillSettingsFragment()
}
}

View File

@@ -0,0 +1,47 @@
package com.kunzisoft.keepass.settings
import android.os.Bundle
import android.view.MenuItem
import androidx.annotation.StringRes
import androidx.appcompat.widget.Toolbar
import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
abstract class ExternalSettingsActivity : DatabaseModeActivity() {
private var lockView: FloatingActionButton? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_toolbar)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setTitle(retrieveTitle())
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
lockView = findViewById(R.id.lock_button)
lockView?.hide()
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, retrievePreferenceFragment())
.commit()
}
}
@StringRes
abstract fun retrieveTitle(): Int
abstract fun retrievePreferenceFragment(): PreferenceFragmentCompat
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> onDatabaseBackPressed()
}
return super.onOptionsItemSelected(item)
}
}

View File

@@ -19,37 +19,17 @@
*/
package com.kunzisoft.keepass.settings
import android.os.Bundle
import androidx.appcompat.widget.Toolbar
import android.view.MenuItem
import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
class MagikeyboardSettingsActivity : DatabaseModeActivity() {
class MagikeyboardSettingsActivity : ExternalSettingsActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_toolbar)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setTitle(R.string.keyboard_setting_label)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, MagikeyboardSettingsFragment())
.commit()
}
override fun retrieveTitle(): Int {
return R.string.keyboard_setting_label
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> onBackPressed()
}
return super.onOptionsItemSelected(item)
override fun retrievePreferenceFragment(): PreferenceFragmentCompat {
return MagikeyboardSettingsFragment()
}
}

View File

@@ -120,49 +120,55 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
activity?.let { activity ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val autoFillEnablePreference: TwoStatePreference? = findPreference(getString(R.string.settings_autofill_enable_key))
val autofillManager = activity.getSystemService(AutofillManager::class.java)
if (autofillManager != null && autofillManager.hasEnabledAutofillServices())
autoFillEnablePreference?.isChecked = autofillManager.hasEnabledAutofillServices()
autoFillEnablePreference?.onPreferenceClickListener = object : Preference.OnPreferenceClickListener {
@RequiresApi(api = Build.VERSION_CODES.O)
override fun onPreferenceClick(preference: Preference): Boolean {
if ((preference as TwoStatePreference).isChecked) {
try {
enableService()
} catch (e: ActivityNotFoundException) {
val error = getString(R.string.error_autofill_enable_service)
preference.isChecked = false
Log.d(javaClass.name, error, e)
Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
activity.getSystemService(AutofillManager::class.java)?.let { autofillManager ->
if (autofillManager.hasEnabledAutofillServices())
autoFillEnablePreference?.isChecked = autofillManager.hasEnabledAutofillServices()
autoFillEnablePreference?.onPreferenceClickListener =
object : Preference.OnPreferenceClickListener {
@RequiresApi(api = Build.VERSION_CODES.O)
override fun onPreferenceClick(preference: Preference): Boolean {
if ((preference as TwoStatePreference).isChecked) {
try {
enableService()
} catch (e: ActivityNotFoundException) {
val error =
getString(R.string.error_autofill_enable_service)
preference.isChecked = false
Log.d(javaClass.name, error, e)
Toast.makeText(context, error, Toast.LENGTH_SHORT).show()
}
} else {
disableService()
}
return false
}
} else {
disableService()
}
return false
}
@RequiresApi(api = Build.VERSION_CODES.O)
private fun disableService() {
if (autofillManager.hasEnabledAutofillServices()) {
autofillManager.disableAutofillServices()
} else {
Log.d(javaClass.name, "Autofill service already disabled.")
}
}
@RequiresApi(api = Build.VERSION_CODES.O)
private fun disableService() {
if (autofillManager != null && autofillManager.hasEnabledAutofillServices()) {
autofillManager.disableAutofillServices()
} else {
Log.d(javaClass.name, "Autofill service already disabled.")
@RequiresApi(api = Build.VERSION_CODES.O)
@Throws(ActivityNotFoundException::class)
private fun enableService() {
if (!autofillManager.hasEnabledAutofillServices()) {
val intent =
Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE)
intent.data =
Uri.parse("package:com.kunzisoft.keepass.autofill.KeeAutofillService")
Log.d(javaClass.name, "Autofill enable service: intent=$intent")
startActivity(intent)
} else {
Log.d(javaClass.name, "Autofill service already enabled.")
}
}
}
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Throws(ActivityNotFoundException::class)
private fun enableService() {
if (autofillManager != null && !autofillManager.hasEnabledAutofillServices()) {
val intent = Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE)
intent.data = Uri.parse("package:com.kunzisoft.keepass.autofill.KeeAutofillService")
Log.d(javaClass.name, "Autofill enable service: intent=$intent")
startActivity(intent)
} else {
Log.d(javaClass.name, "Autofill service already enabled.")
}
}
}
} else {
findPreference<Preference>(getString(R.string.autofill_key))?.isVisible = false
@@ -477,13 +483,15 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
getString(R.string.setting_style_brightness_key),
getString(R.string.setting_icon_pack_choose_key),
getString(R.string.show_entry_colors_key),
getString(R.string.hide_expired_entries_key),
getString(R.string.hide_templates_key),
getString(R.string.list_entries_show_username_key),
getString(R.string.list_groups_show_number_entries_key),
getString(R.string.recursive_number_entries_key),
getString(R.string.show_otp_token_key),
getString(R.string.show_uuid_key),
getString(R.string.list_size_key),
getString(R.string.monospace_font_fields_enable_key),
getString(R.string.hide_expired_entries_key),
getString(R.string.enable_education_screens_key),
getString(R.string.reset_education_screens_key) -> {
DATABASE_PREFERENCE_CHANGED = true

View File

@@ -120,6 +120,18 @@ object PreferencesUtil {
context.resources.getBoolean(R.bool.show_entry_colors_default))
}
fun showExpiredEntries(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return ! prefs.getBoolean(context.getString(R.string.hide_expired_entries_key),
context.resources.getBoolean(R.bool.hide_expired_entries_default))
}
fun showTemplates(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return ! prefs.getBoolean(context.getString(R.string.hide_templates_key),
context.resources.getBoolean(R.bool.hide_templates_default))
}
fun hideProtectedValue(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.hide_password_key),
@@ -144,6 +156,12 @@ object PreferencesUtil {
context.resources.getBoolean(R.bool.list_groups_show_number_entries_default))
}
fun recursiveNumberEntries(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.recursive_number_entries_key),
context.resources.getBoolean(R.bool.recursive_number_entries_default))
}
fun showOTPToken(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.show_otp_token_key),
@@ -156,12 +174,6 @@ object PreferencesUtil {
context.resources.getBoolean(R.bool.show_uuid_default))
}
fun showExpiredEntries(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return ! prefs.getBoolean(context.getString(R.string.hide_expired_entries_key),
context.resources.getBoolean(R.bool.hide_expired_entries_default))
}
fun getStyle(context: Context): String {
val defaultStyleString = Stylish.defaultStyle(context)
val styleString = PreferenceManager.getDefaultSharedPreferences(context)
@@ -841,15 +853,17 @@ object PreferencesUtil {
context.getString(R.string.setting_style_brightness_key) -> editor.putString(name, value)
context.getString(R.string.setting_icon_pack_choose_key) -> editor.putString(name, value)
context.getString(R.string.show_entry_colors_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.hide_expired_entries_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.hide_templates_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.hide_password_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.colorize_password_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.list_entries_show_username_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.list_groups_show_number_entries_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.recursive_number_entries_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.show_otp_token_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.show_uuid_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.list_size_key) -> editor.putString(name, value)
context.getString(R.string.monospace_font_fields_enable_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.hide_expired_entries_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.enable_education_screens_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.password_generator_length_key) -> editor.putInt(name, value.toInt())

View File

@@ -26,6 +26,7 @@ import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
@@ -54,6 +55,7 @@ open class SettingsActivity
private var coordinatorLayout: CoordinatorLayout? = null
private var toolbar: Toolbar? = null
private var lockView: FloatingActionButton? = null
private var footer: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -62,10 +64,19 @@ open class SettingsActivity
coordinatorLayout = findViewById(R.id.toolbar_coordinator)
toolbar = findViewById(R.id.toolbar)
lockView = findViewById(R.id.lock_button)
footer = findViewById(R.id.screenshot_mode_banner)
// To apply navigation bar with background color
/* TODO Settings nav bar
setTransparentNavigationBar {
coordinatorLayout?.applyWindowInsets(WindowInsetPosition.TOP)
footer?.applyWindowInsets(WindowInsetPosition.BOTTOM)
}*/
mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildOpenDocument { selectedFileUri ->
// Import app properties result
// Import app settings result
try {
selectedFileUri?.let { uri ->
val appProperties = Properties()
@@ -80,11 +91,11 @@ open class SettingsActivity
}
} catch (e: Exception) {
Toast.makeText(this, R.string.error_import_app_properties, Toast.LENGTH_LONG).show()
Log.e(TAG, "Unable to import app properties", e)
Log.e(TAG, "Unable to import app settings", e)
}
}
mExternalFileHelper?.buildCreateDocument { createdFileUri ->
// Export app properties result
// Export app settings result
try {
createdFileUri?.let { uri ->
contentResolver?.openOutputStream(uri)?.use { outputStream ->
@@ -96,7 +107,7 @@ open class SettingsActivity
}
} catch (e: Exception) {
Toast.makeText(this, R.string.error_export_app_properties, Toast.LENGTH_LONG).show()
Log.e(DatabaseLockActivity.TAG, "Unable to export app properties", e)
Log.e(DatabaseLockActivity.TAG, "Unable to export app settings", e)
}
}
@@ -107,7 +118,6 @@ open class SettingsActivity
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
lockView = findViewById(R.id.lock_button)
lockView?.setOnClickListener {
lockAndExit()
}
@@ -166,7 +176,7 @@ open class SettingsActivity
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> onBackPressed()
android.R.id.home -> onDatabaseBackPressed()
}
return super.onOptionsItemSelected(item)
@@ -200,10 +210,10 @@ open class SettingsActivity
}
}
override fun onBackPressed() {
override fun onDatabaseBackPressed() {
// this if statement is necessary to navigate through nested and main fragments
if (supportFragmentManager.backStackEntryCount == 0) {
super.onBackPressed()
super.onDatabaseBackPressed()
} else {
supportFragmentManager.popBackStack()
}

View File

@@ -26,7 +26,7 @@ import com.kunzisoft.keepass.model.SearchInfo
class AutofillBlocklistWebDomainPreferenceDialogFragmentCompat
: AutofillBlocklistPreferenceDialogFragmentCompat() {
override fun buildSearchInfoFromString(searchInfoString: String): SearchInfo? {
override fun buildSearchInfoFromString(searchInfoString: String): SearchInfo {
val newSearchInfo = searchInfoString
// remove prefix https://
.replace(Regex("^.*://"), "")

View File

@@ -29,6 +29,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.util.Log
import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
@@ -45,9 +46,9 @@ const val LOCK_ACTION = "com.kunzisoft.keepass.LOCK"
const val REMOVE_ENTRY_MAGIKEYBOARD_ACTION = "com.kunzisoft.keepass.REMOVE_ENTRY_MAGIKEYBOARD"
const val BACK_PREVIOUS_KEYBOARD_ACTION = "com.kunzisoft.keepass.BACK_PREVIOUS_KEYBOARD"
class LockReceiver(var lockAction: () -> Unit) : BroadcastReceiver() {
class LockReceiver(private var lockAction: () -> Unit) : BroadcastReceiver() {
var mLockPendingIntent: PendingIntent? = null
private var mLockPendingIntent: PendingIntent? = null
var backToPreviousKeyboardAction: (() -> Unit)? = null
override fun onReceive(context: Context, intent: Intent) {
@@ -60,7 +61,7 @@ class LockReceiver(var lockAction: () -> Unit) : BroadcastReceiver() {
}
Intent.ACTION_SCREEN_OFF -> {
if (PreferencesUtil.isLockDatabaseWhenScreenShutOffEnable(context)) {
mLockPendingIntent = PendingIntent.getBroadcast(context,
val lockPendingIntent = PendingIntent.getBroadcast(context,
4575,
Intent(intent).apply {
action = LOCK_ACTION
@@ -71,6 +72,7 @@ class LockReceiver(var lockAction: () -> Unit) : BroadcastReceiver() {
0
}
)
this.mLockPendingIntent = lockPendingIntent
// Launch the effective action after a small time
val first: Long = System.currentTimeMillis() + context.getString(R.string.timeout_screen_off).toLong()
(context.getSystemService(ALARM_SERVICE) as AlarmManager?)?.let { alarmManager ->
@@ -80,20 +82,20 @@ class LockReceiver(var lockAction: () -> Unit) : BroadcastReceiver() {
alarmManager.set(
AlarmManager.RTC_WAKEUP,
first,
mLockPendingIntent
lockPendingIntent
)
} else {
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
first,
mLockPendingIntent
lockPendingIntent
)
}
} else {
alarmManager.set(
AlarmManager.RTC_WAKEUP,
first,
mLockPendingIntent
lockPendingIntent
)
}
}
@@ -120,9 +122,9 @@ class LockReceiver(var lockAction: () -> Unit) : BroadcastReceiver() {
}
private fun cancelLockPendingIntent(context: Context) {
mLockPendingIntent?.let {
mLockPendingIntent?.let { lockPendingIntent ->
val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager?
alarmManager?.cancel(mLockPendingIntent)
alarmManager?.cancel(lockPendingIntent)
mLockPendingIntent = null
}
}
@@ -131,7 +133,7 @@ class LockReceiver(var lockAction: () -> Unit) : BroadcastReceiver() {
fun Context.registerLockReceiver(lockReceiver: LockReceiver?,
registerKeyboardAction: Boolean = false) {
lockReceiver?.let {
registerReceiver(it, IntentFilter().apply {
ContextCompat.registerReceiver(this, it, IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_OFF)
addAction(Intent.ACTION_SCREEN_ON)
addAction(LOCK_ACTION)
@@ -139,7 +141,7 @@ fun Context.registerLockReceiver(lockReceiver: LockReceiver?,
addAction(REMOVE_ENTRY_MAGIKEYBOARD_ACTION)
addAction(BACK_PREVIOUS_KEYBOARD_ACTION)
}
})
}, ContextCompat.RECEIVER_EXPORTED)
}
}

View File

@@ -3,13 +3,17 @@ package com.kunzisoft.keepass.utils
import android.content.res.Resources
import androidx.core.os.ConfigurationCompat
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.model.DataDate
import java.text.DateFormat
import java.util.Calendar
import java.util.Locale
import java.util.TimeZone
object TimeUtil {
fun DateInstant.getDateTimeString(resources: Resources): String {
val locale = ConfigurationCompat.getLocales(resources.configuration)[0] ?: Locale.ROOT
val date = instant.toDate()
return when (type) {
DateInstant.Type.DATE -> DateFormat.getDateInstance(
DateFormat.MEDIUM,
@@ -26,4 +30,22 @@ object TimeUtil {
.format(date)
}
}
// https://github.com/material-components/material-components-android/issues/882#issuecomment-1111374962
// To fix UTC time in date picker
fun datePickerToDataDate(millis: Long): DataDate {
val selectedUtc = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
selectedUtc.timeInMillis = millis
val selectedLocal = Calendar.getInstance()
selectedLocal.clear()
selectedLocal.set(
selectedUtc.get(Calendar.YEAR),
selectedUtc.get(Calendar.MONTH),
selectedUtc.get(Calendar.DAY_OF_MONTH))
return DataDate(
selectedLocal.get(Calendar.YEAR),
selectedLocal.get(Calendar.MONTH) + 1,
selectedLocal.get(Calendar.DAY_OF_MONTH),
)
}
}

View File

@@ -68,6 +68,7 @@ class AddNodeButtonView @JvmOverloads constructor(context: Context,
init {
inflate(context)
hideButton()
}
private fun inflate(context: Context) {

View File

@@ -1,3 +0,0 @@
package com.kunzisoft.keepass.view
data class DataTime(val hours: Int, val minutes: Int)

View File

@@ -111,7 +111,7 @@ class DateTimeEditFieldView @JvmOverloads constructor(context: Context,
mDefault
}
set(value) {
mDateTime = DateInstant(value.date, mDateTime.type)
mDateTime = DateInstant(value.instant, mDateTime.type)
entryExpiresTextView.text = if (entryExpiresCheckBox.isChecked) {
mDateTime.getDateTimeString(resources)
} else {

View File

@@ -57,8 +57,6 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
}
private fun assignExpiresDateText() {
val isExpires = mDateTime.isCurrentlyExpire()
// Show or not the warning icon
expiresImage.isVisible = if (mActivated) {
isExpires
@@ -100,6 +98,13 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
mDateTime.type = value
}
var isExpirable: Boolean = false
val isExpires: Boolean
get() {
return isExpirable && mDateTime.isCurrentlyExpire()
}
override var activation: Boolean
get() {
return mActivated
@@ -128,7 +133,7 @@ class DateTimeFieldView @JvmOverloads constructor(context: Context,
mDefault
}
set(value) {
mDateTime = DateInstant(value.date, mDateTime.type)
mDateTime = DateInstant(value.instant, mDateTime.type)
assignExpiresDateText()
}

View File

@@ -22,28 +22,30 @@ package com.kunzisoft.keepass.view
import android.content.Context
import android.text.Editable
import android.text.InputType
import android.text.Spannable
import android.text.SpannableString
import android.text.TextWatcher
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.TextView
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.password.PasswordEntropy
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
class PassKeyView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
class PasswordEditView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
: FrameLayout(context, attrs, defStyle) {
private var mPasswordEntropyCalculator: PasswordEntropy? = null
private val passwordInputLayout: TextInputLayout
private val passwordText: TextView
private val passwordText: EditText
private val passwordStrengthProgress: LinearProgressIndicator
private val passwordEntropy: TextView
@@ -51,38 +53,19 @@ class PassKeyView @JvmOverloads constructor(context: Context,
private var mMaxLines: Int = 3
private var mShowPassword: Boolean = false
private var mPasswordTextWatcher: MutableList<TextWatcher> = mutableListOf()
private val passwordTextWatcher = object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
mPasswordTextWatcher.forEach {
it.beforeTextChanged(charSequence, i, i1, i2)
}
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
mPasswordTextWatcher.forEach {
it.onTextChanged(charSequence, i, i1, i2)
}
}
override fun afterTextChanged(editable: Editable) {
mPasswordTextWatcher.forEach {
it.afterTextChanged(editable)
}
getEntropyStrength(editable.toString())
}
}
private var mPasswordTextWatchers: MutableList<TextWatcher> = mutableListOf()
private var mPasswordTextWatcher: TextWatcher? = null
init {
context.theme.obtainStyledAttributes(
attrs,
R.styleable.PassKeyView,
R.styleable.PasswordView,
0, 0).apply {
try {
mViewHint = getString(R.styleable.PassKeyView_passKeyHint)
mViewHint = getString(R.styleable.PasswordView_passwordHint)
?: context.getString(R.string.password)
mMaxLines = getInteger(R.styleable.PassKeyView_passKeyMaxLines, mMaxLines)
mShowPassword = getBoolean(R.styleable.PassKeyView_passKeyVisible,
mMaxLines = getInteger(R.styleable.PasswordView_passwordMaxLines, mMaxLines)
mShowPassword = getBoolean(R.styleable.PasswordView_passwordVisible,
!PreferencesUtil.hideProtectedValue(context))
} finally {
recycle()
@@ -90,31 +73,53 @@ class PassKeyView @JvmOverloads constructor(context: Context,
}
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
inflater?.inflate(R.layout.view_passkey, this)
inflater?.inflate(R.layout.view_password_edit, this)
passwordInputLayout = findViewById(R.id.password_input_layout)
passwordInputLayout = findViewById(R.id.password_edit_input_layout)
passwordInputLayout?.hint = mViewHint
passwordText = findViewById(R.id.password_text)
passwordText = findViewById(R.id.password_edit_text)
if (mShowPassword) {
passwordText?.inputType = passwordText.inputType or
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
}
passwordText?.maxLines = mMaxLines
passwordText?.applyFontVisibility()
passwordText.addTextChangedListener(passwordTextWatcher)
passwordStrengthProgress = findViewById(R.id.password_strength_progress)
passwordStrengthProgress = findViewById(R.id.password_edit_strength_progress)
passwordStrengthProgress?.apply {
setIndicatorColor(PasswordEntropy.Strength.RISKY.color)
progress = 0
max = 100
}
passwordEntropy = findViewById(R.id.password_entropy)
passwordEntropy = findViewById(R.id.password_edit_entropy)
mPasswordEntropyCalculator = PasswordEntropy {
passwordText?.text?.toString()?.let { firstPassword ->
getEntropyStrength(firstPassword)
}
}
mPasswordTextWatcher = object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
mPasswordTextWatchers.forEach {
it.beforeTextChanged(charSequence, i, i1, i2)
}
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
mPasswordTextWatchers.forEach {
it.onTextChanged(charSequence, i, i1, i2)
}
}
override fun afterTextChanged(editable: Editable) {
mPasswordTextWatchers.forEach {
it.afterTextChanged(editable)
}
getEntropyStrength(editable.toString())
PasswordGenerator.colorizedPassword(editable)
}
}
passwordText?.addTextChangedListener(mPasswordTextWatcher)
}
private fun getEntropyStrength(passwordText: String) {
@@ -134,11 +139,18 @@ class PassKeyView @JvmOverloads constructor(context: Context,
}
fun addTextChangedListener(textWatcher: TextWatcher) {
mPasswordTextWatcher.add(textWatcher)
mPasswordTextWatchers.add(textWatcher)
}
fun removeTextChangedListener(textWatcher: TextWatcher) {
mPasswordTextWatcher.remove(textWatcher)
mPasswordTextWatchers.remove(textWatcher)
}
private fun spannableValue(value: String): Spannable {
return if (PreferencesUtil.colorizePassword(context))
PasswordGenerator.getColorizedPassword(value)
else
SpannableString(value)
}
var passwordString: String
@@ -146,11 +158,6 @@ class PassKeyView @JvmOverloads constructor(context: Context,
return passwordText.text.toString()
}
set(value) {
val spannableString =
if (PreferencesUtil.colorizePassword(context))
PasswordGenerator.getColorizedPassword(value)
else
SpannableString(value)
passwordText.text = spannableString
passwordText.setText(spannableValue(value))
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright 2024 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.view
import android.content.Context
import android.os.Build
import android.text.Spannable
import android.util.AttributeSet
import android.util.TypedValue
import android.widget.TextView
import androidx.core.view.ViewCompat
import androidx.core.view.setPadding
import androidx.core.widget.TextViewCompat
import androidx.core.widget.doAfterTextChanged
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.password.PasswordEntropy
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
class PasswordTextEditFieldView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
: TextEditFieldView(context, attrs, defStyle) {
private var mPasswordEntropyCalculator: PasswordEntropy = PasswordEntropy {
valueView.text?.toString()?.let { firstPassword ->
getEntropyStrength(firstPassword)
}
}
private var isColorizedPasswordActivated = PreferencesUtil.colorizePassword(context)
private var passwordProgressViewId = ViewCompat.generateViewId()
private var passwordEntropyViewId = ViewCompat.generateViewId()
private var mPasswordProgress = LinearProgressIndicator(context).apply {
layoutParams = LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
).apply {
addRule(ALIGN_PARENT_BOTTOM)
}
setPadding(
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
1f,
context.resources.displayMetrics
).toInt()
)
setIndicatorColor(PasswordEntropy.Strength.RISKY.color)
progress = 0
max = 100
}
private val mPasswordEntropyView = TextView(context).apply {
layoutParams = LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
).apply {
addRule(ALIGN_PARENT_BOTTOM)
}
setPadding(
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
4f,
context.resources.displayMetrics
).toInt()
)
TextViewCompat.setTextAppearance(this, R.style.KeepassDXStyle_Text_Indicator)
}
init {
buildViews()
valueView.doAfterTextChanged { editable ->
getEntropyStrength(editable.toString())
PasswordGenerator.colorizedPassword(editable)
}
addView(mPasswordProgress)
addView(mPasswordEntropyView)
}
private fun buildViews() {
mPasswordProgress.apply {
id = passwordProgressViewId
layoutParams = (layoutParams as LayoutParams?)?.also {
it.addRule(LEFT_OF, actionImageButtonId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it.addRule(START_OF, actionImageButtonId)
}
}
}
mPasswordEntropyView.apply {
id = passwordEntropyViewId
layoutParams = (layoutParams as LayoutParams?)?.also {
it.addRule(ALIGN_RIGHT, passwordProgressViewId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it.addRule(ALIGN_END, passwordProgressViewId)
}
}
}
}
private fun getEntropyStrength(passwordText: String) {
mPasswordEntropyCalculator.getEntropyStrength(passwordText) { entropyStrength ->
mPasswordProgress.apply {
post {
setIndicatorColor(entropyStrength.strength.color)
setProgressCompat(entropyStrength.estimationPercent, true)
}
}
mPasswordEntropyView.apply {
post {
text = PasswordEntropy.getStringEntropy(resources, entropyStrength.entropy)
}
}
}
}
override fun spannableValue(value: String?): Spannable? {
if (value == null)
return null
return if (isColorizedPasswordActivated)
PasswordGenerator.getColorizedPassword(value)
else
super.spannableValue(value)
}
override var label: String
get() {
return super.label
}
set(value) {
super.label = value
// Define views Ids with label value
passwordProgressViewId = "passwordProgressViewId $value".hashCode()
passwordEntropyViewId = "passwordEntropyViewId $value".hashCode()
buildViews()
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2024 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.view
import android.content.Context
import android.graphics.Color
import android.text.SpannableString
import android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
import android.text.style.ImageSpan
import android.util.AttributeSet
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.password.PasswordEntropy
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
class PasswordTextFieldView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
: TextFieldView(context, attrs, defStyle) {
private var mPasswordEntropyCalculator: PasswordEntropy = PasswordEntropy {
valueView.text?.toString()?.let { firstPassword ->
getEntropyStrength(firstPassword)
}
}
private var indicatorDrawable = ContextCompat.getDrawable(
context,
R.drawable.ic_shield_white_24dp
)?.apply {
val lineHeight = labelView.lineHeight
setBounds(0,0,lineHeight, lineHeight)
DrawableCompat.setTint(this, Color.TRANSPARENT)
}
override var label: String
get() {
return labelView.text.toString().removeSuffix(ICON_STRING_SPACES)
}
set(value) {
indicatorDrawable?.let { drawable ->
val spannableString = SpannableString("$value$ICON_STRING_SPACES")
val startPosition = spannableString.split(ICON_STRING)[0].length
val endPosition = startPosition + ICON_STRING.length
spannableString
.setSpan(
ImageSpan(drawable),
startPosition,
endPosition,
SPAN_EXCLUSIVE_EXCLUSIVE
)
labelView.text = spannableString
} ?: kotlin.run {
labelView.text = value
}
}
override fun setLabel(@StringRes labelId: Int) {
label = resources.getString(labelId)
}
override var value: String
get() {
return valueView.text.toString()
}
set(value) {
val spannableString =
if (PreferencesUtil.colorizePassword(context))
PasswordGenerator.getColorizedPassword(value)
else
SpannableString(value)
valueView.text = spannableString
changeProtectedValueParameters()
}
override fun setValue(@StringRes valueId: Int) {
value = resources.getString(valueId)
}
private fun getEntropyStrength(passwordText: String) {
mPasswordEntropyCalculator.getEntropyStrength(passwordText) { entropyStrength ->
labelView.apply {
post {
val strengthColor = entropyStrength.strength.color
indicatorDrawable?.let { drawable ->
DrawableCompat.setTint(drawable, strengthColor)
}
invalidate()
}
}
}
}
companion object {
private const val ICON_STRING = "[icon]"
private const val ICON_STRING_SPACES = " $ICON_STRING"
}
}

View File

@@ -17,8 +17,10 @@ import com.kunzisoft.keepass.database.element.template.TemplateAttribute
import com.kunzisoft.keepass.database.element.template.TemplateAttributeAction
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.database.helper.isStandardPasswordName
import com.kunzisoft.keepass.model.DataDate
import com.kunzisoft.keepass.model.DataTime
import com.kunzisoft.keepass.otp.OtpEntryFields
import org.joda.time.DateTime
class TemplateEditView @JvmOverloads constructor(context: Context,
@@ -112,7 +114,9 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
override fun buildLinearTextView(templateAttribute: TemplateAttribute,
field: Field): TextEditFieldView? {
return context?.let {
TextEditFieldView(it).apply {
(if (TemplateField.isStandardPasswordName(context, templateAttribute.label))
PasswordTextEditFieldView(it)
else TextEditFieldView(it)).apply {
// hiddenProtectedValue (mHideProtectedValue) don't work with TextInputLayout
setProtection(field.protectedValue.isProtected)
default = templateAttribute.default
@@ -211,35 +215,31 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
val dateTimeView = getFieldViewById(viewId)
if (dateTimeView is DateTimeEditFieldView) {
dateTimeView.dateTime = DateInstant(
action.invoke(dateTimeView.dateTime).date,
dateTimeView.dateTime.type)
action.invoke(dateTimeView.dateTime).instant,
dateTimeView.dateTime.type
)
}
}
}
fun setCurrentDateTimeValue(dateMilliseconds: Long) {
fun setCurrentDateTimeValue(date: DataDate) {
// Save the date
setCurrentDateTimeSelection { instant ->
val newDateInstant = DateInstant(
DateTime(instant.date)
.withMillis(dateMilliseconds)
.toDate(), instant.type)
if (instant.type == DateInstant.Type.DATE_TIME) {
val instantTime = DateInstant(instant.date, DateInstant.Type.TIME)
setCurrentDateTimeSelection { dateInstant ->
dateInstant.setDate(date.year, date.month, date.day)
if (dateInstant.type == DateInstant.Type.DATE_TIME) {
// Trick to recall selection with time
mOnDateInstantClickListener?.invoke(instantTime)
mOnDateInstantClickListener?.invoke(
DateInstant(dateInstant.instant, DateInstant.Type.TIME)
)
}
newDateInstant
dateInstant
}
}
fun setCurrentTimeValue(time: DataTime) {
setCurrentDateTimeSelection { instant ->
DateInstant(
DateTime(instant.date)
.withHourOfDay(time.hours)
.withMinuteOfHour(time.minutes)
.toDate(), instant.type)
setCurrentDateTimeSelection { dateInstant ->
dateInstant.setTime(time.hour, time.minute)
dateInstant
}
}

View File

@@ -10,6 +10,7 @@ import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.database.element.template.TemplateAttribute
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.database.helper.isStandardPasswordName
import com.kunzisoft.keepass.model.OtpModel
import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
@@ -48,7 +49,9 @@ class TemplateView @JvmOverloads constructor(context: Context,
field: Field): TextFieldView? {
// Add an action icon if needed
return context?.let {
TextFieldView(it).apply {
(if (TemplateField.isStandardPasswordName(context, templateAttribute.label))
PasswordTextFieldView(it)
else TextFieldView(it)).apply {
applyFontVisibility(mFontInVisibility)
setProtection(field.protectedValue.isProtected, mHideProtectedValue)
label = templateAttribute.alias
@@ -100,13 +103,12 @@ class TemplateView @JvmOverloads constructor(context: Context,
return context?.let {
DateTimeFieldView(it).apply {
label = TemplateField.getLocalizedName(context, field.name)
val dateInstantType = templateAttribute.options.getDateFormat()
type = templateAttribute.options.getDateFormat()
isExpirable = templateAttribute.options.getExpirable()
try {
val value = field.protectedValue.toString().trim()
type = dateInstantType
activation = value.isNotEmpty()
} catch (e: Exception) {
type = dateInstantType
activation = false
}
}

View File

@@ -4,15 +4,16 @@ import android.content.Context
import android.os.Build
import android.text.InputFilter
import android.text.InputType
import android.text.Spannable
import android.text.SpannableString
import android.util.AttributeSet
import android.util.TypedValue
import android.view.ContextThemeWrapper
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.annotation.DrawableRes
import androidx.appcompat.view.ContextThemeWrapper
import androidx.appcompat.widget.AppCompatImageButton
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
@@ -20,28 +21,27 @@ import androidx.core.view.isVisible
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.isStandardPasswordName
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
class TextEditFieldView @JvmOverloads constructor(context: Context,
open class TextEditFieldView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
: RelativeLayout(context, attrs, defStyle), GenericTextFieldView {
private var labelViewId = ViewCompat.generateViewId()
private var valueViewId = ViewCompat.generateViewId()
private var actionImageButtonId = ViewCompat.generateViewId()
protected var actionImageButtonId = ViewCompat.generateViewId()
private val labelView = TextInputLayout(context).apply {
layoutParams = LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT)
}
private val valueView = TextInputEditText(
ContextThemeWrapper(getContext(),
R.style.KeepassDXStyle_TextInputLayout)
protected val valueView = TextInputEditText(
ContextThemeWrapper(
getContext(),
R.style.KeepassDXStyle_TextInputLayout
)
).apply {
layoutParams = LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
@@ -57,7 +57,10 @@ class TextEditFieldView @JvmOverloads constructor(context: Context,
maxLines = 1
}
private var actionImageButton = AppCompatImageButton(
ContextThemeWrapper(context, R.style.KeepassDXStyle_ImageButton_Simple), null, 0).apply {
ContextThemeWrapper(
context,
R.style.KeepassDXStyle_ImageButton_Simple
), null, 0).apply {
layoutParams = LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT).also {
@@ -86,10 +89,10 @@ class TextEditFieldView @JvmOverloads constructor(context: Context,
private fun buildViews() {
labelView.apply {
id = labelViewId
layoutParams = (layoutParams as LayoutParams?).also {
it?.addRule(LEFT_OF, actionImageButtonId)
layoutParams = (layoutParams as LayoutParams?)?.also {
it.addRule(LEFT_OF, actionImageButtonId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it?.addRule(START_OF, actionImageButtonId)
it.addRule(START_OF, actionImageButtonId)
}
}
}
@@ -123,18 +126,16 @@ class TextEditFieldView @JvmOverloads constructor(context: Context,
buildViews()
}
protected open fun spannableValue(value: String?): Spannable? {
return SpannableString(value)
}
override var value: String
get() {
return valueView.text?.toString() ?: ""
}
set(value) {
val spannableString =
if (PreferencesUtil.colorizePassword(context)
&& TemplateField.isStandardPasswordName(context, label))
PasswordGenerator.getColorizedPassword(value)
else
SpannableString(value)
valueView.setText(spannableString)
valueView.setText(spannableValue(value))
}
override var default: String = ""
@@ -145,6 +146,7 @@ class TextEditFieldView @JvmOverloads constructor(context: Context,
valueView.filters += InputFilter.LengthFilter(MAX_CHARS_LIMIT)
}
else -> {
@Suppress("KotlinConstantConditions")
val chars = if (numberChars > MAX_CHARS_LIMIT) MAX_CHARS_LIMIT else numberChars
valueView.filters += InputFilter.LengthFilter(chars)
}
@@ -164,6 +166,7 @@ class TextEditFieldView @JvmOverloads constructor(context: Context,
valueView.maxLines = MAX_LINES_LIMIT
}
else -> {
@Suppress("KotlinConstantConditions")
val lines = if (numberLines > MAX_LINES_LIMIT) MAX_LINES_LIMIT else numberLines
valueView.inputType = valueView.inputType or
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE

View File

@@ -22,7 +22,6 @@ package com.kunzisoft.keepass.view
import android.content.Context
import android.os.Build
import android.text.InputFilter
import android.text.SpannableString
import android.text.util.Linkify
import android.util.AttributeSet
import android.util.TypedValue
@@ -38,15 +37,11 @@ import androidx.core.text.util.LinkifyCompat
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.isStandardPasswordName
import com.kunzisoft.keepass.model.EntryInfo.Companion.APPLICATION_ID_FIELD_NAME
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
class TextFieldView @JvmOverloads constructor(context: Context,
open class TextFieldView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
: RelativeLayout(context, attrs, defStyle), GenericTextFieldView {
@@ -56,7 +51,7 @@ class TextFieldView @JvmOverloads constructor(context: Context,
private var showButtonId = ViewCompat.generateViewId()
private var copyButtonId = ViewCompat.generateViewId()
private val labelView = AppCompatTextView(context).apply {
protected val labelView = AppCompatTextView(context).apply {
setTextAppearance(context,
R.style.KeepassDXStyle_TextAppearance_LabelTextStyle)
layoutParams = LayoutParams(
@@ -77,7 +72,7 @@ class TextFieldView @JvmOverloads constructor(context: Context,
}
}
}
private val valueView = AppCompatTextView(context).apply {
protected val valueView = AppCompatTextView(context).apply {
setTextAppearance(context,
R.style.KeepassDXStyle_TextAppearance_TextNode)
layoutParams = LayoutParams(
@@ -131,46 +126,46 @@ class TextFieldView @JvmOverloads constructor(context: Context,
private fun buildViews() {
copyButton.apply {
id = copyButtonId
layoutParams = (layoutParams as LayoutParams?).also {
it?.addRule(ALIGN_PARENT_RIGHT)
layoutParams = (layoutParams as LayoutParams?)?.also {
it.addRule(ALIGN_PARENT_RIGHT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it?.addRule(ALIGN_PARENT_END)
it.addRule(ALIGN_PARENT_END)
}
}
}
showButton.apply {
id = showButtonId
layoutParams = (layoutParams as LayoutParams?).also {
layoutParams = (layoutParams as LayoutParams?)?.also {
if (copyButton.isVisible) {
it?.addRule(LEFT_OF, copyButtonId)
it.addRule(LEFT_OF, copyButtonId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it?.addRule(START_OF, copyButtonId)
it.addRule(START_OF, copyButtonId)
}
} else {
it?.addRule(ALIGN_PARENT_RIGHT)
it.addRule(ALIGN_PARENT_RIGHT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it?.addRule(ALIGN_PARENT_END)
it.addRule(ALIGN_PARENT_END)
}
}
}
}
labelView.apply {
id = labelViewId
layoutParams = (layoutParams as LayoutParams?).also {
it?.addRule(LEFT_OF, showButtonId)
layoutParams = (layoutParams as LayoutParams?)?.also {
it.addRule(LEFT_OF, showButtonId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it?.addRule(START_OF, showButtonId)
it.addRule(START_OF, showButtonId)
}
}
}
valueView.apply {
id = valueViewId
layoutParams = (layoutParams as LayoutParams?).also {
it?.addRule(LEFT_OF, showButtonId)
layoutParams = (layoutParams as LayoutParams?)?.also {
it.addRule(LEFT_OF, showButtonId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
it?.addRule(START_OF, showButtonId)
it.addRule(START_OF, showButtonId)
}
it?.addRule(BELOW, labelViewId)
it.addRule(BELOW, labelViewId)
}
}
}
@@ -188,7 +183,7 @@ class TextFieldView @JvmOverloads constructor(context: Context,
labelView.text = value
}
fun setLabel(@StringRes labelId: Int) {
open fun setLabel(@StringRes labelId: Int) {
labelView.setText(labelId)
}
@@ -197,17 +192,11 @@ class TextFieldView @JvmOverloads constructor(context: Context,
return valueView.text.toString()
}
set(value) {
val spannableString =
if (PreferencesUtil.colorizePassword(context)
&& TemplateField.isStandardPasswordName(context, label))
PasswordGenerator.getColorizedPassword(value)
else
SpannableString(value)
valueView.text = spannableString
valueView.text = value
changeProtectedValueParameters()
}
fun setValue(@StringRes valueId: Int) {
open fun setValue(@StringRes valueId: Int) {
value = resources.getString(valueId)
changeProtectedValueParameters()
}
@@ -237,7 +226,7 @@ class TextFieldView @JvmOverloads constructor(context: Context,
invalidate()
}
private fun changeProtectedValueParameters() {
protected fun changeProtectedValueParameters() {
valueView.apply {
if (showButton.isVisible) {
applyHiddenStyle(showButton.isSelected)

View File

@@ -22,9 +22,16 @@ package com.kunzisoft.keepass.view
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.app.Activity
import android.content.Context
import android.graphics.*
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.Selection
import android.text.Spannable
import android.text.SpannableString
@@ -43,8 +50,14 @@ import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.appcompat.widget.ActionMenuView
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.forEach
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import com.google.android.material.appbar.CollapsingToolbarLayout
import com.google.android.material.snackbar.Snackbar
@@ -287,3 +300,88 @@ fun CollapsingToolbarLayout.changeTitleColor(color: Int) {
setExpandedTitleColor(color)
invalidate()
}
fun Activity.setTransparentNavigationBar(applyToStatusBar: Boolean = false, applyWindowInsets: () -> Unit) {
// Only in portrait
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1
&& resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
WindowCompat.setDecorFitsSystemWindows(window, false)
window.navigationBarColor = ContextCompat.getColor(this, R.color.surface_selector)
if (applyToStatusBar) {
obtainStyledAttributes(intArrayOf(R.attr.colorSurface)).apply {
window.statusBarColor = getColor(0, Color.GRAY)
recycle()
}
}
applyWindowInsets.invoke()
}
}
/**
* Apply a margin to a view to fix the window inset
*/
fun View.applyWindowInsets(position: WindowInsetPosition = WindowInsetPosition.BOTTOM) {
ViewCompat.setOnApplyWindowInsetsListener(this) { view, windowInsets ->
var consumed = false
// To fix listener in API 27
if (view is ViewGroup) {
view.forEach { child ->
// Dispatch the insets to the child
val childResult = ViewCompat.dispatchApplyWindowInsets(child, windowInsets)
// If the child consumed the insets, record it
if (childResult.isConsumed) {
consumed = true
}
}
}
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
when (position) {
WindowInsetPosition.TOP -> {
if (view.layoutParams is ViewGroup.MarginLayoutParams) {
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
}
}
}
WindowInsetPosition.LEGIT_TOP -> {
if (view.layoutParams is ViewGroup.MarginLayoutParams) {
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = 0
}
}
}
WindowInsetPosition.BOTTOM -> {
if (view.layoutParams is ViewGroup.MarginLayoutParams) {
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = insets.bottom
}
}
}
WindowInsetPosition.BOTTOM_IME -> {
val imeHeight = windowInsets.getInsets(WindowInsetsCompat.Type.ime()).bottom
if (view.layoutParams is ViewGroup.MarginLayoutParams) {
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = if (imeHeight > 1) 0 else insets.bottom
}
}
}
WindowInsetPosition.TOP_BOTTOM_IME -> {
val imeHeight = windowInsets.getInsets(WindowInsetsCompat.Type.ime()).bottom
if (view.layoutParams is ViewGroup.MarginLayoutParams) {
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
bottomMargin = if (imeHeight > 1) imeHeight else 0
}
}
}
}
// If any of the children consumed the insets, return an appropriate value
if (consumed) WindowInsetsCompat.CONSUMED else windowInsets
}
}
enum class WindowInsetPosition {
TOP, BOTTOM, LEGIT_TOP, BOTTOM_IME, TOP_BOTTOM_IME
}

View File

@@ -3,6 +3,7 @@ package com.kunzisoft.keepass.viewmodels
import android.app.Application
import android.net.Uri
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.kunzisoft.keepass.app.App
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
@@ -19,9 +20,8 @@ class DatabaseFileViewModel(application: Application) : AndroidViewModel(applica
mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(application.applicationContext)
}
val isDefaultDatabase: MutableLiveData<Boolean> by lazy {
MutableLiveData<Boolean>()
}
private val mIsDefaultDatabase = MutableLiveData<Boolean>()
val isDefaultDatabase: LiveData<Boolean> = mIsDefaultDatabase
fun checkIfIsDefaultDatabase(databaseUri: Uri) {
IOActionTask(
@@ -30,7 +30,7 @@ class DatabaseFileViewModel(application: Application) : AndroidViewModel(applica
?.parseUri() == databaseUri)
},
{
isDefaultDatabase.value = it
mIsDefaultDatabase.value = it
}
).execute()
}
@@ -46,13 +46,12 @@ class DatabaseFileViewModel(application: Application) : AndroidViewModel(applica
).execute()
}
val databaseFileLoaded: MutableLiveData<DatabaseFile> by lazy {
MutableLiveData<DatabaseFile>()
}
private val mDatabaseFileLoaded = MutableLiveData<DatabaseFile>()
val databaseFileLoaded: LiveData<DatabaseFile> = mDatabaseFileLoaded
fun loadDatabaseFile(databaseUri: Uri) {
mFileDatabaseHistoryAction?.getDatabaseFile(databaseUri) { databaseFileRetrieved ->
databaseFileLoaded.value = databaseFileRetrieved
mDatabaseFileLoaded.value = databaseFileRetrieved
}
}
}

View File

@@ -2,6 +2,7 @@ package com.kunzisoft.keepass.viewmodels
import android.app.Application
import android.net.Uri
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.kunzisoft.keepass.app.App
@@ -10,8 +11,8 @@ import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.model.DatabaseFile
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.IOActionTask
import com.kunzisoft.keepass.utils.parseUri
import com.kunzisoft.keepass.utils.UriUtil.releaseUriPermission
import com.kunzisoft.keepass.utils.parseUri
class DatabaseFilesViewModel(application: Application) : AndroidViewModel(application) {
@@ -25,11 +26,29 @@ class DatabaseFilesViewModel(application: Application) : AndroidViewModel(applic
MutableLiveData<DatabaseFileData>()
}
private var mDefaultDatabaseAlreadyChecked : Boolean = false
val defaultDatabase: MutableLiveData<Uri?> by lazy {
MutableLiveData<Uri?>()
}
fun checkDefaultDatabase() {
fun doForDefaultDatabase(action: (defaultDatabaseUri: Uri) -> Unit) {
if (!mDefaultDatabaseAlreadyChecked) {
mDefaultDatabaseAlreadyChecked = true
val context = getApplication<App>().applicationContext
PreferencesUtil.getDefaultDatabasePath(context)?.parseUri()?.let { databaseFileUri ->
if (FileDatabaseInfo(context, databaseFileUri).exists) {
action.invoke(databaseFileUri)
} else {
Log.e(TAG, "Unable to automatically load a non-accessible file")
}
} ?: run {
Log.i(TAG, "No default database to prepare")
}
}
}
private fun checkDefaultDatabase() {
IOActionTask(
{
PreferencesUtil.getDefaultDatabasePath(getApplication<App>().applicationContext)
@@ -149,4 +168,8 @@ class DatabaseFilesViewModel(application: Application) : AndroidViewModel(applic
enum class DatabaseFileAction {
NONE, ADD, UPDATE, DELETE
}
companion object {
private val TAG = DatabaseFilesViewModel::class.java.name
}
}

View File

@@ -43,8 +43,8 @@ class KeyGeneratorViewModel: ViewModel() {
val requirePassphraseGeneration : LiveData<Void?> get() = _requirePassphraseGeneration
private val _requirePassphraseGeneration = SingleLiveEvent<Void?>()
fun setKeyGenerated(passKey: String) {
_keyGenerated.value = passKey
fun setKeyGenerated(value: String) {
_keyGenerated.value = value
}
fun validateKeyGenerated() {

View File

@@ -4,7 +4,8 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.view.DataTime
import com.kunzisoft.keepass.model.DataDate
import com.kunzisoft.keepass.model.DataTime
abstract class NodeEditViewModel : ViewModel() {
@@ -23,8 +24,8 @@ abstract class NodeEditViewModel : ViewModel() {
val requestDateTimeSelection : LiveData<DateInstant> get() = _requestDateTimeSelection
private val _requestDateTimeSelection = SingleLiveEvent<DateInstant>()
val onDateSelected : LiveData<Long> get() = _onDateSelected
private val _onDateSelected = SingleLiveEvent<Long>()
val onDateSelected : LiveData<DataDate> get() = _onDateSelected
private val _onDateSelected = SingleLiveEvent<DataDate>()
val onTimeSelected : LiveData<DataTime> get() = _onTimeSelected
private val _onTimeSelected = SingleLiveEvent<DataTime>()
@@ -57,12 +58,12 @@ abstract class NodeEditViewModel : ViewModel() {
_requestDateTimeSelection.value = dateInstant
}
fun selectDate(dateMilliseconds: Long) {
_onDateSelected.value = dateMilliseconds
fun selectDate(date: DataDate) {
_onDateSelected.value = date
}
fun selectTime(hours: Int, minutes: Int) {
_onTimeSelected.value = DataTime(hours, minutes)
fun selectTime(dataTime: DataTime) {
_onTimeSelected.value = dataTime
}
private enum class ColorRequest {

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:alpha="0.60" android:color="?attr/colorSurface"/>
</selector>

View File

@@ -8,7 +8,7 @@
<item android:state_selected="true">
<shape>
<corners android:radius="25dp" />
<solid android:color="?attr/colorSecondaryContainer"/>
<solid android:color="?attr/colorSecondary"/>
</shape>
</item>
<item android:state_selected="false">

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M11 16C11 16.6 10.6 17 10 17S9 16.6 9 16C9 15.4 9.4 15 10 15S11 15.4 11 16M20 8V20C20 21.1 19.1 22 18 22H6C4.9 22 4 21.1 4 20V4C4 2.9 4.9 2 6 2H14M18 15H12.8C12.2 13.4 10.5 12.6 9 13.2C7.4 13.8 6.6 15.5 7.2 17S9.5 19.4 11 18.8C11.9 18.5 12.5 17.8 12.8 17H14V19H16V17H18M18.5 9L13 3.5V9H18.5Z" />
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M18,22l-0.01,-6L14,12l3.99,-4.01L18,2H6v6l4,4l-4,3.99V22H18zM8,7.5V4h8v3.5l-4,4L8,7.5z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,1L3,5v6c0,5.55 3.84,10.74 9,12 5.16,-1.26 9,-6.45 9,-12V5l-9,-4z"/>
</vector>

View File

@@ -1,7 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">
<path android:fillColor="#ffffff" android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
</vector>

View File

@@ -22,15 +22,12 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:filterTouchesWhenObscured="true"
android:fitsSystemWindows="true">
android:filterTouchesWhenObscured="true">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/toolbar_coordinator"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner"
app:layout_constraintTop_toTopOf="parent">
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
@@ -96,7 +93,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:paddingBottom="48dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/history_container"
@@ -138,14 +136,26 @@
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/activity_entry_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/entry_content_tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="180dp"
android:background="@drawable/background_item_selection"
android:backgroundTint="?attr/colorSurfaceContainerLow"
android:backgroundTint="@color/surface_selector"
android:layout_marginBottom="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_gravity="bottom|center_horizontal"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner"
app:tabMode="fixed"
tools:targetApi="lollipop">
@@ -163,24 +173,25 @@
</com.google.android.material.tabs.TabLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
</FrameLayout>
<include
layout="@layout/view_button_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|bottom" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<include layout="@layout/view_screenshot_mode_banner" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include layout="@layout/view_screenshot_mode_banner" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -22,34 +22,31 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:importantForAutofill="noExcludeDescendants"
android:id="@+id/activity_entry_edit_container"
tools:targetApi="o"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:filterTouchesWhenObscured="true">
<com.kunzisoft.keepass.view.ToolbarSpecial
android:id="@+id/special_mode_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/entry_edit_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/entry_edit_bottom_bar">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.kunzisoft.keepass.view.ToolbarSpecial
android:id="@+id/special_mode_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
</com.google.android.material.appbar.AppBarLayout>
app:layout_constraintTop_toBottomOf="@+id/special_mode_view"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.core.widget.NestedScrollView
android:id="@+id/entry_edit_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:scrollbarStyle="insideOverlay"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
@@ -57,7 +54,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="@dimen/card_view_margin_vertical"
android:paddingBottom="@dimen/card_view_margin_vertical">
android:paddingBottom="128dp">
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/entry_edit_template_selector"
android:layout_width="match_parent"
@@ -77,32 +74,55 @@
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.kunzisoft.keepass.view.ToolbarAction
android:id="@+id/entry_edit_bottom_bar"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/activity_entry_edit_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner" />
app:layout_constraintBottom_toBottomOf="parent">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/entry_edit_validate"
style="@style/KeepassDXStyle.Fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/validate"
android:src="@drawable/ic_check_white_24dp"
app:fabCustomSize="@dimen/button_small_size"
app:layout_constraintTop_toTopOf="@+id/entry_edit_bottom_bar"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bottom_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner">
<include
layout="@layout/view_button_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner"/>
<com.kunzisoft.keepass.view.ToolbarAction
android:id="@+id/entry_edit_bottom_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_constraintBottom_toBottomOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/entry_edit_validate"
style="@style/KeepassDXStyle.Fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/validate"
android:src="@drawable/ic_check_white_24dp"
app:fabCustomSize="@dimen/button_small_size"
app:layout_constraintTop_toTopOf="@+id/entry_edit_bottom_bar"
app:layout_constraintBottom_toBottomOf="@+id/entry_edit_bottom_bar"
android:layout_marginBottom="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<include
layout="@layout/view_button_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<include
app:layout_constraintTop_toBottomOf="@+id/bottom_toolbar"
app:layout_constraintBottom_toBottomOf="parent"
layout="@layout/view_screenshot_mode_banner" />
</androidx.constraintlayout.widget.ConstraintLayout>
<ProgressBar
android:id="@+id/loading"
@@ -110,12 +130,9 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
app:layout_anchor="@+id/entry_scroll"
app:layout_anchorGravity="top|center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include layout="@layout/view_screenshot_mode_banner" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -73,7 +73,7 @@
android:shadowDy="2"
android:shadowRadius="2"
android:paddingTop="?attr/actionBarSize"
android:textColor="@color/green_light"
android:textColor="?attr/colorPrimaryContainer"
android:gravity="center"
android:text="@string/app_name_part1"/>
<TextView
@@ -89,7 +89,7 @@
android:shadowDy="2"
android:shadowRadius="2"
android:paddingTop="?attr/actionBarSize"
android:textColor="@color/orange"
android:textColor="?attr/colorSecondary"
android:gravity="center"
android:text="@string/app_name_part2"/>
<TextView
@@ -107,7 +107,7 @@
android:shadowDy="2"
android:shadowRadius="2"
android:paddingTop="?attr/actionBarSize"
android:textColor="@color/green_lightest"
android:textColor="?attr/colorSecondaryContainer"
android:gravity="center"
android:text="@string/app_name_part3"/>
</LinearLayout>

View File

@@ -31,67 +31,73 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.kunzisoft.keepass.view.ToolbarSpecial
android:id="@+id/special_mode_view"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/activity_group_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:title="@string/app_name"
app:layout_constraintTop_toBottomOf="@+id/special_mode_view">
<TextView
android:id="@+id/database_name"
android:layout_width="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<com.kunzisoft.keepass.view.ToolbarSpecial
android:id="@+id/special_mode_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginLeft="12dp"
android:singleLine="true"
tools:text="Database"
style="@style/KeepassDXStyle.Title.OnSurface" />
</com.google.android.material.appbar.MaterialToolbar>
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:layout_width="48dp"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginLeft="48dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/special_mode_view"
app:layout_constraintBottom_toTopOf="@+id/group_coordinator">
<ImageView
android:id="@+id/database_color"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical|start"
android:visibility="gone"
android:src="@drawable/background_rounded_square"
android:contentDescription="@string/content_description_database_color"/>
<ImageView
android:id="@+id/database_modified"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical|start"
android:visibility="gone"
android:src="@drawable/ic_modified_white_12dp"
android:contentDescription="@string/save"/>
</FrameLayout>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:title="@string/app_name"
app:layout_constraintTop_toBottomOf="@+id/special_mode_view">
<TextView
android:id="@+id/database_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginLeft="12dp"
android:maxLines="2"
android:ellipsize="end"
tools:text="Database"
style="@style/KeepassDXStyle.Title.OnSurface" />
</com.google.android.material.appbar.MaterialToolbar>
<FrameLayout
android:layout_width="48dp"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginLeft="48dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/special_mode_view"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/database_color"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical|start"
android:visibility="gone"
android:src="@drawable/background_rounded_square"
android:contentDescription="@string/content_description_database_color"/>
<ImageView
android:id="@+id/database_modified"
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical|start"
android:visibility="gone"
android:src="@drawable/ic_modified_white_12dp"
android:contentDescription="@string/save"/>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/group_coordinator"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/toolbar_action"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/activity_group_header">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="match_parent"
@@ -123,48 +129,57 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:background="?android:attr/windowBackground"
android:layout_below="@+id/toolbar" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/activity_group_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent">
<com.kunzisoft.keepass.view.ToolbarAction
android:id="@+id/toolbar_action"
android:layout_width="match_parent"
android:layout_height="64dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner" />
<com.kunzisoft.keepass.view.AddNodeButtonView
android:id="@+id/add_node_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_anchor="@+id/nodes_list_fragment_container"
app:layout_anchorGravity="end|bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.kunzisoft.keepass.view.ToolbarAction
android:id="@+id/toolbar_action"
android:layout_width="match_parent"
android:layout_height="64dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/loading"
<include
layout="@layout/view_button_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
</FrameLayout>
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner"
app:layout_constraintStart_toStartOf="parent" />
<include
layout="@layout/view_button_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner" />
<include layout="@layout/view_screenshot_mode_banner" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/error_coordinator"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner"/>
<include layout="@layout/view_screenshot_mode_banner" />
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.kunzisoft.keepass.view.NavigationDatabaseView
@@ -172,7 +187,6 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
style="@style/Widget.Material3.NavigationView"
android:fitsSystemWindows="true" />
style="@style/Widget.Material3.NavigationView" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -67,9 +67,19 @@
android:layout_margin="12dp"
android:contentDescription="@string/about"
android:elevation="4dp"
android:src="@drawable/ic_app_white_24dp"
android:src="@drawable/ic_app_lock_white_24dp"
app:tint="?attr/colorSecondary"
android:background="@drawable/background_image"
android:backgroundTint="@color/green"/>
app:backgroundTint="?attr/colorPrimaryContainer"/>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_margin="12dp"
android:contentDescription="@string/about"
android:elevation="4dp"
android:src="@drawable/ic_app_key_white_24dp"
app:tint="?attr/colorOnPrimaryContainer"/>
</FrameLayout>
<com.google.android.material.appbar.MaterialToolbar

View File

@@ -18,42 +18,45 @@
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:filterTouchesWhenObscured="true"
android:background="?android:attr/windowBackground"
android:fitsSystemWindows="true">
android:background="?android:attr/windowBackground">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/toolbar_coordinator"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner">
app:layout_constraintBottom_toTopOf="@+id/screenshot_mode_banner" >
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/toolbar_default"
app:layout_constraintTop_toTopOf="parent"/>
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<include
android:id="@+id/toolbar"
layout="@layout/toolbar_default" />
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<include
layout="@layout/view_button_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|bottom" />
layout="@layout/view_button_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
app:layout_anchorGravity="bottom|start"
app:layout_dodgeInsetEdges="bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<include layout="@layout/view_screenshot_mode_banner" />
<include layout="@layout/view_screenshot_mode_banner"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -50,14 +50,14 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_view_padding">
<com.kunzisoft.keepass.view.PassKeyView
<com.kunzisoft.keepass.view.PasswordEditView
android:id="@+id/passphrase_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/passphrase_copy_button"
android:layout_toLeftOf="@+id/passphrase_copy_button"
app:passKeyHint="@string/passphrase"
app:passKeyMaxLines="7"/>
app:passwordHint="@string/passphrase"
app:passwordMaxLines="7"/>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/passphrase_copy_button"

View File

@@ -50,7 +50,7 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_view_padding">
<com.kunzisoft.keepass.view.PassKeyView
<com.kunzisoft.keepass.view.PasswordEditView
android:id="@+id/password_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -207,6 +207,8 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/ignore_chars_filter_layout"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_width="0dp"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText

View File

@@ -29,7 +29,7 @@
android:scrollbarStyle="insideOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="64dp"
android:paddingBottom="120dp"
android:clipToPadding="false" />
<LinearLayout
android:id="@+id/not_found_container"

View File

@@ -72,11 +72,11 @@
android:text="@string/password"/>
<!-- Password Input -->
<com.kunzisoft.keepass.view.PassKeyView
<com.kunzisoft.keepass.view.PasswordEditView
android:id="@+id/password_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passKeyVisible="false"/>
app:passwordVisible="false"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_repeat_input_layout"
android:layout_width="match_parent"
@@ -121,6 +121,15 @@
android:layout_height="wrap_content"
android:text="@string/entry_keyfile"/>
<com.google.android.material.button.MaterialButton
style="@style/KeepassDXStyle.Button.Secondary"
android:id="@+id/keyfile_generate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="end"
app:icon="@drawable/ic_file_key_white_24dp"
android:text="@string/generate_keyfile" />
<com.kunzisoft.keepass.view.KeyFileSelectionView
android:id="@+id/keyfile_selection"
android:layout_width="match_parent"

View File

@@ -1,91 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:gravity="bottom"
android:orientation="vertical"
android:layout_marginBottom="6dp"
android:paddingTop="36dp"
android:paddingLeft="@dimen/default_margin"
android:paddingRight="@dimen/default_margin"
android:paddingBottom="@dimen/default_margin"
tools:ignore="UnusedAttribute">
<TextView
android:id="@+id/nav_database_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
style="@style/KeepassDXStyle.Text.Info.OnSurface"
android:textSize="11sp"
tools:text="version"
android:textIsSelectable="true" />
<ImageView
android:id="@+id/nav_database_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/content_description_nav_header"
app:layout_constraintTop_toBottomOf="@+id/nav_database_version"
app:layout_constraintBottom_toTopOf="@+id/nav_database_name"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:layout_marginBottom="12dp"
app:srcCompat="@drawable/ic_database_white_36dp"
style="@style/KeepassDXStyle.Icon"
app:tint="?attr/colorSecondary" />
<ImageView
android:id="@+id/nav_database_modified"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/save"
android:src="@drawable/ic_modified_white_12dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/nav_database_icon"
app:layout_constraintStart_toEndOf="@+id/nav_database_icon"
app:layout_constraintTop_toTopOf="@+id/nav_database_icon" />
<ImageView
android:id="@+id/nav_database_color"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="center"
android:contentDescription="@string/content_description_database_color"
android:src="@drawable/background_icon"
app:layout_constraintBottom_toBottomOf="@+id/nav_database_name"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/nav_database_name"
style="@style/KeepassDXStyle.Title.OnSurface"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:maxLines="2"
android:text="@string/database"
android:textIsSelectable="true"
app:layout_constraintBottom_toTopOf="@+id/nav_database_path"
app:layout_constraintEnd_toStartOf="@+id/nav_database_color"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/nav_database_path"
style="@style/KeepassDXStyle.Text.Info.OnSurface"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
android:textSize="11sp"
android:text="@string/path"
android:textIsSelectable="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
android:gravity="bottom"
android:layout_margin="@dimen/default_margin">
<TextView
android:id="@+id/nav_database_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingEnd="8dp"
android:paddingRight="8dp"
style="@style/KeepassDXStyle.Text.Info.OnSurface"
android:textSize="11sp"
tools:text="version"
android:textIsSelectable="true" />
<ImageView
android:id="@+id/nav_database_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/content_description_nav_header"
app:layout_constraintTop_toBottomOf="@+id/nav_database_version"
app:layout_constraintBottom_toTopOf="@+id/nav_database_name"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="6dp"
android:layout_marginLeft="6dp"
android:layout_marginBottom="12dp"
app:srcCompat="@drawable/ic_database_white_36dp"
style="@style/KeepassDXStyle.Icon"
app:tint="?attr/colorSecondary" />
<ImageView
android:id="@+id/nav_database_modified"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/save"
android:src="@drawable/ic_modified_white_12dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/nav_database_icon"
app:layout_constraintStart_toEndOf="@+id/nav_database_icon"
app:layout_constraintTop_toTopOf="@+id/nav_database_icon" />
<ImageView
android:id="@+id/nav_database_color"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="center"
android:contentDescription="@string/content_description_database_color"
android:src="@drawable/background_icon"
app:layout_constraintBottom_toBottomOf="@+id/nav_database_name"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/nav_database_name"
style="@style/KeepassDXStyle.Title.OnSurface"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:maxLines="2"
android:text="@string/database"
android:textIsSelectable="true"
app:layout_constraintBottom_toTopOf="@+id/nav_database_path"
app:layout_constraintEnd_toStartOf="@+id/nav_database_color"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/nav_database_path"
style="@style/KeepassDXStyle.Text.Info.OnSurface"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
android:textSize="11sp"
android:text="@string/path"
android:textIsSelectable="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@@ -15,7 +15,7 @@
app:useCompatPadding="true"
android:layout_marginStart="-6dp"
android:layout_marginLeft="-6dp"
android:layout_marginBottom="-10dp"
android:layout_marginBottom="-7dp"
android:contentDescription="@string/lock"
android:layout_gravity="bottom"
android:visibility="visible"

View File

@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_warning_white_24dp"
android:src="@drawable/ic_hourglass_bottom_white_24dp"
android:contentDescription="@string/content_description_file_information"
app:tint="?android:attr/textColor"/>
<androidx.appcompat.widget.AppCompatTextView

View File

@@ -36,7 +36,7 @@
android:minHeight="48dp"
android:hint="@string/password"
android:inputType="textPassword"
android:importantForAutofill="yes"
android:importantForAutofill="no"
android:focusable="true"
android:focusableInTouchMode="true"
android:autofillHints="password"

View File

@@ -7,7 +7,7 @@
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_input_layout"
android:id="@+id/password_edit_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
@@ -18,7 +18,7 @@
tools:ignore="UnusedAttribute">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password_text"
android:id="@+id/password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
@@ -31,23 +31,21 @@
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/password_strength_progress"
android:id="@+id/password_edit_strength_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:padding="1dp"
app:trackCornerRadius="8dp"
app:layout_constraintTop_toBottomOf="@+id/password_input_layout"/>
app:layout_constraintBottom_toBottomOf="@+id/password_edit_input_layout"/>
<TextView
android:id="@+id/password_entropy"
android:id="@+id/password_edit_entropy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Entropy: 72.50 bit"
android:textSize="11sp"
android:layout_margin="4dp"
android:textColor="?attr/colorSecondary"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/password_input_layout"
app:layout_constraintEnd_toEndOf="@+id/password_input_layout" />
style="@style/KeepassDXStyle.Text.Indicator"
android:padding="4dp"
app:layout_constraintBottom_toBottomOf="@+id/password_edit_input_layout"
app:layout_constraintEnd_toEndOf="@+id/password_edit_input_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -6,11 +6,11 @@
android:id="@+id/screenshot_mode_banner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/grey"
android:background="?attr/colorSecondary"
android:paddingHorizontal="16dp"
android:paddingVertical="8dp"
android:text="@string/screenshot_mode_banner_text"
android:textColor="@color/white"
android:textColor="?attr/colorOnSecondary"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View File

@@ -20,17 +20,17 @@
<string name="homepage">الصفحة الرئيسة</string>
<string name="accept">قبول</string>
<string name="add_group">إضافة مجموعة</string>
<string name="encryption">التعميّة</string>
<string name="encryption_algorithm">خوارزمية التعميّة</string>
<string name="encryption">التشفير</string>
<string name="encryption_algorithm">خوارزمية التشفير</string>
<string name="application">التطبيق</string>
<string name="brackets">الأقواس</string>
<string name="extended_ASCII">تمديد ASCII</string>
<string name="extended_ASCII">ASCII ممتد</string>
<string name="allow">سماح</string>
<string name="clipboard_cleared">مُسِحت الحافظة</string>
<string name="clipboard_error_title">خطأ في الحافظة</string>
<string name="clipboard_error_clear">تعذَّر مسح الحافظة</string>
<string name="database">قاعدة البيانات</string>
<string name="decrypting_db">يفك تعمية محتوى قاعدة البيانات…</string>
<string name="decrypting_db">يفك تشفير محتوى قاعدة البيانات…</string>
<string name="digits">أرقام</string>
<string name="entry_cancel">إلغاء</string>
<string name="entry_notes">ملاحظات</string>
@@ -80,7 +80,7 @@
<string name="progress_create">إنشاء قاعدة بيانات جديدة …</string>
<string name="protection">الحماية</string>
<string name="read_only">محمي من التعديل</string>
<string name="content_description_remove_from_list">حذف</string>
<string name="content_description_remove_from_list">إزالة</string>
<string name="root">الجذر</string>
<string name="memory_usage">استخدام الذاكرة</string>
<string name="parallelism">التَّوازِي</string>
@@ -155,15 +155,15 @@
<string name="menu_url">الانتقال الى الرابط</string>
<string name="menu_file_selection_read_only">محمي من التعديل</string>
<string name="menu_open_file_read_and_write">قابل للتعديل</string>
<string name="select_database_file">فتح قاعدة بيانات موجودة</string>
<string name="create_keepass_file">انشاء قاعدة بيانات</string>
<string name="select_database_file">فتح مخزن موجود</string>
<string name="create_keepass_file">انشاء مخزن جديد</string>
<string name="progress_title">قيد العمل…</string>
<string name="read_only_warning">KeePassDX يحتاج صلاحية الكتابة من اجل تعديل قاعدة البيانات.</string>
<string name="encryption_explanation">خوارزمية تشفير جميع البيانات.</string>
<string name="encryption_explanation">خوارزمية تشفير جميع البيانات</string>
<string name="unsupported_db_version">قاعدة بيانات غير مدعومة.</string>
<string name="build_label">بناء %1$s</string>
<string name="encrypted_value_stored">تم حفظ كلمة السر المشفرة</string>
<string name="unavailable">قاعدة البيانات لا تمتلك بيانات اعتماد.</string>
<string name="unavailable">غير متوفر</string>
<string name="menu_appearance_settings">المظهر</string>
<string name="general">عام</string>
<string name="autofill">ملأ تلقائي</string>
@@ -177,7 +177,7 @@
<string name="clipboard_notifications_title">اشعارات الحافظة</string>
<string name="clipboard_warning">اذا فشل الحذف التلقائي من الحافظة ,احذف تأريخه يدويا.</string>
<string name="lock_database_screen_off_title">قفل الشاشة</string>
<string name="lock_database_screen_off_summary">اقفل قاعدة البيانات عند انغلاق الشاشة</string>
<string name="lock_database_screen_off_summary">اقفل قاعدة البيانات بعد بضع ثوانٍ بمجرد إيقاف تشغيل الشاشة</string>
<string name="biometric_delete_all_key_title">حذف مفاتيح التشفير</string>
<string name="unavailable_feature_text">لا يمكن بدأ هذه الميزة .</string>
<string name="unavailable_feature_version">هذا الجهاز يعمل بأندرويد %1$s لكن يحتاج نسخة %2$s على الأقل.</string>
@@ -185,9 +185,9 @@
<string name="path">مسار</string>
<string name="database_history">تأريخ</string>
<string name="clipboard_notifications_summary">أظهر اشعارات الحافظة لنسخ الحقول عند عرض مدخل</string>
<string name="advanced_unlock">البصمة</string>
<string name="advanced_unlock">فتح الجهاز</string>
<string name="biometric_unlock_enable_title">فحص البصمة</string>
<string name="biometric_unlock_enable_summary">يسمح بفحص البصمة لفتح قاعدة البيانات</string>
<string name="biometric_unlock_enable_summary">يتيح لك مسح بياناتك الحيوية لفتح قاعدة البيانات</string>
<string name="monospace_font_fields_enable_summary">غير خط الحقول لتوضيح المحارف</string>
<string name="allow_copy_password_title">الوثوق بالحافظة</string>
<string name="allow_copy_password_summary">اسمح بنسخ كلمة السر والحقول المحمية إلى للحافظة</string>
@@ -213,10 +213,10 @@
<string name="keyboard_keys_category">مفاتيح</string>
<string name="keyboard_key_vibrate_title">إهتزاز عند اللمس</string>
<string name="keyboard_key_sound_title">صوت عند اللمس</string>
<string name="allow_no_password_title">"إسمح بالفتح دون كلمة سر "</string>
<string name="allow_no_password_title">إسمح بدون المفتاح الرئيسي</string>
<string name="enable_read_only_title">محمي من التعديل</string>
<string name="enable_read_only_summary">افتح قاعدة البيانات في وضع القراءة افتراضيا</string>
<string name="enable_education_screens_title">شاشات تعليمية</string>
<string name="enable_education_screens_title">تلميحات تعليمية</string>
<string name="reset_education_screens_summary">أعد عرض كل المعلومات التعليمية</string>
<string name="reset_education_screens_text">إعادة تعيين الشاشات التلميحات</string>
<string name="education_create_database_title">أنشئ قاعدة بيانات</string>
@@ -233,7 +233,7 @@
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
<string name="keyboard_notification_entry_content_title">%1$s متوفر على Magikeyboard</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="reset_education_screens_title">إعادة تعيين الشاشات التعليمية</string>
<string name="reset_education_screens_title">إعادة تعيين التلميحات التعليمية</string>
<string name="education_search_title">البحث من خلال الإدخالات</string>
<string name="content_description_open_file">افتح الملف</string>
<string name="content_description_add_entry">إضافة مدخلة</string>
@@ -261,7 +261,7 @@
<string name="content_description_update_from_list">تحديث</string>
<string name="content_description_keyboard_close_fields">أغلق الحقول</string>
<string name="error_create_database_file">لا يمكن انشاء قاعدة بيانات بكلمة السر وملف المفتاح الحاليين.</string>
<string name="menu_advanced_unlock_settings">فك القفل المتقدم</string>
<string name="menu_advanced_unlock_settings">فك قفل الجهاز</string>
<string name="entry_attachments">مرفقات</string>
<string name="entry_history">السجل</string>
<string name="entry_add_attachment">أضف مرفقا</string>
@@ -272,7 +272,7 @@
<string name="master_key">المفتاح الرئيسي</string>
<string name="error_otp_period">يجب ان تكون المدة بين %1$d و%2$d ثانية.</string>
<string name="error_otp_secret_key">المفتاح السري يجب ان يكون بصيغة Base32.</string>
<string name="error_save_database">لا يمكن حفظ قاعدة البيانات.</string>
<string name="error_save_database">تعذر حفظ قاعدة البيانات.</string>
<string name="error_create_database">لا يمكن إنشاء ملف قاعدة البيانات.</string>
<string name="error_copy_group_here">لا يمكن نسخ مجموعة هنا.</string>
<string name="error_label_exists">هذه التسمية موجودة بالفعل.</string>
@@ -334,8 +334,8 @@
<string name="database_data_compression_title">ضغط البيانات</string>
<string name="data">البيانات</string>
<string name="unavailable_feature_hardware">تعذر العثور على ماسح البصمة.</string>
<string name="biometric_delete_all_key_summary">احذف كل مفاتيح التعمية المرتبطة بفك القفل المتقدم</string>
<string name="advanced_unlock_explanation_summary">استخدم إلغاء القفل المتقدم لفتح قاعدة البيانات بسهولة</string>
<string name="biometric_delete_all_key_summary">احذف كل مفاتيح التشفير المرتبطة بفتح الجهاز</string>
<string name="advanced_unlock_explanation_summary">استخدم إلغاء القفل الجهاز لفتح قاعدة البيانات بسهولة</string>
<string name="lock_database_show_button_summary">يعرض زر القَفل في الواجهة</string>
<string name="lock_database_show_button_title">اعرض زر القَفل</string>
<string name="lock_database_back_root_summary">قفل قاعدة البيانات عند النقر على زر الرجوع في الشاشة الرئيسية</string>
@@ -359,10 +359,10 @@
<string name="autofill_application_id_blocklist_title">قائمة التطبيقات المحظورة</string>
<string name="content_description_repeat_toggle_password_visibility">بدِّل ظهور كلمة السر</string>
<string name="hide_expired_entries_summary">لن تعرض المدخلات منتهية الصلاحية</string>
<string name="education_read_only_summary">غيِّر وضع الجلسة.
<string name="education_read_only_summary">تغيير وضع الافتتاح للجلسة.
\n
\n\"محمي من التعديل\" يمنع أي تغيير في قاعدة البيانات.
\n\"قابل للتعديل\" يتيح لك إضافة أو حذف أو تعديل جميع العناصر.</string>
\nيمنع \"محمي ضد الكتابة\" التغييرات غير المقصودة في قاعدة البيانات.
\n\"قابل للتعديل\" يتيح لك إضافة أو حذف أو تعديل جميع العناصر كما تريد.</string>
<string name="education_read_only_title">احمي قاعدة البيانات من التعديل</string>
<string name="education_unlock_title">افتح قاعدة البيانات</string>
<string name="education_add_attachment_summary">أضف مرفقا للمدخلة لحفظ بيانات اضافية.</string>
@@ -373,7 +373,7 @@
<string name="keyboard_selection_entry_title">اختيار المدخلة</string>
<string name="device_keyboard_setting_title">إعدادات لوحة مفاتيح الجهاز</string>
<string name="magic_keyboard_explanation_summary">نشِّط لوحة مفاتيح مخصصة لملأ كلمة السر وحقول معرّفك</string>
<string name="biometric_auto_open_prompt_summary">اطلب فك القفل المتقدم ان كانت قاعدة البيانات معدّة لذلك</string>
<string name="biometric_auto_open_prompt_summary">اطلب إلغاء قفل الجهاز تلقائيًا إذا كانت قاعدة البيانات معدّة لذلك</string>
<string name="biometric_auto_open_prompt_title">افتح المحث تلقائيا</string>
<string name="keystore_not_accessible">لم يُهيأ مخزن المفاتيح بشكل صحيح.</string>
<string name="warning_remove_unlinked_attachment">حذف البيانات سيقلل من حجم قاعدة البيانات لكن احذر أن تكون إحدى هذه البيانات ملحقة لكي-باس.</string>
@@ -428,7 +428,7 @@
<string name="membership">العضوية</string>
<string name="name">الاسم</string>
<string name="email">البريد الإلكتروني</string>
<string name="email_address">البريد الإلكتروني</string>
<string name="email_address">عنوان البريد الإلكتروني</string>
<string name="ssid">SSID</string>
<string name="debit_credit_card">بطاقة السحب الفوري / الإئتمان</string>
<string name="error_registration_read_only">لا يمكن حفظ عنصر في قاعدة بيانات مفتوحة للقراءة فقط</string>
@@ -446,34 +446,34 @@
<string name="back_to_previous_keyboard">عُد للوحة المفاتيح السابقة</string>
<string name="select_entry">اختر مدخلًا</string>
<string name="autofill_close_database_title">أغلق قاعدة البيانات</string>
<string name="success_import_app_properties">أّستوردت خصائص التطبيق</string>
<string name="success_export_app_properties">صُدرت خصائص التطبيق</string>
<string name="success_import_app_properties">أّستوردت إعدادات التطبيق</string>
<string name="success_export_app_properties">صُدرت إعدادات التطبيق</string>
<string name="warning_database_revoked">أُجهض الوصول إلى الملف بواسطة مدير الملفات ، أغلق قاعدة البيانات ثم أعد فتحها.</string>
<string name="properties">الخصائص</string>
<string name="token">الرمز</string>
<string name="seed">البذرة</string>
<string name="error_database_uri_null">يتعذر استرداد مسار قاعدة البيانات.</string>
<string name="error_rebuild_list">يتعذر إعادة بناء القائمة بشكل صحيح.</string>
<string name="menu_keystore_remove_key">احذف رمز فك القفل المتقدم</string>
<string name="menu_form_filling_settings">تعبئة الحقول</string>
<string name="menu_keystore_remove_key">احذف رمز فك القفل الجهاز</string>
<string name="menu_form_filling_settings">ملء النموذج</string>
<string name="menu_reload_database">أعد تحميل البيانات</string>
<string name="menu_external_icon">أيقونة خارجية</string>
<string name="registration_mode">وضع التسجيل</string>
<string name="import_app_properties_title">استورد خصائص التطبيق</string>
<string name="import_app_properties_summary">اختر ملفًا لاستيراد خصائص التطبيق</string>
<string name="export_app_properties_title">صدّر خصائص التطبيق</string>
<string name="export_app_properties_summary">أنشئ ملفًا لتصدير خصائص التطبيق</string>
<string name="error_import_app_properties">خطأ أثناء استيراد خصائص التطبيق</string>
<string name="error_export_app_properties">خطأ أثناء تصدير خصائص التطبيق</string>
<string name="import_app_properties_summary">اختر ملفًا لاستيراد إعدادات التطبيق</string>
<string name="export_app_properties_title">صدّر إعدادات التطبيق</string>
<string name="export_app_properties_summary">أنشئ ملفًا لتصدير إعدادات التطبيق</string>
<string name="error_import_app_properties">خطأ أثناء استيراد إعدادات التطبيق</string>
<string name="error_export_app_properties">خطأ أثناء تصدير إعدادات التطبيق</string>
<string name="warning_database_info_changed">غُيِّرت معلومات قاعدة البيانات من خارج هذا التطبيق.</string>
<string name="warning_database_info_changed_options">ادمج البيانات أو استبدل التعديلات الخارجية بحفظ قاعدة البيانات أو أعد تحميلها لجلب آخر التغييرات.</string>
<string name="credential_before_click_advanced_unlock_button">اكتب كلمة السر، وأنقر هذا الزر.</string>
<string name="device_credential">بيانات الاعتماد للجهاز</string>
<string name="advanced_unlock_tap_delete">انفر لحذف مفاتيح فك القفل المتقدم</string>
<string name="advanced_unlock_tap_delete">انقر لحذف مفاتيح فتح الجهاز</string>
<string name="keyboard_auto_go_action_title">إجراء اللمس التلقائي</string>
<string name="keyboard_previous_fill_in_title">إجراء لمس تلقائي</string>
<string name="keyboard_previous_fill_in_title">العودة إلى الوراء</string>
<string name="keyboard_previous_lock_title">اقفل قاعدة البيانات</string>
<string name="education_advanced_unlock_title">فك القفل المتقدم لقاعدة البيانات</string>
<string name="education_advanced_unlock_title">فتح قاعدة بيانات الجهاز</string>
<string name="hint_icon_name">اسم الأيقونة</string>
<string name="autofill_manual_selection_title">اختيار يدوي</string>
<string name="description_app_properties">خصائص KeePassDX لإدارة إعدادات التطبيقات</string>
@@ -483,7 +483,7 @@
<string name="content_description_database_color">لون قاعدة البيانات</string>
<string name="menu_merge_from">ادمج من…</string>
<string name="show_uuid_summary">يعرض \"المعرف العام\" المرتبط بمُدخل او بمجموعة</string>
<string name="expired">انتهت المهلة</string>
<string name="expired">انتهت</string>
<string name="tags">الوسوم</string>
<string name="menu_merge_database">ادمج البيانات</string>
<string name="current_group">المجموعة الحالية</string>
@@ -497,11 +497,11 @@
<string name="custom_data">بيانات مخصصة</string>
<string name="case_sensitive">حساسة لحالة الأحرف</string>
<string name="regex">تعابير نمطية</string>
<string name="enable_keep_screen_on_title">أبق الشاشة شغّالة</string>
<string name="enable_keep_screen_on_title">أبقِ الشاشة شغّالة</string>
<string name="enable_education_screens_summary">أبرز العناصر لتعلم طريقة عمل التطبيق</string>
<string name="autofill_read_only_save">غير مسموح حفظ البيانات في قاعدة بيانات مفتوحة للقراءة فقط.</string>
<string name="autofill_inline_suggestions_keyboard">أُضيف اقتراح ملء تلقائي.</string>
<string name="keyboard_previous_database_credentials_summary">ارجع للوحة المفاتيح السابقة تلقائيًا في شاشة بيانات اعتماد قاعدة البيانات.</string>
<string name="keyboard_previous_database_credentials_summary">الرجوع للوحة المفاتيح السابقة تلقائيًا في شاشة بيانات اعتماد قاعدة البيانات</string>
<string name="autofill_manual_selection_summary">اعرض خيارًا يسمح للمستخدم باختيار مدخلة من قاعدة البيانات</string>
<string name="keyboard_previous_search_title">شاشة البحث</string>
<string name="keyboard_previous_search_summary">ارجع للوحة المفاتيح السابقة تلقائيًا في شاشة البحث</string>
@@ -510,16 +510,190 @@
<string name="autofill_close_database_summary">أغلق قاعدة البيانات بعد الملء التلقائي</string>
<string name="autofill_ask_to_save_data_summary">اسأل عن حفظ البيانات عند ملئك لنموذج</string>
<string name="templates_group_uuid_title">مجموعة القوالب</string>
<string name="advanced_unlock_timeout">انتهت مهلة فك القفل المتقدم</string>
<string name="temp_advanced_unlock_timeout_summary">مهلة استخدام فك القفل المتقدم قبل حذف محتواها</string>
<string name="advanced_unlock_delete_all_key_warning">أتريد حذف كل مفاتيح التعمية المرتبطة بفك القفل المتقدم؟</string>
<string name="advanced_unlock_timeout">انتهت مهلة فتح الجهاز</string>
<string name="temp_advanced_unlock_timeout_summary">مهلة استخدام فتح الجهاز قبل حذف محتواها</string>
<string name="advanced_unlock_delete_all_key_warning">أتريد حذف كل مفاتيح التشفير المرتبطة بفتح الجهاز؟</string>
<string name="templates">القوالب</string>
<string name="templates_group_enable_title">استخدام القوالب</string>
<string name="notification">الإشعارات</string>
<string name="temp_advanced_unlock_enable_summary">لا تستخدم أي محتوى معمى لاستخدام فك القفل المتقدم</string>
<string name="temp_advanced_unlock_timeout_title">انتهاء صلاحية فك القفل المتقدم</string>
<string name="temp_advanced_unlock_enable_summary">لا تقم بتخزين أي محتوى مشفر لاستخدام إلغاء قفل الجهاز</string>
<string name="temp_advanced_unlock_timeout_title">انتهاء صلاحية فتح الحهاز</string>
<string name="hide_expired_entries_title">إخفاء الإدخالات منتهية الصلاحية</string>
<string name="content_description_hardware_key_checkbox">خانة إختيار مفتاح الجهاز</string>
<string name="content_description_passphrase_word_count">عدد عبارات المرور</string>
<string name="content_description_entry_background_color">لون خلفية المدخل</string>
<string name="passphrase">عبارة المرور</string>
<string name="colorize_password_title">تلوين كلمات المرور</string>
<string name="permission">الإذن</string>
<string name="advanced_unlock_prompt_not_initialized">تعذر تهيئة موجه إلغاء قفل الجهاز.</string>
<string name="biometric_security_update_required">مطلوب تحديث أمان المقاييس الحيوية.</string>
<string name="advanced_unlock_not_recognized">تعذر التعرف على طباعة فتح الجهاز</string>
<string name="temp_advanced_unlock_enable_title">فتح جهاز مؤقت</string>
<string name="autofill_inline_suggestions_title">اقتراحات مضمنة</string>
<string name="education_setup_OTP_summary">قم بإعداد إدارة كلمات المرور لمرة واحدة (HOTP / TOTP) لإنشاء رمز مميز مطلوب للمصادقة الثنائية (2FA).</string>
<string name="education_field_copy_summary">يمكن لصق الحقول المنسوخة في أي مكان.
\n
\nاستخدم طريقة ملء النموذج التي تفضلها.</string>
<string name="html_text_dev_feature_work_hard">نحن نعمل بجد لإصدار هذه الميزة بسرعة.</string>
<string name="autofill_inline_suggestions_summary">حاول عرض اقتراحات الملء التلقائي مباشرة من لوحة مفاتيح متوافقة</string>
<string name="delete_entered_password_summary">يحذف كلمة المرور التي تم إدخالها بعد محاولة الاتصال بقاعدة البيانات</string>
<string name="education_lock_summary">اقفل قاعدةبياناتك بسرعة، يمكنك إعداد التطبيق لقفلها بعد فترة، وعند إيقاف تشغيل الشاشة.</string>
<string name="education_sort_title">فرز العنصر</string>
<string name="contribute">ساهِم</string>
<string name="upload_attachment">رفع %1$s</string>
<string name="download_canceled">ألغيت!</string>
<string name="unit_kibibyte">كيلو بايت</string>
<string name="unit_mebibyte">ميغا بايت</string>
<string name="unit_gibibyte">جيجابت</string>
<string name="entropy">إنتروبيا: %1$s بت</string>
<string name="entropy_high">الانتروبيا: مرتفع</string>
<string name="entropy_calculate">الانتروبيا: احسب…</string>
<string name="exclude_ambiguous_chars">استبعاد الأحرف الغامضة</string>
<string name="consider_chars_filter">ضع في اعتبارك الأحرف</string>
<string name="ignore_chars_filter">تجاهل الأحرف</string>
<string name="style_choose_title">سمة التطبيق</string>
<string name="lower_case">أحرف صغيرة</string>
<string name="upper_case">الأحرف الكبيرة</string>
<string name="title_case">حالة العنوان</string>
<string name="character_count">عدد الأحرف: %1$d</string>
<string name="style_choose_summary">السمة المستخدمة في التطبيق</string>
<string name="show_entry_colors_summary">يعرض ألوان المقدمة والخلفية لإدخال</string>
<string name="icon_pack_choose_summary">حزمة الأيقونات المستخدمة في التطبيق</string>
<string name="show_entry_colors_title">ألوان الدخول</string>
<string name="device_credential_unlock_enable_title">فتح بيانات اعتماد الجهاز</string>
<string name="autofill_block_restart">أعد تشغيل التطبيق الذي يحتوي على النموذج لتنشيط الحظر.</string>
<string name="education_donation_title">مشاركة</string>
<string name="education_donation_summary">ساعد في زيادة الاستقرار والأمان وفي إضافة المزيد من الميزات.</string>
<string name="html_text_dev_feature">هذه الميزة &lt;strong&gt; قيد التطوير&lt;/strong&gt; وتتطلب &lt;strong&gt; مساهمتك&lt;/strong&gt; لتكون متاحة قريبًا.</string>
<string name="html_text_dev_feature_contibute">من خلال &lt;strong&gt; المساهمة&lt;/strong&gt; ،</string>
<string name="download_finalization">جارِ الانتهاء…</string>
<string name="download_complete">مكتمل!</string>
<string name="unit_byte">B</string>
<string name="icon_section_custom">مُخصص</string>
<string name="content_description_entry_foreground_color">لون مقدمة الدخول</string>
<string name="keyboard_previous_fill_in_summary">العودة تلقائيًا إلى لوحة المفاتيح السابقة بعد تنفيذ \"إجراء المفتاح التلقائي\"</string>
<string name="download_attachment">تثبيت %1$s</string>
<string name="html_about_privacy">&lt;strong&gt; لا يتم استرداد أي بيانات مستخدم&lt;/strong&gt;، هذا التطبيق لا يتصل بأي خادم، ويعمل محليًا فقط ويحترم خصوصية المستخدمين تمامًا.</string>
<string name="error_cancel_by_user">ألغى المستخدم.</string>
<string name="show_otp_token_title">إظهار رمز \"الاقتران لمرة واحدة\" OTP</string>
<string name="show_otp_token_summary">إظهار رموز\"الاقتران لمرة واحدة\" في قائمة المدخلات</string>
<string name="warning_database_already_opened">قاعدة البيانات مفتوحة بالفعل، أغلقها أولاً لفتح قاعدة البيانات الجديدة</string>
<string name="warning_database_info_reloaded">ستؤدي إعادة تحميل قاعدة البيانات إلى حذف البيانات المعدلة محليًا.</string>
<string name="templates_group_enable_summary">استخدم القوالب الديناميكية لملء حقول الإدخال</string>
<string name="keyboard_auto_go_action_summary">إجراء مفتاح \"Go\" بعد الضغط على مفتاح \"Field\"</string>
<string name="allow_no_password_summary">يسمح بالنقر فوق الزر \"فتح\" إذا لم يتم تحديد بيانات اعتماد</string>
<string name="education_generate_password_summary">أنشئ كلمة مرور قوية لربطها بإدخالك، وحددها بسهولة وفقًا لمعايير النموذج ولا تنس كلمة المرور الآمنة.</string>
<string name="education_setup_OTP_title">قم بإعداد OTP</string>
<string name="style_brightness_title">سطوع السمة</string>
<string name="word_separator">الفاصل</string>
<string name="screenshot_mode_banner_text">وضع لقطة الشاشة</string>
<string name="style_brightness_summary">اختيار سمة فاتحة او داكنة</string>
<string name="icon_section_standard">قياسي</string>
<string name="wireless">واي فاي Wi-Fi</string>
<string name="icon_pack_choose_title">حزمة أيقونات</string>
<string name="content_description_nav_header">رأس التنقل</string>
<string name="inherited">موروث</string>
<string name="auto_type_sequence">تسلسل الكتابة تلقائيًا</string>
<string name="kdf_explanation">لإنشاء مفتاح خوارزمية التشفير، يتحول المفتاح الرئيسي باستخدام وظيفة اشتقاق مفتاح مملح عشوائيًا.</string>
<string name="html_text_dev_feature_buy_pro">بشراء الإصدار &lt;strong&gt; pro &lt;/strong&gt;،</string>
<string name="auto_type">كتابة تلقائيًا</string>
<string name="hardware_key">مفتاح الجهاز</string>
<string name="advanced_unlock_prompt_store_credential_title">رابط لفتح الجهاز</string>
<string name="backspace">فراغ للخلف</string>
<string name="enter">دخول</string>
<string name="education_sort_summary">اختر كيفية فرز الإدخالات والمجموعات.</string>
<string name="html_text_feature_generosity">هذا &lt;strong&gt; النمط المرئي&lt;/strong&gt; متاح بفضل كرمك.</string>
<string name="info">المعلومات</string>
<string name="waiting_challenge_response">في انتظار استجابة التحدي…</string>
<string name="bank_identifier_code">SWIFT / BIC</string>
<string name="international_bank_account_number">IBAN</string>
<string name="error_no_hardware_key">حدد مفتاح الجهاز.</string>
<string name="colorize_password_summary">تلوين أحرف كلمة المرور حسب النوع</string>
<string name="enable_keep_screen_on_summary">استمر في تشغيل الشاشة عند مشاهدة إدخال أو تعديله</string>
<string name="enable_screenshot_mode_title">وضع لقطة الشاشة</string>
<string name="navigation_drawer_open">درج التنقل مفتوح</string>
<string name="waiting_challenge_request">في انتظار طلب التحدي…</string>
<string name="navigation_drawer_close">درج التنقل مقفول</string>
<string name="error_XML_malformed">XML تالف.</string>
<string name="error_otp_type">لم يتم التعرف على نوع OTP الحالي من خلال هذا النموذج، وقد لا يؤدي التحقق من صحته إلى إنشاء الرمز المميز بشكل صحيح.</string>
<string name="error_challenge_already_requested">التحدي مطلوب بالفعل</string>
<string name="error_response_already_provided">تقدم الرد بالفعل.</string>
<string name="error_no_response_from_challenge">غير قادر على الحصول على رد من التحدي.</string>
<string name="error_driver_required">مطلوب تعريف لـ%1$s.</string>
<string name="error_unable_merge_database_kdb">غير قادر على الدمج مع ملف قاعدة بيانات kdb</string>
<string name="error_location_unknown">موقع قاعدة البيانات غير معروف، لا يمكن تنفيذ إجراء قاعدة البيانات.</string>
<string name="menu_advanced_unlock_settings_summary">القياس الحيوي، بيانات اعتماد الجهاز</string>
<string name="menu_database_settings_summary">البيانات الوصفية، سلة المحذوفات، القوالب، التاريخ</string>
<string name="menu_security_settings_summary">التشفير، وظيفة اشتقاق المفتاح</string>
<string name="error_hardware_key_unsupported">مفتاح الجهاز غير مدعوم.</string>
<string name="master_key_settings_summary">التغيير والتجديد</string>
<string name="error_empty_key">لا يمكن أن يكون المفتاح فارغًا.</string>
<string name="corrupted_file">ملف تالف.</string>
<string name="warning_keyfile_integrity">لا يتم ضمان تجزئة الملف لأن Android يمكنه تغيير بياناته بسرعة. قم بتغيير امتداد الملف إلى bin. من أجل التكامل الصحيح.</string>
<string name="invalid_db_same_uuid">%1$s بنفس UUID %2$s موجود بالفعل.</string>
<string name="remember_hardware_key_title">تذكر مفاتيح الأجهزة</string>
<string name="warning_exact_alarm">لم تسمح للتطبيق باستخدام منبه دقيق. نتيجة لذلك، لن يتم تنفيذ الميزات التي تتطلب مؤقتًا في وقت محدد.</string>
<string name="remember_hardware_key_summary">يتتبع مفاتيح الأجهزة المستخدمة</string>
<string name="warning_database_notification_permission">يسمح لك إذن الإشعار بعرض حالة قاعدة البيانات وقفلها باستخدام زر يسهل الوصول إليه.
\n
\nإذا لم تنشط هذا الإذن، فلن تكون قاعدة البيانات المفتوحة في الخلفية مرئية إذا كان هناك تطبيق آخر في المقدمة.</string>
<string name="warning_copy_permission">مطلوب إذن الإشعار لاستخدام ميزة إشعار الحافظة.</string>
<string name="merge_success">اكتمل الدمج بنجاح</string>
<string name="advanced_unlock_prompt_store_credential_message">ما زلت بحاجة إلى تذكر بيانات الاعتماد الرئيسية في مخزنك إذا كنت تستخدم التعرف على فتح الجهاز.</string>
<string name="advanced_unlock_prompt_extract_credential_title">التعرف على فتح الجهاز</string>
<string name="later">لاحقًا</string>
<string name="configure">تضبيط</string>
<string name="advanced_unlock_prompt_extract_credential_message">استخراج بيانات اعتماد قاعدة البيانات مع بيانات فتح الجهاز</string>
<string name="ask">إسأل</string>
<string name="configure_biometric">لم تسجل بيانات اعتماد المقاييس الحيوية أو الجهاز.</string>
<string name="show_uuid_title">إظهار \"المعرف العام المميز\" UUID</string>
<string name="unlock_and_link_biometric">رابط فتح الجهاز</string>
<string name="advanced_unlock_invalid_key">لا يمكن قراءة مفتاح فتح الجهاز. يرجى حذفه وتكرار إجراء التعرف على الفتح.</string>
<string name="advanced_unlock_scanning_error">خطأ في فتح الجهاز: %1$s</string>
<string name="menu_appearance_settings_summary">المظاهر والألوان والسمات</string>
<string name="autofill_explanation_summary">تمكين الملء التلقائي لملء النماذج بسرعة في التطبيقات الأخرى</string>
<string name="device_credential_unlock_enable_summary">يتيح لك استخدام بيانات اعتماد جهازك لفتح قاعدة البيانات</string>
<string name="autofill_service_name">KeePassDX نموذج الملء التلقائي</string>
<string name="unlock">فتح</string>
<string name="menu_app_settings_summary">البحث، القفل، التاريخ، الخصائص</string>
<string name="menu_form_filling_settings_summary">لوحة المفاتيح، الملء التلقائي، الحافظة</string>
<string name="advanced_unlock_keystore_warning">ستقوم هذه الميزة بتخزين بيانات الاعتماد المشفرة في KeyStore الآمن بجهازك.
\n
\nاعتمادًا على تطبيق API الأصلي لنظام التشغيل، قد لا يعمل بكامل طاقته.
\n
\nتحقق من توافق وأمن KeyStore مع الشركة المصنعة لجهازك ومنشئ ROM الذي تستخدمه.</string>
<string name="keyboard_selection_entry_summary">عند عرض إدخال في KeePassDX، عبئ Magikeyboard بهذا الإدخال</string>
<string name="enable_screenshot_mode_summary">اسمح لتطبيقات الطرف الثالث بتسجيل أو التقاط لقطات شاشة للتطبيق</string>
<string name="keyboard_save_search_info_summary">حاول حفظ المعلومات المشتركة عند إجراء اختيار إدخال يدوي لاستخدامات مستقبلية أسهل</string>
<string name="education_entry_edit_summary">تحرير الإدخال الخاص بك مع الحقول المخصصة. يمكن الرجوع إلى بيانات التجمع بين حقول الإدخال المختلفة.</string>
<string name="education_validate_entry_title">تحقق من صحة الإدخال</string>
<string name="education_validate_entry_summary">تذكر التحقق من صحة الإدخال الخاص بك وحفظ قاعدة البيانات الخاصة بك.
\n
\nإذا تم تنشيط القفل التلقائي ونسيت أنك تجري تعديلاً، فإنك تخاطر بفقدان بياناتك.</string>
<string name="education_entry_new_field_summary">قم بتسجيل حقل إضافي، أضف قيمة وقم بحمايته بشكل اختياري.</string>
<string name="education_unlock_summary">أدخل كلمة المرور و/أو ملف المفتاح لفتح قاعدة بياناتك.
\n
\nقم بعمل نسخة احتياطية من ملف قاعدة البيانات في مكان آمن بعد كل تغيير.</string>
<string name="html_text_dev_feature_thanks">شكرا جزيلا لمساهمتك.</string>
<string name="at_least_one_char">على الأقل حرف واحد من كل منهما</string>
<string name="html_text_dev_feature_upgrade">تذكر أن تحافظ على تحديث تطبيقك عن طريق تثبيت إصدارات جديدة.</string>
<string name="download">تثبيت</string>
<string name="html_text_ad_free">على عكس العديد من تطبيقات إدارة كلمات المرور ، فإن هذا التطبيق &lt;strong&gt;بدون إعلانات&lt;/strong&gt;، و &lt;strong&gt;برنامج حر متروك الحقوق&lt;/strong&gt; ولا يجمع البيانات الشخصية على خوادمه، بغض النظر عن الإصدار الذي تستخدمه.</string>
<string name="download_initialization">جارِ التهيئة…</string>
<string name="download_progression">قيد التقدم: %1$d%%</string>
<string name="html_text_buy_pro">بشراء الإصدار الاحترافي، ستتمتع بإمكانية الوصول إلى هذا &lt;strong&gt; النمط المرئي&lt;/strong&gt; وستساعد بشكل خاص في &lt;strong&gt; تنفيذ مشروعات المجتمع. &lt;/strong&gt;</string>
<string name="html_text_donation">من أجل الحفاظ على حريتنا ولكي نكون نشيطين دائمًا، فإننا نعتمد على &lt;strong&gt; مساهمتك.&lt;/strong&gt;</string>
<string name="html_text_dev_feature_encourage">أنت تشجع المطورين على إنشاء &lt;strong&gt; ميزات جديدة&lt;/strong&gt; و &lt;strong&gt; إصلاح الخلل&lt;/strong&gt; وفقًا لملاحظاتك.</string>
<string name="style_name_forest">غابة</string>
<string name="style_name_simple">بسيط</string>
<string name="style_name_moon">قمر</string>
<string name="style_name_divine">إلهي</string>
<string name="style_name_classic">كلاسيكي</string>
<string name="style_name_dark">داكن</string>
<string name="style_name_reply">رد</string>
<string name="warning_database_info_changed_options_read_only">أعِد تحميل قاعدة البيانات بأحدث التغييرات.</string>
<string name="style_name_sun">شمس</string>
<string name="style_name_kunzite">الكونزيت</string>
<string name="style_name_follow_system">اتبع النظام</string>
<string name="style_name_light">فاتح</string>
</resources>

View File

@@ -0,0 +1,662 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="info">Məlumat</string>
<string name="contact">Əlaqə</string>
<string name="homepage">Ana səhifə</string>
<string name="add_entry">Şifrə əlavə et</string>
<string name="edit_entry">Şifrəyə düzəliş et</string>
<string name="add_group">Qrup əlavə et</string>
<string name="key_derivation_function">Açar yaratma funksiyası</string>
<string name="app_timeout">Taym-aut</string>
<string name="app_timeout_summary">Məlumat bazasını kilidləmədən öncəki boşluq müddəti</string>
<string name="application">Tətbiq</string>
<string name="brackets">Mötərizə</string>
<string name="extended_ASCII">Artırılmış ASCII</string>
<string name="allow">İcazə ver</string>
<string name="clipboard_cleared">Mübadilə buferi təmizləndi</string>
<string name="clipboard_error_title">Mübadilə buferi xətası</string>
<string name="clipboard_timeout">Mübadilə buferinin taym-aut (boşda qalma) müddəti</string>
<string name="clipboard_timeout_summary">Mübadilə buferində məlumatların saxlanma müddəti (əgər cihazınız dəstəkləyirsə)</string>
<string name="content_description_background">Arxaplan</string>
<string name="content_description_open_file">Faylı</string>
<string name="content_description_add_entry">Qeyd əlavə et</string>
<string name="content_description_add_group">Qrup əlavə et</string>
<string name="content_description_add_item">Fayl əlavə et</string>
<string name="content_description_file_information">Fayl məlumatları</string>
<string name="content_description_credentials_information">Şəxsiyyəti təsdiq edən məlumatlar</string>
<string name="content_description_otp_information">Birdəfəlik şifrə məlumatları</string>
<string name="content_description_keyfile_checkbox">Açar fayl təsdiqi</string>
<string name="content_description_hardware_key_checkbox">Aparat-təchizat açarının təsdiqi</string>
<string name="content_description_entry_icon">Şifrə ikonu</string>
<string name="content_description_database_color">Məlumat bazasının rəngi</string>
<string name="discard_changes">Dəyişiklikləri ləğv et?</string>
<string name="entry_password_generator">Şifrə generatoru</string>
<string name="content_description_password_length">Şifrə uzunluğu</string>
<string name="entry_add_attachment">Qoşma əlavə et</string>
<string name="select_to_copy">%1$sfaylını mübadilə buferinə köçürmək üçün seçin</string>
<string name="retrieving_db_key">Məlumat bazası açarı əldə edilir …</string>
<string name="waiting_challenge_request">Doğrulama istəyi gözlənilir …</string>
<string name="waiting_challenge_response">Doğrulama cavabı gözlənilir …</string>
<string name="database">Məlumat bazası</string>
<string name="template_group_name">Şablonlar</string>
<string name="decrypting_db">Məlumat bazası məzmunun şifrəsi açılır …</string>
<string name="digits">Rəqəmlər</string>
<string name="default_checkbox">Standart məlumat bazası olaraq istifədə et</string>
<string name="html_about_privacy">&lt;strong&gt;Heç bir istifadəçi məlumatı toplanmır&lt;/strong&gt;, bu tətbiq heç bir serverə bağlanmır, yalnız lokal olaraq işləyir və tamamilə istidəçilərin gizliliyinə hörmət edir.</string>
<string name="entry_accessed">Giriş edildi</string>
<string name="entry_cancel">Ləğv et</string>
<string name="entry_notes">Qeydlər</string>
<string name="entry_confpassword">Şifrəni təsdiq et</string>
<string name="entry_UUID">UUID (Qlobal Unikal İdentifikator)</string>
<string name="entry_history">Tarixçə</string>
<string name="entry_attachments">Qoşmalar</string>
<string name="entry_keyfile">Açar fayl</string>
<string name="hardware_key">Aparat-təchizat açarı</string>
<string name="entry_modified">Modifikasiya edilmiş</string>
<string name="searchable">Axtarıla bilən</string>
<string name="error_pass_match">Şifrələr uyğun deyil.</string>
<string name="error_string_key">Hər bir sıranın bir adı olmalıdır.</string>
<string name="error_label_exists">Bu etiket artıq mövcuddur.</string>
<string name="error_wrong_length">\"Uzunluq\" sahəsinə müsbət bir rəqəm yazın.</string>
<string name="error_autofill_enable_service">\"Avtomatik doldurma\" xidmətini aktiv etmək mümkün olmadı.</string>
<string name="error_move_group_here">Qrupu buraya köçürə bilməzsiniz.</string>
<string name="error_copy_group_here">Qrupu buraya nüsxələyə bilməzsiniz.</string>
<string name="error_create_database">Məlumat bazası yaratmaq mümkün deyil.</string>
<string name="error_create_database_file">Bu şifrə və açar faylı ilə məlumat bazası yaratmaq mümkün deyil.</string>
<string name="error_otp_counter">Sayğac %1$dvə%2$d aralığında olmalıdır.</string>
<string name="error_otp_period">Dövr %1$dvə%2$d saniyə aralığında olmalıdır.</string>
<string name="contribution">İanə</string>
<string name="feedback">Rəy</string>
<string name="about_description">Keepass şifrə menecerinin android tətbiqi</string>
<string name="accept">Qəbul et</string>
<string name="master_key">Ana şifrə</string>
<string name="security">Təhlükəsizlik</string>
<string name="encryption">Şifrələmə</string>
<string name="encryption_algorithm">Şifrələmə alqortiması</string>
<string name="clipboard_error">Bəzi cihazlar mübadilə buferindən istifadə etməyə icazə verməyəcək.</string>
<string name="clipboard_error_clear">Mübadilə buferi təmizlənmədi</string>
<string name="content_description_password_checkbox">Şifrə təsdiqi</string>
<string name="expired">Müddəti bitdi</string>
<string name="content_description_entry_foreground_color">Şifrənin ön plan rəngi</string>
<string name="content_description_entry_background_color">Şifrənin arxa plan rəngi</string>
<string name="validate">Doğrula</string>
<string name="discard">Ləğv et</string>
<string name="content_description_passphrase_word_count">Şifrədəki söz sayısı</string>
<string name="content_description_update_from_list">Yenilə</string>
<string name="content_description_remove_from_list">Sil</string>
<string name="html_about_contribution">&lt;strong&gt;Müstəqilliyimiz qorumaq&lt;/strong&gt;, &lt;strong&gt;xətaları düzəltmək&lt;/strong&gt;,&lt;strong&gt;yeni funskiyalar əlavə etmək&lt;/strong&gt;&lt;strong&gt;hər zaman aktiv olmaq&lt;/strong&gt;üçün&lt;strong&gt;sizin &lt;/strong&gt;dəstəyinizə etibar edirik.</string>
<string name="entry_created">Yaradıldı</string>
<string name="entry_expires">İstifadə müddəti biti</string>
<string name="tags">Etiketlər</string>
<string name="entry_password">Şifrə</string>
<string name="error_disallow_no_credentials">Ən azından bir ədəd şəxsiyyəti təyin edən məlumat təyin edilməlidir.</string>
<string name="error_pass_gen_type">Ən azından bir ədəd şifrə generatoru növü seçilməlidir.</string>
<string name="error_rounds_too_large">\"Transformasiya mərhələləri\" çox yüksəkdir. 2147483648-ə təyin edin.</string>
<string name="error_save_database">Malumat bazasını yadda saxlamaq mümkün olmadı.</string>
<string name="error_otp_secret_key">Məxfi söz Base32 formatında olmalıdır.</string>
<string name="error_challenge_already_requested">Doğrulama artıq istənilib</string>
<string name="error_response_already_provided">Artıq cavab verilib.</string>
<string name="error_location_unknown">Məlumat bazasının yeri məlum deyil, məlumat bazası funksiyası yerinə yetirilə bilməz.</string>
<string name="error_empty_key">Açar bölməsi boş saxlanıla bilməz.</string>
<string name="field_name">Sahə adı</string>
<string name="field_value">Sahə dəyəri</string>
<string name="file_not_found_content">Fayl tapılmadı. Onu fayl menecerində yenidən açmağı yoxlayın.</string>
<string name="corrupted_file">Zədələnmiş fayl.</string>
<string name="hint_conf_pass">Şifrəni təsdiq et</string>
<string name="hint_generated_password">Yaradılmış şifrə</string>
<string name="hint_group_name">Qrup adı</string>
<string name="hint_icon_name">İkona adı</string>
<string name="hint_keyfile">Açar faylı</string>
<string name="passphrase">Şifrəli cümlə</string>
<string name="error_driver_required">%1$s üçün drayver lazımdır.</string>
<string name="error_cancel_by_user">İstifadəçi tərəfindən ləğv edildi.</string>
<string name="hint_length">Uzunluq</string>
<string name="error_hardware_key_unsupported">Aparat-təchizat açarı dəstəklənmir.</string>
<string name="generate_password">Şifrə yarat</string>
<string name="password">Şifrə</string>
<string name="file_browser">Fayl meneceri</string>
<string name="hint_pass">Şifrə</string>
<string name="show_uuid_title">UUID-ni göstər</string>
<string name="show_uuid_summary">Şifrə və ya şifrə qrupuna bağlı UUID-ni göstər</string>
<string name="list_groups_show_number_entries_summary">Qrupdaki şifrələrin sayını göstər</string>
<string name="list_size_title">Listdəki faylların həcmi</string>
<string name="list_size_summary">Element listindəki mətnin ölçüsü</string>
<string name="creating_database">Məlumat bazası yaradılır …</string>
<string name="loading_database">Məlumat bazası yüklənir …</string>
<string name="lowercase">Kiçik hərf</string>
<string name="about">Haqqında</string>
<string name="menu_change_key_settings">Ana açarı dəyişdir</string>
<string name="copy_field">%1$s nüsxələndi</string>
<string name="menu_form_filling_settings">Forum doldurma</string>
<string name="menu_form_filling_settings_summary">Klaviatura, avtomatik douldurma, mübadilə buferi</string>
<string name="menu_advanced_unlock_settings">Cihaz kilidini aç</string>
<string name="menu_advanced_unlock_settings_summary">Biometrik, cihaz şəxsiyyətini təyin edən məlumatlar</string>
<string name="menu_security_settings_summary">Şifrələmə, açar yaratma funskiyası</string>
<string name="menu_master_key_settings">Ana açar parametrləri</string>
<string name="settings">Parametrlər</string>
<string name="menu_app_settings">Tətbiq parametrləri</string>
<string name="menu_app_settings_summary">Axtar, kilidlə, tarixçə, xüsusiyyətlər</string>
<string name="menu_database_settings">Məlumat bazası parametrləri</string>
<string name="menu_database_settings_summary">Meta məlumatlar, zibil qutusu, şablonlar, tarixçə</string>
<string name="menu_security_settings">Təhlükəsizlik parametrləri</string>
<string name="menu_paste">Mubadilə buferindən əlavə et</string>
<string name="menu_delete">Sil</string>
<string name="menu_cancel">Ləğv et</string>
<string name="menu_hide_password">Şifrəni gizlət</string>
<string name="menu_lock">Məlumat bazasını kilidlə</string>
<string name="menu_save_database">Məlumatları yadda saxla</string>
<string name="menu_merge_database">Məlumatları birləşdir</string>
<string name="menu_reload_database">Məlumatları yenidən yüklə</string>
<string name="menu_merge_from">... -dan birləşdir</string>
<string name="menu_save_copy_to">Bir nüsxəsini burada ... yadda saxla</string>
<string name="menu_open"></string>
<string name="menu_search">Axtar</string>
<string name="menu_showpass">Şifrəni göstər</string>
<string name="menu_donate">İanə et</string>
<string name="master_key_settings_summary">Dəyişiklik, yenilənmə</string>
<string name="menu_edit">Düzəliş et</string>
<string name="menu_copy">Nüsxələ</string>
<string name="menu_move">Köçür</string>
<string name="remember_hardware_key_title">Aparat-təchizat açarlarını xatırla</string>
<string name="remember_keyfile_locations_title">Açar faylın yerini xatırla</string>
<string name="remember_keyfile_locations_summary">Açar faylların saxlanıldığı yeri unutma</string>
<string name="show_recent_files_title">Ən son faylları göstər</string>
<string name="hide_broken_locations_title">Zədələnmiş məlumat bazası linklərini gizlət</string>
<string name="show_recent_files_summary">Ən son məlumat bazalarının yerini göstər</string>
<string name="export_app_properties_title">Tətbiqin parametrlərini ixrac et</string>
<string name="export_app_properties_summary">Tətbiqin parametrlərini ixrac etmək üçün bir fayl yaradın</string>
<string name="description_app_properties">Tətbiq parametrlərini idarə etmək üçün KeePassDX xüsusiyyətləri</string>
<string name="success_import_app_properties">Tətbiqin parametrləri idxal edildi</string>
<string name="success_export_app_properties">Tətbiqin parametrləri ixrac edildi</string>
<string name="encryption_explanation">Bütün malumatlar üçün istifadə olunan məlumat bazası şifrələmə alqoritması</string>
<string name="do_not_kill_app">Tətbiqi bağlamayın …</string>
<string name="space">Boşluq</string>
<string name="filter">Filter</string>
<string name="sort_ascending">Öncə ən aşağı</string>
<string name="sort_groups_before">Öncə qruplar</string>
<string name="sort_recycle_bin_bottom">Aşağıdakı zibil qutusu</string>
<string name="sort_db">Təbii sıralama</string>
<string name="sort_title">Başlıq</string>
<string name="sort_creation_time">Yaradılma</string>
<string name="sort_last_modify_time">Dəyişiklik</string>
<string name="search">Axtar</string>
<string name="underline">Altdan xətt</string>
<string name="uppercase">Böyük hərf</string>
<string name="warning">Xəbərdarlıq</string>
<string name="error_import_app_properties">Tətbiqin parametrlərinin idxalı zamanı xəta baş verdi</string>
<string name="error_export_app_properties">Tətbiqin parametrləri idxal edilən zaman xəta baş verdi</string>
<string name="root">Kök</string>
<string name="sort_menu">Çeşidlə</string>
<string name="sort_username">İstifadəçi adı</string>
<string name="sort_last_access_time">Giriş</string>
<string name="special">Özəl</string>
<string name="unsupported_db_version">Dəstəklənməyən məlumat bazas versiyası.</string>
<string name="merge_success">Birləşdirmə uğurla tamamlandı</string>
<string name="warning_copy_permission">Mübadilə buferi bildiriş funksiyası üçün bildiriş icazəsinə ehtiyyac var.</string>
<string name="later">Sonra</string>
<string name="ask">Soruş</string>
<string name="configure">Kofiqurasiya et</string>
<string name="keystore_not_accessible">Açar ehtiyyatı düzgün formada başladılmadı.</string>
<string name="advanced_unlock_prompt_store_credential_title">Cihaz kilidini açma linki</string>
<string name="database_history">Tarixçə</string>
<string name="advanced_unlock_scanning_error">Cihaz kilidini açma xətası: %1$s</string>
<string name="warning_database_info_reloaded">Məlumat bazasını yenidən yükləmək lokal olaraq modifikasiya olunmuş faylları siləcəkdir.</string>
<string name="warning_database_revoked">Fayla giriş fayl meneceri tərəfindən ləğv edildi, məlumat bazasını bağlayın və onu olduğu yerdən yenidən açın.</string>
<string name="warning_exact_alarm">Siz tətəbiqin zəngli saatdan istifadə etməsinə icazə verməmisiniz. Nəticədə, taymer tələb edən funksiyalar dəqiq bir zamanda işləməyəckdir.</string>
<string name="warning_keyfile_integrity">Android, məlumatlarını anında dəyişdirə biləcəyindən faylın heşi qaranti edilməyib. Doğru bütünlük üçün fayl əlavəsini .bin olaraq dəyişin.</string>
<string name="permission">İcazə</string>
<string name="version_label">Versiya %1$s</string>
<string name="build_label">Nüvə%1$s</string>
<string name="configure_biometric">Biometrik və ya cihaz şəxsiyyəti ilə doğrulama məlumatları tapılmadı.</string>
<string name="biometric_security_update_required">Biometrik təhlükəsizlik yenilənməsi lazımdır.</string>
<string name="unlock_and_link_biometric">Cihaz kilid açma linki</string>
<string name="advanced_unlock_prompt_extract_credential_title">Cihaz kilidini tanıma</string>
<string name="encrypted_value_stored">Şifrələnmiş şifrə ehtiyyata alındı</string>
<string name="advanced_unlock_not_recognized">Cihaz kilidini açmaq üçün barmaq izi tanınmadı</string>
<string name="unavailable">Mövcud deyil</string>
<string name="credential_before_click_advanced_unlock_button">Şifrəni yazın və sonra bu düyməyə basın.</string>
<string name="properties">Xüsusiyyətlər</string>
<string name="menu_appearance_settings">Görünüş</string>
<string name="menu_appearance_settings_summary">Tema, rəng və atributlar</string>
<string name="biometric">Biometriya</string>
<string name="device_credential">Cihazın şəxsiyyətini təsdiq edən məlumatları</string>
<string name="general">Ümumi</string>
<string name="autofill">Avtomatik doldurma</string>
<string name="autofill_service_name">KeePassDX avtomatik doldurma formu</string>
<string name="autofill_sign_in_prompt">KeePassDX ile giriş edin</string>
<string name="education_entry_new_field_title">Xüsusi bölmələr əlavə edin</string>
<string name="education_add_attachment_title">Qoşma əlavə edin</string>
<string name="advanced_unlock_explanation_summary">Məlumat bazasını daha asan açmaq üçün cihazın kilid açma funksiyasından istifadə edin</string>
<string name="device_credential_unlock_enable_summary">Məlumat bazasını açmaq üçün cihaz şəxsiyyət məlumatlarından istifadə etməyə imkan verir</string>
<string name="education_add_attachment_summary">Önəmli xarici məlumatları yadda saxlamaq üçün şifrənizə (qeyd) qoşma əlavə edin.</string>
<string name="temp_advanced_unlock_enable_title">Müvəqqəti kilid açma</string>
<string name="temp_advanced_unlock_timeout_title">Cihazın kilid açma müddəti bitdi</string>
<string name="unavailable_feature_version">Bu cihazda Andoird %1$s versiyası var, lakin %2$svə ya daha sonrakı versiya lazımdır.</string>
<string name="path">Yol</string>
<string name="unavailable_feature_hardware">Lazımi aparat-təchizat tapılmadı.</string>
<string name="max_history_size_title">Maksimum həcm</string>
<string name="templates_group_uuid_title">Şablonlar qrupu</string>
<string name="max_history_items_title">Maskimum sayı</string>
<string name="max_history_size_summary">Hər şifrəyə görə tarixçə həcmini limitlə</string>
<string name="settings_database_recommend_changing_master_key_summary">Ana açarın dəyişdirilməsini tövsiyə et (gün)</string>
<string name="settings_database_force_changing_master_key_title">Yeniləməyə məcbur et</string>
<string name="settings_database_force_changing_master_key_next_time_title">Bir sonrakı səfərə yeniləməyə məcbur et</string>
<string name="settings_database_force_changing_master_key_summary">Ana açarın dəyişdirilməsini tələb et (gün)</string>
<string name="settings_database_force_changing_master_key_next_time_summary">Bir sonrakı səfərə ana açarın dəyişdirilməsini tələb et (tək səfərlik)</string>
<string name="keyboard_notification_entry_summary">Şifrə mövcud olanda bildirişi göstər</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="keyboard_appearance_category">Görünüş</string>
<string name="keyboard_theme_title">Klaviatura teması</string>
<string name="keyboard_change">Klaviaturanı dəyişdir</string>
<string name="keyboard_keys_category">Açarlar</string>
<string name="keyboard_key_sound_title">Düyməyə toxunulduğunda səs çıxart</string>
<string name="education_unlock_summary">Məlumat bazanızın şifrəsini açmaq üçün şifrə və\\və ya açar faylı daxil edin.\n\nMəlumat bazası faylını hər dəfə dəyişəndən sonra etibarlı bir yerdə ehtiyat üçün nüsxələyin.</string>
<string name="biometric_unlock_enable_title">Biometrik kilid açma</string>
<string name="biometric_unlock_enable_summary">Məlumat bazasını açmaq üçün biometrikləri skan etməyə imkan verir</string>
<string name="device_credential_unlock_enable_title">Cihaz şəxsiyyət məlumatları ilə kilid açma</string>
<string name="biometric_auto_open_prompt_title">Avtomatik açma istəyi</string>
<string name="biometric_auto_open_prompt_summary">Məlumat bazası ondan istifadə ediləcək şəkildə quraşdırılıbsa, cihaz kilidini avtomatik olaraq tələb et</string>
<string name="temp_advanced_unlock_enable_summary">Cihaz kilidini açmaq üçün hər hansısa şifrələnmiş məzmunu saxlamayın</string>
<string name="biometric_delete_all_key_title">Şifrələnmiş açarları silin</string>
<string name="unavailable_feature_text">Bu funksiya işləmədi.</string>
<string name="file_name">Fayl adı</string>
<string name="assign_master_key">Ana açar təyin edin</string>
<string name="data">Məlumat</string>
<string name="database_data_compression_title">Məlumat sıxışdırma</string>
<string name="database_data_compression_summary">Məlumat sıxışdırma məlumat bazasının həcmini azaldır</string>
<string name="database_data_remove_unlinked_attachments_title">Əlaqəsiz məlumatları sil</string>
<string name="recycle_bin_title">Zibil qutusu istifadəsi</string>
<string name="recycle_bin_summary">Qrup və qeydləri (şifrə) silməzdən öncə \"Zibil qutusuna\" köçür</string>
<string name="recycle_bin_group_title">Zibil qutusu qrupu</string>
<string name="templates_group_enable_title">Şablonlardan istifadə</string>
<string name="templates_group_enable_summary">Şifrə məlumatlarındakı xanaları doldurmaq üçün dinamik şablonlardan istifadə edin</string>
<string name="settings_database_recommend_changing_master_key_title">Yeniləməyi tövsiyə et</string>
<string name="allow_copy_password_summary">Şifrələrin və qorunan məlumatların mübadilə buferinə nüsxələnməsinə icazə ver</string>
<string name="allow_copy_password_warning">Xəbərdarlıq: Mübadilə buferi bütün tətbiqlər tərəfindən istifadə olunur. Əgər həssas məlumatlar nüsxələnibsə, digər tətbiqlər onu bərpa edə bilər.</string>
<string name="enable">Aktiv et</string>
<string name="disable">Deaktiv et</string>
<string name="notification">Bildiriş</string>
<string name="clear_clipboard_notification_title">Tətbiqi bağlayarkən sil</string>
<string name="database_name_title">Məlumat bazasının adı</string>
<string name="database_description_title">Məlumat bazasının açıqlaması</string>
<string name="database_default_username_title">Standart (susmaya görə) istifadəçi adı</string>
<string name="database_custom_color_title">Xüsusi məlumat bazası rəngi</string>
<string name="database_version_title">Məlumat bazası versiyası</string>
<string name="text_appearance">Mətn</string>
<string name="application_appearance">İnterfeys</string>
<string name="other">Digər</string>
<string name="compression">Sıxışdırma</string>
<string name="compression_none">Heç biri</string>
<string name="compression_gzip">Gzip</string>
<string name="recycle_bin">Zibil qutusu</string>
<string name="templates">Şablonlar</string>
<string name="keyboard">Klaviatura</string>
<string name="magic_keyboard_title">Magikeyboard</string>
<string name="device_keyboard_setting_title">Cihaz klaviatura parametrləri</string>
<string name="keyboard_name">Magikeyboard</string>
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
<string name="keyboard_setting_label">Magikeyboard parametrləri</string>
<string name="keyboard_entry_category">Şifrə</string>
<string name="keyboard_selection_entry_title">Şifrə seçimi</string>
<string name="keyboard_notification_entry_title">Bildiriş məlumatı</string>
<string name="keyboard_save_search_info_title">Paylaşılan məlumatları yadda saxla</string>
<string name="keyboard_notification_entry_clear_close_title">Tətbiqi bağlayarkən təmizlə</string>
<string name="keyboard_notification_entry_clear_close_summary">Bildirişi bağlayarkən məlumat bazasını bağla</string>
<string name="keyboard_entry_timeout_title">Taymaut</string>
<string name="keyboard_notification_entry_content_title_text">Şifrə</string>
<string name="keyboard_notification_entry_content_title">%1$s Magikeyboard-da istifadə edilə bilər</string>
<string name="keyboard_key_vibrate_title">Düyməyə toxunulduğunda titrət</string>
<string name="education_setup_OTP_title">Birdəfəlik şifrə (OTP) təyin edin</string>
<string name="education_unlock_title">Məlaumat bazasının şifrəsini açın</string>
<string name="education_read_only_title">Məlumat bazasını dəyişiklik edilməsinə qarşı qoruyun</string>
<string name="education_field_copy_title">Bölməni (sahəni) nüsxələyin</string>
<string name="education_field_copy_summary">Nüsxələnmiş bölmələr (sahələr) istənilən yerə nüsxələnə bilər.\n\nÜntünlük verdiyiniz form doldurma metodunu seçin.</string>
<string name="education_lock_title">Məlumat bazasını kilidləyin</string>
<string name="html_text_donation">Azadlığımızı qorumaq və daima aktiv olmağınız üçün sizin &lt;strong&gt;yardımınıza güvənirik.&lt;/strong&gt;</string>
<string name="html_text_feature_generosity">Bu &lt;strong&gt;görünüş stili&lt;/strong&gt;sizin əliaçıqlığınız sayəsində mövuddur.</string>
<string name="html_text_dev_feature">Bu xüsusiyyət &lt;strong&gt;hazırlıq mərhələsindədir&lt;/strong&gt; və tezliklə &lt;strong&gt;istifadə verilməsi üçün sizin &lt;strong&gt;yardımınıza ehtiyyacı var.</string>
<string name="html_text_dev_feature_encourage">tərtibatçıları &lt;strong&gt;yeni funksiyalar əlavə etməyə&lt;/strong&gt;&lt;strong&gt;sizin rəylərinizə əsasən &lt;/strong&gt;xətaları düzəltməyə həvəsləndirirsiniz.</string>
<string name="contribute">Yardım et</string>
<string name="unit_kibibyte">KiB</string>
<string name="unit_mebibyte">MiB</string>
<string name="unit_gibibyte">GiB</string>
<string name="style_name_simple">Sadə</string>
<string name="save">Yadda saxla</string>
<string name="number">Nömrə</string>
<string name="card_verification_value">CVV</string>
<string name="personal_identification_number">PİN</string>
<string name="international_bank_account_number">İBAN</string>
<string name="standard">Standart</string>
<string name="warning_sure_add_file">Hər bir halda fayl əlavə edilsinmi?</string>
<string name="warning_remove_unlinked_attachment">Əlaqəsiz məlumatların silinməsi məlumat bazanızın həcmini azalda bilər, lakin KeePass modulları üçün olan məlumatları da silə bilər.</string>
<string name="warning_sure_remove_data">Hər bir halda bu məlumatlar silinsinmi?</string>
<string name="warning_empty_keyfile">Boş bir açar faylı əlavə etmək məsləhət görülmür.</string>
<string name="warning_empty_keyfile_explanation">Açar faylın məzmunu heç vaxt dəyişdirilə bilinməməlidir və ən yaxşı halda təsadüfi yaradılmış məlumatlardan ibarət olmalıdır.</string>
<string name="warning_database_info_changed">Məlumat bazası faylınızda olan informasiya tətbiq xaricində dəyişdirilib.</string>
<string name="warning_database_info_changed_options_read_only">Ən son dəyişikliklərlə məlumat bazasını yenidən yükləyin.</string>
<string name="warning_database_notification_permission">Bildiriş icazəsi, məlumat bazasının statusunu göstərməyə və onu əlçatan bir düymə ilə kilidləməyə imkan verir.\n\nƏgər icazəni aktivləşdirməsəniz arxa planda açıq olan məlumat bazası, ön planda başqa bir tətbiq varkən görünməyəcəkdir.</string>
<string name="warning_database_info_changed_options">Məlumatları birləşdirin, məlumat bazasını yadda saxlayaraq xarici dəyişikliklərin üzərinə yazın və ya ən son dəyişikliklər ilə onu yenidən yükləyin.</string>
<string name="clipboard">Mübadilə buferi</string>
<string name="clipboard_explanation_summary">Cihazınızın mübadilə buferindən istifadə edərək şifrə sahələrini (bölmələrini) nüsxələyin</string>
<string name="clipboard_notifications_title">Mübadilə buferi bildirişləri</string>
<string name="clipboard_notifications_summary">Şifrəni göstərərkən sahələri (bölmə) nüsxələmək üçün mübadilə buferi bildirişlərini göstər</string>
<string name="clipboard_warning">Əgər mübadilə buferinin avtomatik silinməsi uğursuz olarsa, onun tarixçəsini əllə silin.</string>
<string name="html_text_ad_free">Digər bir çox şifrə menecerlerindən fərqli olaraq, bu tətbiq &lt;strong&gt;reklamsız&lt;/strong&gt;,&lt;strong&gt;azad lisenziyaya sahibdir&lt;/strong&gt; və hansı versiyanı istifadə etdiyinizdən asılı olmayaraq, şəxsi məlumatlarınızı öz serverlərində toplamır.</string>
<string name="advanced_unlock_keystore_warning">Bu xüsusiyyət, şifrələnən şəxsiyyəti təsdiq edən məlumatları cihazın təhlükəsiz açar bazasında saxlayacaqdır.\n\nƏməliyyat sisteminin yerli APİ-nin tətbiqindən asılı olaraq, tam olaraq funksional olmaya bilər.\n\nCihazın istehsalçısı və istifadə etdiyiniz ROM-un tərtibatçısı ilə açar bazasının uyğunluğu və təhlükəsizliyini yoxlayın.</string>
<string name="autofill_inline_suggestions_title">Cümlə daxili təkliflər</string>
<string name="autofill_inline_suggestions_summary">Birbaşa uyğun olan klaviaturadan avtomatik doldurma təkliflərini göstərməyə çalış</string>
<string name="autofill_manual_selection_title">Əllə seçim</string>
<string name="autofill_manual_selection_summary">İstifadəçiyə məlumat bazası şifrəsini seçməyə imkan verən seçimi göstər</string>
<string name="autofill_save_search_info_title">Axtarış məlumatlarını yadda saxla</string>
<string name="autofill_inline_suggestions_keyboard">Avtomatik doldurma təklifləri əlavə edildi.</string>
<string name="allow_no_password_title">Ana açar olmamasına icazə ver</string>
<string name="enable_read_only_summary">Məlumat bazasını standart olaraq yazma-qorumalı (dəyişməz) aç</string>
<string name="enable_auto_save_database_title">Məlumat bazasını avtomatik olaraq yadda saxla</string>
<string name="reset_education_screens_summary">Bütün təlim məlumatlarını yenidən göstər</string>
<string name="reset_education_screens_text">Təlim ipuclarını sıfırlamaq</string>
<string name="education_new_node_title">Məlumat bazanıza məlumatlar (fayl) əlavə edin</string>
<string name="education_search_summary">Şifrələrinizi geri əldə etmək üçün başlıq, istifadəçi adı və ya digər sahələrin (bölmə) məzmununu daxil et.</string>
<string name="education_entry_edit_title">Şifrəyə düzəliş edin</string>
<string name="education_generate_password_summary">Şifrənizlə əlaqələndirmək üçün güclü bir şifrə yaradın, anketin kriteriyalarına görə onu asanlıqla müəyyənlşdirin və güvənli şifrəni unutmayın.</string>
<string name="education_generate_password_title">Güclü şifrə yaradın</string>
<string name="keyboard_previous_lock_title">Məlumat bazasını kilidlə</string>
<string name="file_manager_install_description">Məlumat bazası fayllarını yaratmaq, açmaq və yadda saxlamaq üçün ACTION_CREATE_DOCUMENT və ACTION_OPEN_DOCUMENT funksiyalarını həyata keçirə bilən bir fayl meneceri tələb olunur.</string>
<string name="content_description_node_children">Şəbəkə nöqtəsinin alt kateqoriyası</string>
<string name="content_description_add_node">Şəbəkə nöqtəsi əlavə edin</string>
<string name="content_description_repeat_toggle_password_visibility">Şifrənin görünüb-görünməməsinin dəyişdirilməsini təkrarlayın</string>
<string name="content_description_nav_header">Naviqasiya başlığı</string>
<string name="navigation_drawer_open">Naviqasiya panelini aç</string>
<string name="navigation_drawer_close">Naviqasiya panelini bağla</string>
<string name="entry_add_field">Sahə (bölmə) əlavə et</string>
<string name="content_description_remove_field">Sahəni (bölməni) sil</string>
<string name="content_description_keyboard_close_fields">Sahələri (bölmələri) bağla</string>
<string name="html_about_licence">KeePassDX©%1$dKunzisoft&lt;strong&gt;ıq mənbəlidir və&lt;/strong&gt;&lt;strong&gt;ondan heç bir reklam yoxdur&lt;/strong&gt;.\n&lt;strong&gt;GPLv3&lt;/strong&gt;lisenziyasına sahibdir, hər hansısa bir qarantiyası yoxdur.</string>
<string name="inherited">İdxal et</string>
<string name="auto_type">Avtomatik yazma</string>
<string name="auto_type_sequence">Avtomatik yazma sırası</string>
<string name="entry_not_found">Şifrə məlumatları tapılmadı.</string>
<string name="custom_data">Özəl məlumat</string>
<string name="entry_title">Başlıq</string>
<string name="entry_setup_otp">Tək səfərlik şifrə təyin et</string>
<string name="otp_type">OTP növü</string>
<string name="otp_secret">Sirr</string>
<string name="otp_period">Müddət (saniyə)</string>
<string name="otp_counter">Sayğac</string>
<string name="otp_digits">Rəqəmlər</string>
<string name="search_filters">Axtarış filterləri</string>
<string name="otp_algorithm">Alqoritma</string>
<string name="current_group">Hazırki qrup</string>
<string name="regex">Müntəzəm ifadə</string>
<string name="debit_credit_card">Debet / Kredit Kartı</string>
<string name="holder">Sahib</string>
<string name="id_card">Səxsiyyət Vəsiqəsi</string>
<string name="name">Ad</string>
<string name="place_of_issue">Verildiyi yer</string>
<string name="date_of_issue">Verildiyi tarix</string>
<string name="email">Elektron poçt</string>
<string name="email_address">Elektron poçt adresi</string>
<string name="wireless">Wi-Fi</string>
<string name="ssid">SSİD</string>
<string name="type">Növ</string>
<string name="cryptocurrency">Kripto valyuta pul kisəsi</string>
<string name="token">Jeton</string>
<string name="private_key">Şəxsi açar</string>
<string name="public_key">Ortaq açar</string>
<string name="seed">Başlanğıc</string>
<string name="account">Hesab</string>
<string name="bank">Bank</string>
<string name="bank_name">Bank adı</string>
<string name="bank_identifier_code">SWIFT / BIC</string>
<string name="secure_note">Təhlükəsizlik Qeydi</string>
<string name="membership">Üzvlük</string>
<string name="template">Şablon</string>
<string name="version">Versiya</string>
<string name="entry_otp">OTP</string>
<string name="entry_url">URL</string>
<string name="entry_user_name">İstifadəçi adı</string>
<string name="error_arc4">Arcfour axın şifrəsi dəstəklənmir.</string>
<string name="error_file_not_create">Faylı yaratmaq mümkün olmadə</string>
<string name="error_can_not_handle_uri">Bu URİ-nin KeePassDX-də istifadəsi mümkün olmadı.</string>
<string name="case_sensitive">Böyük/kiçik hərf həssaslığı</string>
<string name="error_invalid_db">Məlumat bazasını oxumaq mümkün olmadı.</string>
<string name="error_invalid_path">Fayl yolunun doğru olduğundan əmin olun.</string>
<string name="error_invalid_OTP">Etibarsız gizli OTP.</string>
<string name="error_no_name">Ad daxil edin.</string>
<string name="error_word_reserved">Bu söz rezerv edilib və istifadəsi mümkün deyil.</string>
<string name="error_nokeyfile">Açar faylı seçin.</string>
<string name="error_no_hardware_key">Aparat-təchizat açarı seçin.</string>
<string name="error_out_of_memory">Bütün məlumat bazanızı yükləyəcək qədər yaddaşda yer yoxdur.</string>
<string name="error_XML_malformed">XML xətalı formalaşıb.</string>
<string name="error_load_database">Məlumat bazasını yükləmək mümkün olmadı.</string>
<string name="error_load_database_KDF_memory">Açarı yükləmək mümkün olmadı. KDF \"Yaddaş İstifadəsini\" azaltmağa çalışın.</string>
<string name="error_move_entry_here">Bu şifrəni buraya köçürə bilməzsiniz.</string>
<string name="error_copy_entry_here">Bu şifrəni buraya nüsxələyə bilməzsiniz.</string>
<string name="error_otp_digits">Jeton %1$d ilə %2$d arası rəqəmlərdən ibarət olmalıdır.</string>
<string name="error_otp_type">Mövcud OTP növü bu form tərəfindən tanınmır, onun doğrulaması artıq düzgün şəkildə jeton yaratmaya bilər.</string>
<string name="error_string_type">Bu mətn istənilən məlumat (fayl) ilə uyğunlaşmır.</string>
<string name="error_registration_read_only">Dəyişməz (yalnız oxuna bilən) məlumat bazasında yeni bir məlumatın yadda saxlanılmasına icazə verilmir</string>
<string name="error_field_name_already_exists">Sahə (bölmə) adı artıq mövcuddur.</string>
<string name="error_database_uri_null">Mləlumat bazası URİ-sini geri qaytarmaq olmur.</string>
<string name="error_rebuild_list">Listi düzgün şəkildə yenidən hazırlamaq mümkün deyil.</string>
<string name="error_file_to_big">Qarşıya yükləməyə çalışdığınız faylın həcmi çox böyükdür.</string>
<string name="error_duplicate_file">Fayl məlumatları artıq mövcuddur.</string>
<string name="error_upload_file">Fayl məlumatları qarşıya yüklənərkən xəta baş verdi.</string>
<string name="error_remove_file">Fayl məlumatlarını silərkən xəta baş verdi.</string>
<string name="error_start_database_action">Məlumat bazasında prosses həyata keçirilərkən xəta baş verdi.</string>
<string name="error_no_response_from_challenge">Doğrulama istəyindən cavab almaq mümkün deyil.</string>
<string name="error_unable_merge_database_kdb">kdb məlumat bazası faylı ilə birləşdirmə etmək mümkün deyil</string>
<string name="invalid_credentials">Şəxsiyyəti təsdiq edən məlumatları oxumaq mümkün olmadı.</string>
<string name="invalid_algorithm">Yanlış alqoritma.</string>
<string name="invalid_db_same_uuid">%1$s eyni UUİD dəyərinə sahib %2$s artıq mövcuddur.</string>
<string name="invalid_db_sig">Məlumat bazasının formatını tanımaq mümkün olmadı.</string>
<string name="keyfile_is_empty">Açar faylı boşdur.</string>
<string name="length">Uzunluq</string>
<string name="hide_password_title">Şifrələri gizlət</string>
<string name="hide_password_summary">Şifrələri standart olaraq (***) ilə maskala</string>
<string name="colorize_password_title">Şifrələri rəngləndir</string>
<string name="colorize_password_summary">Şifrə hərflərini (simvollarını) növə görə rəngləndir</string>
<string name="list_entries_show_username_title">İstifadəçi adlarını göstər</string>
<string name="list_entries_show_username_summary">Şifrə siyahılarında olan istifadəçi adlarını göstər</string>
<string name="list_groups_show_number_entries_title">Şifrələrin sayını göstər</string>
<string name="show_otp_token_title">OTP Jetononu göstər</string>
<string name="show_otp_token_summary">Şifrələrin siyahısında OTP jetonlarını göstər</string>
<string name="menu_keystore_remove_key">Cihaz kilid açma açarını sil</string>
<string name="menu_url">URL-ni aç</string>
<string name="menu_file_selection_read_only">Yazma qoruması</string>
<string name="menu_open_file_read_and_write">Modifikasiya edilə bilən</string>
<string name="menu_empty_recycle_bin">Zibil qutusunu boşalt</string>
<string name="menu_restore_entry_history">Tarixçəni bərpa et</string>
<string name="menu_delete_entry_history">Tarixçəni sil</string>
<string name="menu_external_icon">Xarici ikona</string>
<string name="minus">Mənfi</string>
<string name="never">Heç vaxt</string>
<string name="no_results">Axtarılan nəticə tapılmadı</string>
<string name="no_url_handler">Bu URL-ni açmaq üçün bir veb brauzer quraşdır.</string>
<string name="select_database_file">Mövcud kassanı</string>
<string name="create_keepass_file">Yeni kassa yarat</string>
<string name="auto_focus_search_title">Sürətli axtarış</string>
<string name="auto_focus_search_summary">Məlumat bazasını açarkən axtarış tələb et</string>
<string name="subdomain_search_title">Alt domendə axtarış</string>
<string name="subdomain_search_summary">Veb domenləri, alt domen məhdudiyyətləri ilə arxtarın</string>
<string name="progress_create">Yeni məlumat bazası yaradılır …</string>
<string name="progress_title">İşləyir …</string>
<string name="protection">Qoruma</string>
<string name="read_only">Yazma qorumalı</string>
<string name="read_only_warning">Fayl menecerinizdən asılı olaraq, KeePassDX cihazınızın yaddaşına yazmasına icazə verilməyə bilər.</string>
<string name="contains_duplicate_uuid">Məluamt bazasında təkrarlanan UUİD-lər mövcuddur.</string>
<string name="contains_duplicate_uuid_procedure">Təkrarlananlar üçün yeni UUİD-lər yaradaraq problemi həll edib davam et istəyirsinizmi?</string>
<string name="search_mode">Axtarış modu</string>
<string name="save_mode">Yadda saxlama modu</string>
<string name="selection_mode">Seçim modu</string>
<string name="registration_mode">Qeydiyyat modu</string>
<string name="remember_database_locations_title">Məlumat bazalarının yerlərini xatırlayın</string>
<string name="remember_database_locations_summary">Məlumat bazalarının harada saxlanıldığını izlə</string>
<string name="remember_hardware_key_summary">Aparat-təchizat açarlarının harada istifadə olunduğunu izlə</string>
<string name="hide_broken_locations_summary">Son məlumat bazaları siyahısındakı yararsız linkləri gizlət</string>
<string name="import_app_properties_title">Tətbiq parametrlərini idxal et</string>
<string name="import_app_properties_summary">Tətbiq parametrlərini idxal etmək üçün fayl seçin</string>
<string name="rounds">Transformasiya turları</string>
<string name="rounds_explanation">Əlavə şifrələmə turları, brute force hücumlarına qarşı yüksək qoruma təmin edər, lakin yükləmə və yadda saxlama prossesini ciddi şəkildə yavaşladır.</string>
<string name="memory_usage">Yaddaş istifadəsi</string>
<string name="memory_usage_explanation">Açar yaratma funksiyası tərəfindən istifadə ediləcək yaddaşın miqdarı.</string>
<string name="parallelism">Paralellik</string>
<string name="kdf_explanation">Şifrələmə alqoritmasının açarını hazırlamaq üçün ana açar, təsadüfi açar yaratma funksiyasından istifadə edilərək çevrilir.</string>
<string name="parallelism_explanation">Açar yaratma funksiyası tərəfindən istifadə edilən paralellik dərəcəsi (yəni thread-lərin sayı).</string>
<string name="saving_database">Məlumat bazası yadda saxlanılır …</string>
<string name="command_execution">Əmr yerinə yetirilir …</string>
<string name="warning_no_encryption_key">Şifrələmə açarı olmadan davam edilsinmi?</string>
<string name="warning_permanently_delete_nodes">Seçilmiş şəbəkə nöqtələri qalıcı olaraq silinsinmi?</string>
<string name="warning_empty_recycle_bin">Zibil qutusundakı bütün şəbəkə nöqtələri qalıcı olaraq silinsinmi?</string>
<string name="warning_file_too_big">KeePassDX məlumat bazası sadəcə kiçik köməkçi faylları (PGP açar faylları kimi) ehtiva edə bilər.\n\nMəlumat bazanızın bu yükləməylə həcmi çox arta və performansı aşağı düşə bilər.</string>
<string name="warning_replace_file">Bu faylın yüklənməsi mövcud olanı əvəzləyəcəkdir.</string>
<string name="warning_password_encoding">Məlumat bazası faylındakı mətn kodlama formatından xaric şifrə hərflərindən (simvol) istifadə etməkdən yayının (tanınmayan hərflər (simvollar) eyni hərfə çevrilir).</string>
<string name="warning_database_read_only">Məlumat bazasındakı dəyişiklikləri yadda saxlamaq üçün faylların yazılmasına icazə verin</string>
<string name="warning_database_link_revoked">Fayla giriş icazəsi fayl meneceri tərəfindən rədd edildi</string>
<string name="warning_database_already_opened">Məlumat bazası artıq açıqdır, yenisi açmaq üçün öncə onu bağlayın</string>
<string name="warning_empty_password">Şifrə qoruması olmadan davam edilsinmi?</string>
<string name="advanced_unlock_prompt_store_credential_message">Cihazın kilid açma funksiyasından istifadə etsəniz belə, kassanın əsas şəxsiyyət təyin etmə məlumatlarını yenə də xatırlamaq lazımdır.</string>
<string name="advanced_unlock_prompt_extract_credential_message">Cihazın kilid açma funksiyası ilə məlumat bazasının şəxsiyyətini tədiq edən məlumatlarını əldə edin</string>
<string name="advanced_unlock_invalid_key">Cihazın kilid açma açarı oxunmadı. Zəhmət olmazsa, onu silin və kilid açma prossesini təkrarlayın.</string>
<string name="advanced_unlock_prompt_not_initialized">Cihaz kilid açma istəyini başlatmaq mümkün deyil.</string>
<string name="autofill_explanation_summary">Digər tətbiqlərdə formları (anket) daha sürətli doldurmaq üçün avtomatik doldurma funksiyasını aktiv edin</string>
<string name="autofill_select_entry">Şifrə seç .…</string>
<string name="set_autofill_service_title">Standart avtomatik doldurma xidmətini təyin edin</string>
<string name="autofill_preference_title">Avtomatik doldurmanın parametrləri</string>
<string name="password_size_title">Yaradılan şifrə həcmi</string>
<string name="password_size_summary">Yaradılan şifrələrin standart həcmini təyin edər</string>
<string name="list_password_generator_options_title">Şifrə hərfləri (simvolları)</string>
<string name="list_password_generator_options_summary">İcazə verilən şifrə yaratma hərflərini (simvollarını) təyin et</string>
<string name="database_opened">Məlumat bazasııldı</string>
<string name="lock">Kilid</string>
<string name="lock_database_screen_off_title">Ekran kilidi</string>
<string name="lock_database_screen_off_summary">Ekran söndükdən bir neçə saniyə sonra məlumat bazasının kilidləyin</string>
<string name="lock_database_back_root_title">Kilidləmək üçün \"Geri\" düyməsinə sıxın</string>
<string name="lock_database_back_root_summary">İstifadəçi kök ekranında geri düyməsinə klik etdikdə məlumat bazasını kilidlə</string>
<string name="lock_database_show_button_title">Kilid düyməsini göstərin</string>
<string name="lock_database_show_button_summary">İstifadəçi interfeysində kilid düyməsini göstərin</string>
<string name="content">Məzmun</string>
<string name="unlock">Kilidi aç</string>
<string name="advanced_unlock">Cihaz kilidini aç</string>
<string name="advanced_unlock_tap_delete">Cihaz kilid açma açarlarını silmək üçün toxunun</string>
<string name="temp_advanced_unlock_timeout_summary">Məzmununu silmədən öncə cihazın kilidini açma istifadə müddəti</string>
<string name="advanced_unlock_timeout">Cihaz kilidi açma taymout müddəti</string>
<string name="biometric_delete_all_key_summary">Cihaz kilid açma tanıması ilə bağlı bütün şifrəli açarları silin</string>
<string name="advanced_unlock_delete_all_key_warning">Cihaz kilid açma tanıması ilə bağlı bütün şifrəli açarlar silinsinmi?</string>
<string name="database_data_remove_unlinked_attachments_summary">Məlumat bazasında olan, lakin şifrəyə bağlı olmayan qoşmaları silin</string>
<string name="max_history_items_summary">Hər şifrə başına düşən keçmiş məlumatların (fayl) sayını limitləyin</string>
<string name="monospace_font_fields_enable_title">Sahə (bölmə) yazı tipi</string>
<string name="monospace_font_fields_enable_summary">Hərflərin (simvol) daha yaxşı görünməsi üçün sahələrdə (bölmə) istifadə olunan fontu dəyişdirin</string>
<string name="allow_copy_password_title">Mübadilə buferi güvəni</string>
<string name="clear_clipboard_notification_summary">Mübadilə buferinin istifadə müddəti bitdikdə və ya istifadə etməyə başladıqdan sonra bildiriş bağlandığında məlumat bazasını kilidləyin</string>
<string name="magic_keyboard_explanation_summary">Şifrə və bütün şəxsiyyət məlumatlarının daxil olduğu özəl klaviaturanı aktivləşdirin</string>
<string name="keyboard_selection_entry_summary">KeePassDX-də bir şifrəyə baxarkən, Magikeyboard-da həmin şifrəni göstər</string>
<string name="keyboard_save_search_info_summary">Gələcəkdə daha asan istifadələr üçün əl ilə şifrə seçimi edərkən paylaşılan məlumatları yadda saxlamağa çalışın</string>
<string name="keyboard_entry_timeout_summary">Klaviatura şifrəsini təmizləmək üçün taym-aut</string>
<string name="keyboard_auto_go_action_title">Avtomatik düymə funksiyası (hərəkəti)</string>
<string name="keyboard_auto_go_action_summary">\"Sahə\" düyməsinə basdıqdan sonra \"Get\" düyməsi funksiyası (hərəkəti)</string>
<string name="keyboard_previous_database_credentials_title">Məlumat bazasının şəxsiyyətini təsdiq edən məlumatların ekranı</string>
<string name="select_entry">Şifrə seç</string>
<string name="backspace">Backspace (geri silmə)</string>
<string name="enter">Enter (daxil et)</string>
<string name="autofill_close_database_title">Məlumat bazasını bağla</string>
<string name="autofill_close_database_summary">Avtomatik doldurma seçimindən sonra məlumat bazasını bağla</string>
<string name="autofill_save_search_info_summary">Gələcəkdə daha asan istifadələr üçün əllə şifrə seçimi edərkən axtarış məlumatlarını yadda saxlamağa çalış</string>
<string name="autofill_ask_to_save_data_title">Məlumatları yadda saxlamaq üçün sorğula</string>
<string name="autofill_ask_to_save_data_summary">Anket doldurma prossesi tamamlandığında məlumatları yadda saxlamaq üçün sorğula</string>
<string name="autofill_application_id_blocklist_title">Tətbiqin bloklama siyahısı</string>
<string name="autofill_application_id_blocklist_summary">Tətbiqlərin avtomatik olaraq doldurulmasını əngəlləyən bloklama siyahısı</string>
<string name="autofill_web_domain_blocklist_title">Veb domen bloklama siyahısı</string>
<string name="autofill_web_domain_blocklist_summary">Veb domenlərin avtomatik olaraq doldurulmasını əngəlləyən bloklama siyahısı</string>
<string name="autofill_block">Avtomatik doldurmanı blokla</string>
<string name="autofill_block_restart">Bloklamanı aktiv etmək üçün anketin daxil olduğu tətbiqi yenidən başladın.</string>
<string name="autofill_read_only_save">Yazma-qorumalı (dəyişməz) olaraq açılan məlumat bazasında yeni məlumatları yadda saxlamağa icazə verilmir.</string>
<string name="allow_no_password_summary">Əgər şəxsiyyəti təsdiq edən məlumatlar seçilməyibsə, \"Aç\" düyməsinin sıxılmasına icazə ver</string>
<string name="delete_entered_password_title">Şifrəni sil</string>
<string name="delete_entered_password_summary">Məlumat bazasına bağlantı cəhdindən sonra daxil edilmiş şifrəni sil</string>
<string name="enable_read_only_title">Yazma qorumalı</string>
<string name="enable_auto_save_database_summary">Hər önəmli prossesdən sonra məlumat bazasını yadda saxla (\"Modifikasiya edilə bilən\" modda keçərlidir)</string>
<string name="enable_keep_screen_on_title">Ekranııq saxla</string>
<string name="enable_keep_screen_on_summary">Şifrəyə baxarkən və ya redaktə edərkən ekranııq saxla</string>
<string name="keyboard_previous_database_credentials_summary">Məlumat bazası şəxsiyyətini təsdiq edən məlumatlar ekranında avtomatik olaraq əvvəlki klaviaturaya geri dön</string>
<string name="keyboard_previous_search_title">Axtarış ekranı</string>
<string name="keyboard_previous_search_summary">Axtarış ekranında avtomatik olaraq əvvəlki klaviaturaya geri dön</string>
<string name="keyboard_previous_fill_in_title">Geri dön</string>
<string name="keyboard_previous_fill_in_summary">\"Avtomatik funksiya düyməsi\" prossesi həyata keçirildikdən sonra avtomatik olaraq əvvəlki klaviaturaya geri dön</string>
<string name="education_validate_entry_title">Şifrəni doğrula</string>
<string name="education_validate_entry_summary">Şifrəni doğrulamağı və məlumat bazasını yadda saxlamağı unutmayın.\n\nƏgər avtomatik kilidləmə aktivləşərsə və dəyişiklik etdiyinizi unutsanız, məlumatlarınızı itirmə riskiniz olar.</string>
<string name="education_entry_new_field_summary">Əlavə bir sahəni (bölmə) qeydiyyata alın, bir dəyər əlavə edin və istəyə bağlı olaraq onu qoruyun.</string>
<string name="education_setup_OTP_summary">İki faktorlu doğrulama (2FA) üçün tələb olunan jetonu yaratmaq üçün bir dəfəlik şifrə menecerini (HOTP / TOTP) təyin edin.</string>
<string name="education_read_only_summary">Sessiya üçün açılış modunu dəyişin.\n\n\"Yazma qoruması\" funksiyası, məlumat bazasına istənilməyən dəyişikliklərin qarşısını alır.\n\"Modifikasiya edilə bilmə\" funksiyası, istədiyiniz kimi bütün elementləri əlavə etməyinizə, silmənizə və ya dəyişdirməyinizə icazə verir.</string>
<string name="education_lock_summary">Məlumat bazanızı cəld şəkildə kilidləyin, müəyyən müddət sonra və ekran söndükdə tətbiqin onu kilidləməsi üçün təyinatlandıra bilərsiniz.</string>
<string name="enable_screenshot_mode_title">Ekran görüntüsü modu</string>
<string name="enable_screenshot_mode_summary">Üçüncü tərəf tətbiqlərə bu tətbiqdə ekran görüntüsü qeyd etməyə və almağa icazə ver</string>
<string name="enable_education_screens_title">Təlim ipucları</string>
<string name="enable_education_screens_summary">Tətbiqin necə işlədiyini öyrənmək üçün elementləri önə çıxarın</string>
<string name="reset_education_screens_title">Təlim ipuclarını sıfırla</string>
<string name="education_create_database_title">Məlumat bazası faylınızı yaradın</string>
<string name="education_create_database_summary">İlk şifrə meneceri faylınızı yaradın.</string>
<string name="education_select_database_title">Mövcud məlumat bazasınıın</string>
<string name="education_select_database_summary">İstifadəyə davam etmək üçün fayl brauzerinizdən əvvəlki məlumat bazası faylınıın.</string>
<string name="education_new_node_summary">Şifrələr rəqəmsal şəxsiyyəti təsdiq edən məlumatları idarə etməyinizə kömək edir.\n\nQruplar (~qovluqlar) məlumat bazasındakı şifrələri düzəltdir.</string>
<string name="education_search_title">Şifrələrdə axtarış edin</string>
<string name="education_advanced_unlock_title">Cihaz maəlumat bazası kilidini açma</string>
<string name="education_advanced_unlock_summary">Məlumat bazanızı daha sürətli açmaq üçün şifrənizi skan edilmiş biometriya və ya cihaz şəxsiyyəti təsdiq edən məlumatlarla əlaqələndirin.</string>
<string name="education_entry_edit_summary">Şifrəyə özəl sahələrlə (bölmə) düzəliş edin. Ümumi məlumatlara müxtəlif şifrə sahələri arasında istinad edilə bilər.</string>
<string name="education_sort_title">Məlumatları (fayl) sıralayın</string>
<string name="education_sort_summary">Şifrə və qrupların necə sıralandığını seçin.</string>
<string name="education_donation_title">İştirak et</string>
<string name="education_donation_summary">Stabilliyin, təhlükəsizliyin artırılmasına və daha çox funksiyaların əlavə edilməsinə yardım edin.</string>
<string name="html_text_buy_pro">Pro versiyasını alaraq, bu &lt;strong&gt;görünüş stilindən&lt;/strong&gt;istifadə edə və xüsusilə &lt;strong&gt;ictimai layihələrinin həyata keçirilməsinə yardım etmiş olacaqsınız.&lt;/strong&gt;</string>
<string name="html_text_dev_feature_buy_pro">&lt;strong&gt;Pro&lt;/strong&gt;versiyasını alaraq,</string>
<string name="html_text_dev_feature_contibute">&lt;strong&gt;Yardım göstərərək&lt;/strong&gt;,</string>
<string name="html_text_dev_feature_thanks">Yardım etdiyiniz üçün çox sağ olun.</string>
<string name="html_text_dev_feature_work_hard">Bu funksiyası tezliklə yayımlamaq üçün çox çaıırıq.</string>
<string name="html_text_dev_feature_upgrade">Yeni versiyaları quraşdıraraq tətbiqi yeni saxlamağı unutmayın.</string>
<string name="download">Yüklə</string>
<string name="download_attachment">Yüklə%1$s</string>
<string name="upload_attachment">%1$sYüklə</string>
<string name="download_initialization">Başladılır …</string>
<string name="download_progression">Davam edir:%1$d%%</string>
<string name="download_finalization">Yekunlaşdırılır…</string>
<string name="download_complete">Bitdi!</string>
<string name="download_canceled">Ləğv edildi!</string>
<string name="unit_byte">B</string>
<string name="entropy">Entropiya:%1$s bit</string>
<string name="entropy_high">Entropiya: Yüksək</string>
<string name="entropy_calculate">Entropiya: Hesabla …</string>
<string name="at_least_one_char">Hər birindən ən az bir hərf (simvol)</string>
<string name="exclude_ambiguous_chars">Qeyri-müəyyən hərfləri (simvolları) istisna et</string>
<string name="consider_chars_filter">Hərfləri (simvolları) nəzərə al</string>
<string name="word_separator">Ayırıcı</string>
<string name="ignore_chars_filter">Hərfləri (simvolları) nəzərə alma</string>
<string name="lower_case">kiçik hərf</string>
<string name="upper_case">BÖYÜK HƏRF</string>
<string name="title_case">İlk hərflər böyük</string>
<string name="character_count">Hərf (simvol) sayı:%1$d</string>
<string name="screenshot_mode_banner_text">Ekran görüntüsü modu</string>
<string name="style_choose_title">Tətbiq teması</string>
<string name="style_choose_summary">Tətbiqdə istifadə olunan tema</string>
<string name="style_name_forest">Meşə</string>
<string name="style_name_divine">Müqəddəs</string>
<string name="style_name_classic">Klassik</string>
<string name="style_name_moon">Ay</string>
<string name="style_name_sun">Günəş</string>
<string name="style_name_reply">Cavab ver</string>
<string name="style_name_kunzite">Kunzit</string>
<string name="style_name_follow_system">Sistemi izle</string>
<string name="style_brightness_title">Tema parlaqlığı</string>
<string name="style_brightness_summary">ıq və ya tünd temaları seç</string>
<string name="style_name_light">ıq</string>
<string name="style_name_dark">Tünd</string>
<string name="icon_section_standard">Standart</string>
<string name="icon_section_custom">Özəl</string>
<string name="icon_pack_choose_title">İkona paketi</string>
<string name="icon_pack_choose_summary">Tətbiqdə istifadı edilən ikona paketi</string>
<string name="show_entry_colors_title">Şifrə rəngləri</string>
<string name="show_entry_colors_summary">Şifrələr üçün ön və arxa plan rənglərini göstərir</string>
<string name="hide_expired_entries_title">İstifadə müddəti bitən, istifadə olunmayan şifrələri gizlət</string>
<string name="hide_expired_entries_summary">İstifadə müddəti bitən şifrələr göstərilmir</string>
<string name="keyboard_previous_lock_summary">Məlumat bazasını kilidlədikdən sonra avtomatik olaraq əvvəlki klaviaturaya geri dön</string>
<string name="custom_fields">Özəl sahələr (bölmə)</string>
<string name="back_to_previous_keyboard">Əvvəlki klaviaturaya geri dön</string>
</resources>

View File

@@ -27,7 +27,7 @@
<string name="menu_showpass">Prikaži lozinku</string>
<string name="menu_search">Traži</string>
<string name="menu_open">Otvori</string>
<string name="menu_save_database">Sačuvaj bazu podataka</string>
<string name="menu_save_database">Sačuvaj podatake</string>
<string name="menu_lock">Zaključaj bazu podataka</string>
<string name="menu_hide_password">Sakrij lozinku</string>
<string name="menu_cancel">Otkaži</string>
@@ -224,12 +224,12 @@
<string name="html_about_contribution">Kako bismo &lt;strong&gt;zadržali našu slobodu&lt;/strong&gt;, &lt;strong&gt;ispravljali greške&lt;/strong&gt;, &lt;strong&gt;dodavali nove opcije&lt;/strong&gt; i &lt;strong&gt;uvek bili aktivni&lt;/strong&gt;, računamo na Vaš &lt;strong&gt;doprinos&lt;/strong&gt;.</string>
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft je &lt;strong&gt;otvorenog koda&lt;/strong&gt; i &lt;strong&gt;ne sadrži reklame&lt;/strong&gt;.
\nPonuđen je onakav kakav jeste, pod &lt;strong&gt;GPLv3&lt;/strong&gt; licencom, bez ikakvih garancija.</string>
<string name="digits">Cifre</string>
<string name="digits">Znamenke</string>
<string name="default_checkbox">Koristi kao podrazumevanu bazu podataka</string>
<string name="decrypting_db">Dešifrovanje sadržaja baze podataka…</string>
<string name="database">Baza podataka</string>
<string name="retrieving_db_key">Dohvatanje ključa baze podataka…</string>
<string name="select_to_copy">Izabarite kako bi ste kopirali %1$s u međuspremnik</string>
<string name="select_to_copy">Izaberite kako bi ste kopirali %1$s u međuspremnik</string>
<string name="content_description_keyboard_close_fields">Zatvori polja</string>
<string name="content_description_remove_from_list">Obriši</string>
<string name="content_description_update_from_list">Ažuriraj</string>
@@ -256,10 +256,161 @@
<string name="clipboard_timeout">Vreme isteka međuspremnika</string>
<string name="clipboard_error_clear">Nije moguće očistiti međuspremnik</string>
<string name="clipboard_error">Neki uređaji neće dozvoliti aplikacijama da koriste međuspremnik.</string>
<string name="clipboard_cleared">Međuspremnik je očišćena</string>
<string name="clipboard_cleared">Međuspremnik je očišćen</string>
<string name="clipboard_error_title">Greška međuspremnika</string>
<string name="allow">Dozvoli</string>
<string name="edit_entry">Izmeni stavku</string>
<string name="add_entry">Dodaj stavku</string>
<string name="contact">Kontakt</string>
<string name="biometric_security_update_required">Neophodno je ažurirati biometriju.</string>
<string name="configure">Podesi</string>
<string name="content_description_passphrase_word_count">Broj reči pristupne fraze</string>
<string name="passphrase">Dugačka lozinka</string>
<string name="filter">Filtar</string>
<string name="content_description_hardware_key_checkbox">Polje za potvrdu hardverskog ključa</string>
<string name="content_description_entry_background_color">Boja pozadine unosa</string>
<string name="name">Ime</string>
<string name="error_rebuild_list">Nije moguće pravilno obnoviti listu.</string>
<string name="auto_focus_search_title">Brza pretraga</string>
<string name="protection">Zaštita</string>
<string name="import_app_properties_summary">Izaberite datoteku za uvoz podešavanja aplikacije</string>
<string name="rounds">Transformacioni krugovi</string>
<string name="content_description_database_color">Boja baze podataka</string>
<string name="content_description_entry_foreground_color">Ulazna boja prednjeg plana</string>
<string name="debit_credit_card">Debitna/kreditna kartica</string>
<string name="place_of_issue">Mjesto izdavanja</string>
<string name="date_of_issue">Datum izdavanja</string>
<string name="email">Email</string>
<string name="email_address">Adresa e-pošte</string>
<string name="type">Vrsta</string>
<string name="cryptocurrency">Novčanik za kriptovalute</string>
<string name="token">Token</string>
<string name="public_key">Javni ključ</string>
<string name="private_key">Privatni ključ</string>
<string name="seed">Tajna fraza</string>
<string name="account">Račun</string>
<string name="bank_identifier_code">SVIFT / BIC</string>
<string name="membership">Članstvo</string>
<string name="error_otp_type">Ovaj obrazac ne prepoznaje postojeći tip OTP-a, njegova validacija možda više neće ispravno generisati token.</string>
<string name="error_start_database_action">Došlo je do greške pri izvođenju radnje u bazi podataka.</string>
<string name="menu_reload_database">Поново учитај податке</string>
<string name="no_url_handler">Instalirajte veb pregledač da biste otvorili ovu URL adresu.</string>
<string name="select_database_file">Otvorite postojeći trezor</string>
<string name="remember_database_locations_summary">Prati gde se čuvaju baze podataka</string>
<string name="hide_broken_locations_summary">Sakrijte pokvarene veze na listi nedavnih baza podataka</string>
<string name="content_description_otp_information">Informacije o jednokratnoj lozinci</string>
<string name="error_upload_file">Došlo je do greške pri otpremanju podataka datoteke.</string>
<string name="hint_icon_name">Ime ikone</string>
<string name="no_results">Nema rezultata pretrage</string>
<string name="memory_usage">Korišćenje memorije</string>
<string name="show_recent_files_title">Prikaži nedavne datoteke</string>
<string name="show_uuid_title">Prikaži UUID</string>
<string name="html_about_privacy">&lt;strong&gt;Ne preuzimaju se nikakvi korisnički podaci&lt;/strong&gt;, ova aplikacija se ne povezuje ni na jedan server, radi samo lokalno i u potpunosti poštuje privatnost korisnika.</string>
<string name="expired">Isteklo</string>
<string name="hardware_key">Hardverski ključ</string>
<string name="bank">Banka</string>
<string name="bank_name">Ime banke</string>
<string name="version">Verzija</string>
<string name="error_remove_file">Došlo je do greške pri uklanjanju podataka iz datoteke.</string>
<string name="error_challenge_already_requested">Izazov je već zahtevan</string>
<string name="error_hardware_key_unsupported">Hardverski ključ nije podržan.</string>
<string name="error_empty_key">Ključ ne može biti prazan.</string>
<string name="colorize_password_summary">Obojite znakove lozinke po tipu</string>
<string name="show_otp_token_title">Prikaži OTP token</string>
<string name="show_uuid_summary">Prikazuje UUID povezan sa unosom ili grupom</string>
<string name="menu_merge_from">Sjedini iz …</string>
<string name="progress_title">Rad u toku …</string>
<string name="export_app_properties_summary">Napravite datoteku za izvoz podešavanja aplikacije</string>
<string name="success_export_app_properties">Podešavanja aplikacije su izvezena</string>
<string name="root">Koren</string>
<string name="rounds_explanation">Dodatne runde šifrovanja pružaju veću zaštitu od napada grube sile, ali zaista mogu usporiti učitavanje i čuvanje.</string>
<string name="memory_usage_explanation">Količina memorije koju će koristiti funkcija izvođenja ključa.</string>
<string name="space">Razmak</string>
<string name="error_unable_merge_database_kdb">Nije moguće spojiti sa kdb datotekom baze podataka</string>
<string name="error_location_unknown">Lokacija baze podataka je nepoznata, radnja baze podataka se ne može izvršiti.</string>
<string name="corrupted_file">Oštećena datoteka.</string>
<string name="colorize_password_title">Obojite lozinke</string>
<string name="show_otp_token_summary">Prikazuje OTP tokene na listi unosa</string>
<string name="error_field_name_already_exists">Ime polja već postoji.</string>
<string name="menu_merge_database">Objedini podatke</string>
<string name="menu_keystore_remove_key">Izbrišite ključ za otključavanje uređaja</string>
<string name="subdomain_search_summary">Pretražujte veb domene sa ograničenjima poddomena</string>
<string name="export_app_properties_title">Izvezite podešavanja aplikacije</string>
<string name="registration_mode">Režim registracije</string>
<string name="remember_database_locations_title">Zapamtite lokacije baza podataka</string>
<string name="remember_hardware_key_title">Zapamtite hardverske ključeve</string>
<string name="remember_hardware_key_summary">Vodi evidenciju o korišćenim hardverskim ključevima</string>
<string name="error_import_app_properties">Greška tokom uvoza podešavanja aplikacije</string>
<string name="hide_broken_locations_title">Sakrij neispravne veze baze podataka</string>
<string name="import_app_properties_title">Uvezite podešavanja aplikacije</string>
<string name="description_app_properties">KeePassDX svojstva za upravljanje podešavanjima aplikacije</string>
<string name="show_recent_files_summary">Prikaži lokacije nedavnih baza podataka</string>
<string name="success_import_app_properties">Podešavanja aplikacije su uvezena</string>
<string name="kdf_explanation">Da bi se generisao ključ za algoritam šifrovanja, glavni ključ se transformiše korišćenjem nasumično slane funkcije izvođenja ključa.</string>
<string name="do_not_kill_app">Ne ubijajte aplikaciju…</string>
<string name="encryption_explanation">Algoritam šifrovanja baze podataka koji se koristi za sve podatke</string>
<string name="command_execution">Izvršavanje komande…</string>
<string name="content_description_nav_header">Zaglavlje za navigaciju</string>
<string name="navigation_drawer_open">Ploča navigacije otvorena</string>
<string name="navigation_drawer_close">Ploča navigacije zatvorena</string>
<string name="searchable">Pretraživo</string>
<string name="inherited">Nasledi</string>
<string name="auto_type_sequence">Automatska sekvenca unosa</string>
<string name="tags">Oznake</string>
<string name="custom_data">Prilagođeni podaci</string>
<string name="search_filters">Filteri za pretragu</string>
<string name="current_group">Trenutna grupa</string>
<string name="case_sensitive">Osetljivo na velika i mala slova</string>
<string name="personal_identification_number">PIN</string>
<string name="international_bank_account_number">IBAN</string>
<string name="secure_note">Sigurna beleška</string>
<string name="error_database_uri_null">URI baze podataka se ne može preuzeti.</string>
<string name="read_only_warning">U zavisnosti od vašeg menadžera datoteka, KeePassDX možda neće dozvoliti da upisuje u vašu memoriju.</string>
<string name="sort_menu">Sortiraj</string>
<string name="auto_type">Automatski unos</string>
<string name="save_mode">Režim čuvanja</string>
<string name="info">Informacije</string>
<string name="waiting_challenge_request">Čeka se zahtev za izazov…</string>
<string name="waiting_challenge_response">Čeka se odgovor na izazov…</string>
<string name="template_group_name">Predlošci</string>
<string name="regex">Regularni izraz</string>
<string name="holder">Vlasnik</string>
<string name="number">Broj</string>
<string name="error_word_reserved">Ova reč je rezervisana i ne može se koristiti.</string>
<string name="card_verification_value">CVV</string>
<string name="id_card">Lična karta</string>
<string name="wireless">Vi-Fi</string>
<string name="ssid">SSID</string>
<string name="standard">Standardno</string>
<string name="template">Šablon</string>
<string name="error_no_hardware_key">Izaberite hardverski ključ.</string>
<string name="error_XML_malformed">XML je pogrešno oblikovan.</string>
<string name="error_move_group_here">Ovde ne možete premestiti grupu.</string>
<string name="error_file_to_big">Datoteka koju pokušavate da otpremite je prevelika.</string>
<string name="error_duplicate_file">Podaci o fajlu već postoje.</string>
<string name="error_response_already_provided">Odgovor je već dat.</string>
<string name="error_no_response_from_challenge">Nije moguće dobiti odgovor na izazov.</string>
<string name="error_cancel_by_user">Korisnik je otkazao.</string>
<string name="error_driver_required">Potreban je drajver za %1$s.</string>
<string name="menu_app_settings_summary">Pretraga, zaključavanje, istorija, svojstva</string>
<string name="menu_form_filling_settings_summary">Tastatura, automatsko popunjavanje, klipbord</string>
<string name="menu_advanced_unlock_settings_summary">Biometrija, akreditiv uređaja</string>
<string name="menu_database_settings_summary">Metapodaci, korpa za otpatke, šabloni, istorija</string>
<string name="menu_security_settings_summary">Šifrovanje, funkcija izvođenja ključa</string>
<string name="master_key_settings_summary">Promena, obnova</string>
<string name="menu_save_copy_to">Sačuvajte kopiju u…</string>
<string name="menu_external_icon">Vanjska ikona</string>
<string name="create_keepass_file">Napravite novi trezor</string>
<string name="auto_focus_search_summary">Zatražite pretragu prilikom otvaranja baze podataka</string>
<string name="subdomain_search_title">Pretraga poddomena</string>
<string name="progress_create">Pravljenje nove baze podataka…</string>
<string name="read_only">Zaštićeno od pisanja</string>
<string name="error_export_app_properties">Greška tokom izvoza podešavanja aplikacije</string>
<string name="contains_duplicate_uuid">Baza podataka sadrži duplirane UUID-ove.</string>
<string name="contains_duplicate_uuid_procedure">Rešiti problem generisanjem novih UUID-ova za nastavak duplikata?</string>
<string name="search_mode">Režim pretrage</string>
<string name="selection_mode">Režim izbora</string>
<string name="parallelism">Paralelizam</string>
<string name="parallelism_explanation">Stepen paralelizma (tj. broj niti) koji koristi funkcija izvođenja ključa.</string>
<string name="saving_database">Čuvanje baze podataka…</string>
</resources>

View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="accept">接受</string>
<string name="add_entry">新增項目</string>
<string name="edit_entry">編輯項目</string>
<string name="add_group">新增群組</string>
<string name="master_key">主密鑰</string>
<string name="security">安全</string>
<string name="encryption">加密</string>
<string name="encryption_algorithm">加密演算法</string>
<string name="key_derivation_function">密鑰推算函數</string>
<string name="app_timeout">超時</string>
<string name="application">應用程式</string>
<string name="brackets">括弧</string>
<string name="extended_ASCII">延伸ASCII</string>
<string name="allow">允許</string>
<string name="clipboard_error_title">剪貼簿錯誤</string>
<string name="clipboard_error">有啲設備唔容許其他應用程式用剪貼簿。</string>
<string name="clipboard_cleared">清除咗剪貼簿</string>
<string name="app_timeout_summary">鎖定資料庫前嘅閒置時間</string>
<string name="clipboard_error_clear">清除唔到剪貼簿</string>
<string name="clipboard_timeout">剪貼簿超時</string>
<string name="clipboard_timeout_summary">剪貼簿保留時間(如果裝置支持)</string>
<string name="content_description_background">背景</string>
<string name="content_description_open_file">開啟檔案</string>
<string name="content_description_node_children">子節點</string>
<string name="content_description_add_node">新增節點</string>
<string name="content_description_add_entry">新增項目</string>
<string name="content_description_add_group">新增群組</string>
<string name="content_description_add_item">新增項目</string>
<string name="content_description_credentials_information">憑證資訊</string>
<string name="content_description_otp_information">一次性密碼(OTP)訊息</string>
<string name="content_description_password_checkbox">密碼核取方塊</string>
<string name="content_description_keyfile_checkbox">密鑰檔案核取方塊</string>
<string name="content_description_hardware_key_checkbox">硬件密鑰方塊</string>
<string name="content_description_repeat_toggle_password_visibility">重複切換密碼能見度</string>
<string name="content_description_entry_icon">項目圖示</string>
<string name="content_description_entry_foreground_color">項目前景顏色</string>
<string name="content_description_entry_background_color">項目背景顏色</string>
<string name="content_description_nav_header">導覽</string>
<string name="validate">驗證</string>
<string name="discard_changes">放棄更改?</string>
<string name="entry_password_generator">密碼產生器</string>
<string name="content_description_password_length">密碼長度</string>
<string name="content_description_passphrase_word_count">密碼短句字數</string>
<string name="entry_add_field">新增欄位</string>
<string name="entry_add_attachment">新增附件</string>
<string name="content_description_remove_field">刪除欄位</string>
<string name="content_description_update_from_list">更新</string>
<string name="content_description_keyboard_close_fields">關閉欄位</string>
<string name="discard">放棄</string>
<string name="select_to_copy">複製%1$s去剪貼簿</string>
<string name="default_checkbox">用作預設資料庫</string>
<string name="digits">數字</string>
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft呢個係&lt;strong&gt;冇廣告&lt;/strong&gt;&lt;strong&gt;開源&lt;/strong&gt;軟件。 \n你可以喺遵循&lt;strong&gt;GPL 3&lt;/strong&gt;或者更高版本嘅情況下重新發佈而Kunzisoft對此不帶有任何擔保。</string>
<string name="html_about_privacy">&lt;strong&gt;唔收集用戶資料。&lt;/strong&gt;,呢個應用程式唔會連接任何伺服器,只會喺裝置上運作,完全尊重用戶私穩。</string>
<string name="html_about_contribution">為程式能夠&lt;strong&gt;保持自主&lt;/strong&gt;&lt;strong&gt;修復漏洞&lt;/strong&gt;&lt;strong&gt;新增功能&lt;/strong&gt;&lt;strong&gt;保持持續開發&lt;/strong&gt;,有賴你的&lt;strong&gt;貢獻&lt;/strong&gt;</string>
<string name="entry_confpassword">確認密碼</string>
<string name="entry_expires">失效時間</string>
<string name="expired">過期</string>
<string name="entry_UUID">UUID</string>
<string name="entry_attachments">附件</string>
<string name="entry_keyfile">密鑰檔案</string>
<string name="hardware_key">硬件密鑰</string>
<string name="entry_modified">修改時間</string>
<string name="entry_created">建立時間</string>
<string name="inherited">繼承</string>
<string name="auto_type">自動填入</string>
<string name="entry_not_found">找不到項目資料。</string>
<string name="entry_password">密碼</string>
<string name="tags">標籤</string>
<string name="custom_data">自定義數據</string>
<string name="save">儲存</string>
<string name="entry_title">名稱</string>
<string name="entry_setup_otp">設定一次性密碼(OTP)</string>
<string name="otp_secret">OTP密鑰</string>
<string name="otp_period">間隔(秒)</string>
<string name="search_filters">搜尋過濾器</string>
<string name="otp_algorithm">演算法</string>
<string name="current_group">目前組别</string>
<string name="case_sensitive">區分大小寫</string>
<string name="regex">正則表達式</string>
<string name="debit_credit_card">扣賬卡 / 信用卡</string>
<string name="holder">持卡人</string>
<string name="email_address">電郵地址</string>
<string name="wireless">Wi-Fi</string>
<string name="standard">標準</string>
<string name="version">版本</string>
<string name="entry_otp">OTP</string>
<string name="error_arc4">唔支援Arcfour stream密碼。</string>
<string name="error_can_not_handle_uri">KeePassDX 處理唔到呢個網址。</string>
<string name="error_file_not_create">新增唔到檔案</string>
<string name="error_invalid_db">讀取唔到資料庫。</string>
<string name="error_invalid_path">請確保路徑正確。</string>
<string name="error_invalid_OTP">無效 OTP 密鑰。</string>
<string name="error_no_name">請輸入用戶名。</string>
<string name="contact">聯絡方法</string>
<string name="info">資訊</string>
<string name="contribution">貢獻</string>
<string name="homepage">首頁</string>
<string name="feedback">反映意見</string>
<string name="about_description">相容KeePass密碼管理軟件嘅Android App</string>
<string name="file_manager_install_description">檔案總管要支援 ACTION_CREATE_DOCUMENT 和 ACTION_OPEN_DOCUMENT 的 intent先可以建立、開啟同儲存資料庫檔案。</string>
<string name="content_description_file_information">檔案資訊</string>
<string name="content_description_database_color">資料庫顔色</string>
<string name="content_description_remove_from_list">移除</string>
<string name="template_group_name">範本</string>
<string name="retrieving_db_key">攞緊資料庫密鑰……</string>
<string name="waiting_challenge_response">等緊Challenge回應……</string>
<string name="waiting_challenge_request">等緊Challenge請求……</string>
<string name="decrypting_db">解密緊資料庫內容……</string>
<string name="database">資料庫</string>
<string name="entry_accessed">存取時間</string>
<string name="entry_cancel">取消</string>
<string name="entry_notes">備註</string>
<string name="otp_type">OTP 類型</string>
<string name="otp_counter">計數器</string>
<string name="number">卡號</string>
<string name="otp_digits">數位</string>
<string name="card_verification_value">安全碼(CVV)</string>
<string name="personal_identification_number">PIN 碼</string>
<string name="id_card">身份證</string>
<string name="name">姓名</string>
<string name="place_of_issue">發行地</string>
<string name="date_of_issue">發行日期</string>
<string name="email">電郵</string>
<string name="ssid">SSID</string>
<string name="public_key">公鑰</string>
<string name="type">類型</string>
<string name="cryptocurrency">加密貨幣錢包</string>
<string name="token">Token</string>
<string name="bank">銀行</string>
<string name="international_bank_account_number">IBAN</string>
<string name="membership">會籍</string>
<string name="private_key">私鑰</string>
<string name="seed">種子</string>
<string name="bank_identifier_code">SWIFT / BIC</string>
<string name="account">帳戶</string>
<string name="bank_name">銀行名稱</string>
<string name="entry_url">網址</string>
<string name="entry_user_name">用戶名</string>
</resources>

View File

@@ -1,12 +1,683 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="feedback">Обратна връзка</string>
<string name="encryption_algorithm">Алгоритъм за криптиране</string>
<string name="encryption">Криптиране</string>
<string name="encryption_algorithm">Алгоритъм за шифроване</string>
<string name="encryption">Шифроване</string>
<string name="security">Сигурност</string>
<string name="master_key">Главен ключ</string>
<string name="add_group">Добави група</string>
<string name="edit_entry">Редактирай</string>
<string name="add_entry">Добави</string>
<string name="accept">Приемам</string>
<string name="master_key">Главна парола</string>
<string name="add_group">Нова група</string>
<string name="edit_entry">Редактиране на запис</string>
<string name="add_entry">Нов запис</string>
<string name="accept">Приемане</string>
<string name="biometric_delete_all_key_title">Изтриване на шифроващите ключове</string>
<string name="digits">Цифри</string>
<string name="contact">За контакт</string>
<string name="app_timeout">Време за изчакване</string>
<string name="application">Приложение</string>
<string name="brackets">Скоби</string>
<string name="about">Относно</string>
<string name="info">Информация</string>
<string name="clipboard_cleared">Клипбордът е изчистен</string>
<string name="content_description_add_group">Нова група</string>
<string name="clipboard_timeout_summary">Продължителност на съхранение в клипборда (ако се поддържа от вашето устройство)</string>
<string name="clipboard_error">Някои устройства не позволяват на приложенията да използват клипборда.</string>
<string name="entry_title">Заглавие</string>
<string name="about_description">Версия за Андроид на приложението за управление на пароли KeePass</string>
<string name="save">Запазване</string>
<string name="entry_confpassword">Потвърждаване на парола</string>
<string name="key_derivation_function">Функция за извличане на ключ</string>
<string name="content_description_open_file">Отваряне на файл</string>
<string name="entry_cancel">Отказ</string>
<string name="custom_data">Потребителски данни</string>
<string name="tags">Етикети</string>
<string name="clipboard_explanation_summary">Копиране на полета за въвеждане посредством междинната памет на устройството</string>
<string name="otp_type">Вид на OTP</string>
<string name="entry_url">Адрес в интернет</string>
<string name="contribution">Участие</string>
<string name="entry_UUID">Идентификатор</string>
<string name="entry_history">История</string>
<string name="copy_field">%1$s копие</string>
<string name="clipboard_error_title">Грешка в клипборда</string>
<string name="file_manager_install_description">За създаване, отваряне и запазване на файлове на хранилищата е необходимо приложение за управление на файлове, което приема действието ACTION_CREATE_DOCUMENT и ACTION_OPEN_DOCUMENT.</string>
<string name="content_description_add_entry">Нов запис</string>
<string name="clipboard_timeout">Време за изчакване на клипборда</string>
<string name="expired">Изтекла давност</string>
<string name="entry_password">Парола</string>
<string name="retrieving_db_key">Получаване на ключа на хранилището…</string>
<string name="entry_accessed">Достъпен</string>
<string name="entry_created">Създаден</string>
<string name="entry_user_name">Потребител</string>
<string name="content_description_background">Фон</string>
<string name="clipboard_error_clear">Не може да се изчисти клипборда</string>
<string name="entry_expires">Изтичаща давност</string>
<string name="entry_attachments">Прикачени файлове</string>
<string name="otp_period">Период (секунди)</string>
<string name="app_timeout_summary">Време без активност преди заключване на хранилището</string>
<string name="otp_digits">Цифри</string>
<string name="extended_ASCII">Разширен набор от ASCII</string>
<string name="entry_otp">OTP</string>
<string name="entry_notes">Бележка</string>
<string name="otp_counter">Брояч</string>
<string name="allow">Разрешаване</string>
<string name="allow_copy_password_warning">Внимание: Междинната памет се споделя от всички приложения. Ако бъде копирана чувствителна информация, друго приложение може да ги използва.</string>
<string name="entry_modified">Променен</string>
<string name="select_to_copy">Изберете, за да копирате %1$s в клипборда</string>
<string name="otp_secret">Таен ключ</string>
<string name="homepage">Уебсайт</string>
<string name="loading_database">Зареждане на хранилището…</string>
<string name="password">Парола</string>
<string name="remember_hardware_key_title">Запомняне на хардуерните ключове</string>
<string name="decrypting_db">Разшифроване на хранилището…</string>
<string name="unlock">Отключване</string>
<string name="unavailable_feature_hardware">Необходимият хардуер не може да бъде намерен.</string>
<string name="hardware_key">Хардуерен ключ</string>
<string name="hide_password_summary">Скриване на паролите (***) по подразбиране</string>
<string name="select_database_file">Отключване на хранилище</string>
<string name="content_description_hardware_key_checkbox">Отметка на поле с хардуерен ключ</string>
<string name="hide_password_title">Скриване на пароли</string>
<string name="hint_pass">Парола</string>
<string name="education_select_database_title">Отворете съществуващо хранилище</string>
<string name="content_description_keyfile_checkbox">Отметка на поле за файл с ключ</string>
<string name="error_hardware_key_unsupported">Хардуерният ключ не се поддържа.</string>
<string name="remember_hardware_key_summary">Запомняне на използваните хардуерни ключове</string>
<string name="error_nokeyfile">Избиране на файл с ключ.</string>
<string name="entry_keyfile">Файл с ключ</string>
<string name="error_no_hardware_key">Изберете хардуерен ключ.</string>
<string name="advanced_unlock_prompt_store_credential_message">Въпреки че използвате разпознаване на отключването на устройството ще трябва да запомните главната парола на хранилището.</string>
<string name="create_keepass_file">Ново хранилище</string>
<string name="recycle_bin">Кошче</string>
<string name="default_checkbox">Използване като хранилище по подразбиране</string>
<string name="otp_algorithm">Алгоритъм</string>
<string name="email">Ел. поща</string>
<string name="email_address">Адрес на ел. поща</string>
<string name="personal_identification_number">ПИН</string>
<string name="database">Хранилище</string>
<string name="menu_lock">Заключване на хранилището</string>
<string name="content_description_password_length">Дължина на паролата</string>
<string name="content_description_remove_from_list">Премахване</string>
<string name="content_description_update_from_list">Обновяване</string>
<string name="entry_password_generator">Създаване на парола</string>
<string name="version">Издание</string>
<string name="settings">Настройки</string>
<string name="creating_database">Създаване на хранилището…</string>
<string name="lock">Заключване</string>
<string name="keyboard">Клавиатура</string>
<string name="keyboard_keys_category">Ключове</string>
<string name="number">Номер</string>
<string name="name">Име</string>
<string name="public_key">Публичен ключ</string>
<string name="private_key">Частен ключ</string>
<string name="menu_database_settings">Настройки на хранилището</string>
<string name="menu_app_settings">Настройки на приложението</string>
<string name="discard">Отхвърляне</string>
<string name="entry_add_field">Ниво поле</string>
<string name="application_appearance">Интерфейс</string>
<string name="other">Други</string>
<string name="database_default_username_title">Потребител по подразбиране</string>
<string name="text_appearance">Текст</string>
<string name="download">Изтегляне</string>
<string name="sort_username">Потребител</string>
<string name="menu_save_database">Запазване на данните</string>
<string name="never">Никога</string>
<string name="field_name">Име на полето</string>
<string name="sort_menu">Сортиране</string>
<string name="field_value">Стойност на полето</string>
<string name="hint_group_name">Име на групата</string>
<string name="menu_merge_database">Обединяване на данните</string>
<string name="menu_merge_from">Обединяване с…</string>
<string name="menu_save_copy_to">Запазване на копие в…</string>
<string name="sort_title">Заглавие</string>
<string name="discard_changes">Отхвърляне на промените?</string>
<string name="menu_reload_database">Презареждане на данните</string>
<string name="contribute">Допринасяне</string>
<string name="error_load_database_KDF_memory">Ключът не може да бъде зареден. Пробвайте да намалите използваната памет от функцията за извличане на ключове.</string>
<string name="content_description_passphrase_word_count">Брой думи във фраза за достъп</string>
<string name="search_filters">Филтри за търсене</string>
<string name="current_group">Текуща група</string>
<string name="case_sensitive">Съвпадение на регистъра</string>
<string name="passphrase">Фраза за достъп</string>
<string name="holder">Собственик</string>
<string name="menu_form_filling_settings">Попълване на формуляри</string>
<string name="menu_delete_entry_history">Премахване на история</string>
<string name="menu_restore_entry_history">Възстановяване на история</string>
<string name="minus">Дефис</string>
<string name="no_results">Няма съвпадения</string>
<string name="progress_title">Обработка…</string>
<string name="progress_create">Създаване на хранилище…</string>
<string name="do_not_kill_app">Не затваряйте приложението…</string>
<string name="menu_appearance_settings">Външен вид</string>
<string name="download_finalization">Завършване…</string>
<string name="content_description_database_color">Цвят на хранилище</string>
<string name="entry_not_found">Данни за записа не са намерени.</string>
<string name="seed">Криптографско семе</string>
<string name="account">Профил</string>
<string name="bank">Банка</string>
<string name="bank_name">Наименование на банката</string>
<string name="standard">Стандарт</string>
<string name="template">Шаблон</string>
<string name="menu_move">Преместване</string>
<string name="menu_cancel">Отказ</string>
<string name="menu_hide_password">Скриване на парола</string>
<string name="auto_focus_search_summary">Търсене при отключване на хранилище</string>
<string name="saving_database">Запазване на хранилището…</string>
<string name="command_execution">Изпълнение на команда…</string>
<string name="content_description_keyboard_close_fields">Затваряне на полета</string>
<string name="content_description_otp_information">Информация за еднократна парола</string>
<string name="content_description_repeat_toggle_password_visibility">Превключвател на видимостта на парола на поле за повтаряне на парола</string>
<string name="content_description_entry_icon">Пиктограма на запис</string>
<string name="inherited">Наследено</string>
<string name="menu_empty_recycle_bin">Изпразване на кошчето</string>
<string name="html_about_privacy">&lt;strong&gt;Не се събират никакви потребителски данни&lt;/strong&gt;, приложението не се свързва с никакви сървъри, работи изцяло локално и напълно уважава поверителността на потребителите.</string>
<string name="searchable">Достъпно за търсене</string>
<string name="menu_external_icon">Външна пиктограма</string>
<string name="autofill_select_entry">Избиране на запис…</string>
<string name="enable_education_screens_title">Обучителни подсказки</string>
<string name="entropy_calculate">Ентропия: изчисляване…</string>
<string name="template_group_name">Шаблони</string>
<string name="bank_identifier_code">SWIFT / BIC</string>
<string name="menu_paste">Поставяне</string>
<string name="content_description_nav_header">Заглавка на меню</string>
<string name="auto_type_sequence">Последователност за автом. въвеждане</string>
<string name="id_card">Карта за самоличност</string>
<string name="card_verification_value">CVV</string>
<string name="place_of_issue">Място на издаване</string>
<string name="date_of_issue">Дата на издаване</string>
<string name="ssid">SSID</string>
<string name="type">Вид</string>
<string name="cryptocurrency">Портфейл за криптовалута</string>
<string name="token">Код за достъп</string>
<string name="menu_change_key_settings">Промяна на главната парола</string>
<string name="menu_advanced_unlock_settings">Отключване на устройството</string>
<string name="menu_security_settings">Настройки за сигурност</string>
<string name="menu_donate">Даряване</string>
<string name="menu_edit">Променяне</string>
<string name="menu_copy">Копиране</string>
<string name="menu_file_selection_read_only">Само за четене</string>
<string name="menu_search">Търсене</string>
<string name="menu_showpass">Показване на паролата</string>
<string name="menu_keystore_remove_key">Премахване на ключа за устройството</string>
<string name="menu_url">Посещаване на адреса</string>
<string name="menu_open_file_read_and_write">За четене и запис</string>
<string name="auto_type">Автоматично въвеждане</string>
<string name="content_description_node_children">Дъщерен възел</string>
<string name="content_description_add_node">Нов възел</string>
<string name="content_description_file_information">Информация за файл</string>
<string name="content_description_credentials_information">Информация за самоличност</string>
<string name="content_description_add_item">Нов елемент</string>
<string name="content_description_password_checkbox">Отметка на поле за парола</string>
<string name="content_description_entry_foreground_color">Цвят на шрифта на запис</string>
<string name="navigation_drawer_open">Отваряне на страничното меню</string>
<string name="navigation_drawer_close">Затваряне на страничното меню</string>
<string name="validate">Проверяване</string>
<string name="content_description_remove_field">Премахване на поле</string>
<string name="entry_add_attachment">Нов прикачен файл</string>
<string name="waiting_challenge_request">Изчакване на заявка за предизвикване…</string>
<string name="waiting_challenge_response">Изчакване на отговор на предизвикване…</string>
<string name="entry_setup_otp">Настройка на еднократна парола</string>
<string name="regex">Регулярен израз</string>
<string name="debit_credit_card">Банкова карта</string>
<string name="wireless">Безжична мрежа</string>
<string name="international_bank_account_number">IBAN</string>
<string name="secure_note">Защитена бележка</string>
<string name="membership">Членство</string>
<string name="error_arc4">Поточният шифър Аркфор не се поддържа.</string>
<string name="error_empty_key">Ключът не трябва да е празен.</string>
<string name="keyfile_is_empty">Файлът с ключ е празен.</string>
<string name="length">Дължина</string>
<string name="menu_app_settings_summary">Търсене, заключване, история, настройки</string>
<string name="menu_form_filling_settings_summary">Клавиатура, автовъвеждане, междинна памет</string>
<string name="menu_database_settings_summary">Описателни данни, кошче, шаблони, история</string>
<string name="master_key_settings_summary">Промяна, обновяване</string>
<string name="menu_open">Отключване</string>
<string name="auto_focus_search_title">Бързо търсене</string>
<string name="subdomain_search_title">Търсене на поддомейни</string>
<string name="menu_delete">Изтриване</string>
<string name="menu_appearance_settings_summary">Теми, цветове, атрибути</string>
<string name="download_initialization">Подготвяне…</string>
<string name="content_description_entry_background_color">Цвят на фона на запис</string>
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft е приложение с &lt;strong&gt;отворен код&lt;/strong&gt; и &lt;strong&gt;без реклами&lt;/strong&gt;. \nРазпространява се под лиценза &lt;strong&gt;GPLv3&lt;/strong&gt; без каквато и да е гаранция.</string>
<string name="menu_advanced_unlock_settings_summary">Биометрия, удостоверяване</string>
<string name="menu_security_settings_summary">Шифроване, функция за извличане на ключ</string>
<string name="menu_master_key_settings">Настройки на главната парола</string>
<string name="file_browser">Управление на файлове</string>
<string name="generate_password">Създаване на парола</string>
<string name="autofill_service_name">Услуга за автоматично попълване на KeePassDX</string>
<string name="settings_database_force_changing_master_key_next_time_summary">Изисква смяна на главната парола следващия път (веднъж)</string>
<string name="filter">Филтър</string>
<string name="sort_db">Естествен ред</string>
<string name="sort_recycle_bin_bottom">Кошчето е най-долу</string>
<string name="sort_groups_before">Първо групите</string>
<string name="autofill_preference_title">Настройка на автоматично попълване</string>
<string name="database_custom_color_title">Цвят на хранилището по избор</string>
<string name="keyboard_theme_title">Тема на клавиатурата</string>
<string name="keyboard_auto_go_action_title">Автоматично действие на клавиш</string>
<string name="education_advanced_unlock_title">Отключвайте хранилището заедно с устройството</string>
<string name="education_advanced_unlock_summary">Свържете паролата със сканиране на биометрични данни или удостоверяване на устройството, за да отключвате бързо хранилищата.</string>
<string name="education_entry_new_field_summary">Създайте допълнително поле, добавете стойност и при необходимост я защитете.</string>
<string name="education_unlock_title">Отключете хранилището</string>
<string name="education_sort_title">Сортиране на записи</string>
<string name="education_donation_summary">Допринесете за повишаване на стабилността, сигурността и добавянето на нови възможности.</string>
<string name="show_entry_colors_summary">Шрифта и фона на записите да е цветен</string>
<string name="backspace">Backspace</string>
<string name="keyboard_previous_database_credentials_title">Екран за въвеждане на главната парола</string>
<string name="select_entry">Изберете запис</string>
<string name="education_new_node_title">Добавете елементи към хранилището</string>
<string name="education_generate_password_summary">Създавайте надеждни пароли за записите, задайте лесно изискванията на формуляра и вашите изисквания за сигурност.</string>
<string name="education_add_attachment_summary">За да запазите важни външни данни можете да прикачвате файлове към записите.</string>
<string name="download_progression">Изпълнение: %1$d%%</string>
<string name="download_complete">Готово!</string>
<string name="unit_kibibyte">КиБ</string>
<string name="character_count">Брой знаци: %1$d</string>
<string name="style_brightness_title">Яркост на темата</string>
<string name="style_brightness_summary">Избор между светла и тъмна тема</string>
<string name="icon_section_standard">Стандартен</string>
<string name="icon_section_custom">Потребителски</string>
<string name="custom_fields">Потребителски полета</string>
<string name="back_to_previous_keyboard">Превключва предната клавиатура</string>
<string name="enable_auto_save_database_title">Автоматично запазване на хранилището</string>
<string name="kdf_explanation">При създаване на ключа за алгоритъма за шифроване, главната парола се преобразува с помощта на функция за извличане на ключ и случайна „сол“.</string>
<string name="rounds">Брой преобразувания</string>
<string name="sort_ascending">Възходящо ↓</string>
<string name="delete_entered_password_title">Премахване на парола</string>
<string name="file_not_found_content">Файлът не е намерен. Пробвайте да го отворите от приложението за управление на файлове.</string>
<string name="unit_byte">Б</string>
<string name="search">Търсене</string>
<string name="uppercase">Горен регистър</string>
<string name="warning">Внимание</string>
<string name="lock_database_back_root_summary">Заключва хранилището при докосване на бутона „Назад“ на началния екран</string>
<string name="read_only">Само за четене</string>
<string name="contains_duplicate_uuid">Хранилището съдържа повтарящ се идентификатор.</string>
<string name="biometric">Биометричен ключ</string>
<string name="set_autofill_service_title">Задаване на подразбирана услуга за автоматично попълване</string>
<string name="password_size_title">Дължина на създаваните пароли</string>
<string name="lock_database_back_root_title">Заключване при „Назад“</string>
<string name="content">Съдържание</string>
<string name="advanced_unlock">Отключване на устройството</string>
<string name="settings_database_recommend_changing_master_key_title">Препоръчителна смяна</string>
<string name="settings_database_recommend_changing_master_key_summary">Препоръчване на смяна на главната парола (в дни)</string>
<string name="settings_database_force_changing_master_key_title">Принудителна смяна</string>
<string name="database_name_title">Име на хранилището</string>
<string name="database_description_title">Описание на хранилището</string>
<string name="magic_keyboard_title">Magikeyboard</string>
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
<string name="keyboard_entry_category">Запис</string>
<string name="keyboard_appearance_category">Външен вид</string>
<string name="allow_no_password_summary">Разрешава докосване на бутона „Отключване“ без попълнена главна парола</string>
<string name="delete_entered_password_summary">Премахва въведената парола след опит за отключване на хранилище</string>
<string name="reset_education_screens_text">Обучителните подсказки са нулирани</string>
<string name="education_entry_edit_summary">Редактирайте записи с потребителски полета. Можете да правите кръстосани връзки между полетата на различни записи.</string>
<string name="education_generate_password_title">Създавайте надеждни пароли</string>
<string name="education_field_copy_summary">Копираните полета могат да бъдат поставени навсякъде.
\n
\nИзползвайте предпочитания то вас метод за попълване на формуляри.</string>
<string name="exclude_ambiguous_chars">Изключване на еднакво изглеждащите знаци</string>
<string name="at_least_one_char">Най-малко по един символ от всяка група</string>
<string name="education_entry_new_field_title">Добавяйте полета по ваш избор</string>
<string name="icon_pack_choose_title">Пакет с пиктограми</string>
<string name="icon_pack_choose_summary">Използвания в приложението пакет с пиктограми</string>
<string name="import_app_properties_title">Внасяне на настройки</string>
<string name="no_url_handler">Инсталирайте мрежов четец, който да отвори този адрес.</string>
<string name="sort_last_modify_time">Дата на промяна</string>
<string name="autofill_sign_in_prompt">Влизане чрез KeePassDX</string>
<string name="style_choose_title">Тема на приложението</string>
<string name="education_search_title">Търсете елементи</string>
<string name="corrupted_file">Файлът е повреден.</string>
<string name="lowercase">Долен регистър</string>
<string name="protection">Защита</string>
<string name="space">Интервал</string>
<string name="sort_creation_time">Дата на създаване</string>
<string name="sort_last_access_time">Дата на последен достъп</string>
<string name="special">Специални</string>
<string name="underline">Подчертаване</string>
<string name="unsupported_db_version">Неподдържана версия на хранилището.</string>
<string name="database_history">История</string>
<string name="general">Общи</string>
<string name="autofill">Автоматично попълване</string>
<string name="device_credential">Удостоверяване на устройството</string>
<string name="lock_database_show_button_summary">Показва бутон за заключване в интерфейса</string>
<string name="assign_master_key">Задаване на главна парола</string>
<string name="file_name">Име на файла</string>
<string name="path">Път</string>
<string name="settings_database_force_changing_master_key_summary">Изисква смяна на главната парола (в дни)</string>
<string name="settings_database_force_changing_master_key_next_time_title">Принудителна смяна следващия път</string>
<string name="data">Данни</string>
<string name="database_data_compression_title">Компресия на данните</string>
<string name="database_data_compression_summary">Компресията на данните намалява размера на хранилището</string>
<string name="database_version_title">Версия на хранилището</string>
<string name="compression">Компресия</string>
<string name="compression_none">Няма</string>
<string name="compression_gzip">Gzip</string>
<string name="templates">Шаблони</string>
<string name="keyboard_name">Magikeyboard</string>
<string name="keyboard_setting_label">Настройки на Magikeyboard</string>
<string name="keyboard_selection_entry_title">Избор на записи</string>
<string name="allow_no_password_title">Разрешаване без главна парола</string>
<string name="enable_read_only_title">Само за четене</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="keyboard_notification_entry_content_title">Записът %1$s е достъпен в Magikeyboard</string>
<string name="keyboard_notification_entry_content_title_text">Запис</string>
<string name="enter">Enter</string>
<string name="autofill_close_database_title">Затваряне на хранилище</string>
<string name="autofill_close_database_summary">Затваряне на хранилището след избор на автоматично попълване</string>
<string name="enable_education_screens_summary">Откроява елементи, с цел да опише как работи приложението</string>
<string name="reset_education_screens_title">Нулиране на обучителни подсказки</string>
<string name="reset_education_screens_summary">Отново показва всички обучителни подсказки</string>
<string name="education_create_database_title">Създайте файла на хранилището</string>
<string name="education_create_database_summary">Създайте своя първи файл за управление на пароли.</string>
<string name="education_select_database_summary">Отворете вече създаден файл на хранилище, за да продължите да го използвате.</string>
<string name="education_entry_edit_title">Променяйте записи</string>
<string name="education_validate_entry_title">Потвърждаване на записа</string>
<string name="education_add_attachment_title">Добавяйте прикачени файлове</string>
<string name="education_read_only_title">Хранилище само за четене</string>
<string name="education_setup_OTP_title">Настройка на OTP</string>
<string name="education_read_only_summary">Променете режима на отваряне за сесията.
\n
\nРежимът „само за четене“ предотвратява нежеланите промени в хранилището.
\nРежимът „за четене и запис“ дава възможност за добавяне, промяна и премахване на елементи.</string>
<string name="education_field_copy_title">Копирайте поле</string>
<string name="education_lock_title">Заключете хранилището</string>
<string name="education_lock_summary">Бързо заключете хранилището. Настройте приложението да се заключва след определено време или при изгасяне на екрана.</string>
<string name="education_sort_summary">Изберете признак за подредбата на записи и групи.</string>
<string name="education_donation_title">Участвайте</string>
<string name="download_attachment">Изтегляне %1$s</string>
<string name="upload_attachment">Изпращане %1$s</string>
<string name="download_canceled">Отказано!</string>
<string name="unit_mebibyte">МиБ</string>
<string name="unit_gibibyte">ГиБ</string>
<string name="entropy">Ентропия: %1$s бита</string>
<string name="entropy_high">Ентропия: висока</string>
<string name="consider_chars_filter">Допълнителни знаци</string>
<string name="word_separator">Разделител</string>
<string name="ignore_chars_filter">Пренебрегнати знаци</string>
<string name="title_case">Всяка Дума</string>
<string name="screenshot_mode_banner_text">Режим екранни снимки</string>
<string name="style_choose_summary">Използваната в приложението тема</string>
<string name="show_entry_colors_title">Оцветяване на записи</string>
<string name="hide_expired_entries_summary">Записите с изтекла давност не се показват</string>
<string name="education_new_node_summary">Елементите дават възможност да управлявате цифрови идентичности.
\n
\nИзползвайте групите (подобно на папки), за да групирате записите в хранилището.</string>
<string name="education_search_summary">Търсете по заглавие, потребител или съдържание на други полета, за да намерите своите пароли.</string>
<string name="html_about_contribution">За &lt;strong&gt;запазване на нашата независимост&lt;/strong&gt;, &lt;strong&gt;отстраняване на дефекти&lt;/strong&gt;, &lt;strong&gt;добавяне на нови възможности&lt;/strong&gt; и &lt;strong&gt;поддържане на активна разработка&lt;/strong&gt;, разчитаме на вашата &lt;strong&gt;поддръжка&lt;/strong&gt;.</string>
<string name="lock_database_show_button_title">Бутон за заключване</string>
<string name="autofill_explanation_summary">Включете услугата за попълване на формуляри в други приложения</string>
<string name="properties">Свойства</string>
<string name="enable_read_only_summary">По подразбиране отваря хранилището само за четене</string>
<string name="education_validate_entry_summary">Не забравяйте да потвърдите записа и да го запазите в хранилището.
\n
\nАко се задейства автоматичното заключване, а сте направили промени, рискувате загуба на данни.</string>
<string name="education_setup_OTP_summary">Настройте управлението на еднократни пароли (HOTP / TOTP) което да създава кодове за достъп за двустепенно удостоверяване (2FA).</string>
<string name="education_unlock_summary">Въведете паролата и/или файла с ключ, за да отключите хранилището.
\n
\nПравете резервно копие на хранилището на сигурно място след всяка промяна.</string>
<string name="lower_case">долен регистър</string>
<string name="upper_case">ГОРЕН РЕГИСТЪР</string>
<string name="hide_expired_entries_title">Скриване на записите без давност</string>
<string name="hint_conf_pass">Потвърждаване на парола</string>
<string name="subdomain_search_summary">Търсене на домейни със зададени поддомейни</string>
<string name="import_app_properties_summary">Изберете резервно копие на настройките</string>
<string name="export_app_properties_summary">Създава резервно копие на настройките</string>
<string name="root">Корен</string>
<string name="show_uuid_title">Идентификатор</string>
<string name="html_text_dev_feature_buy_pro">Купувайки версията &lt;strong&gt;Pro&lt;/strong&gt;,</string>
<string name="html_text_dev_feature_contibute">&lt;strong&gt;Участвайки в проекта&lt;/strong&gt;,</string>
<string name="html_text_dev_feature">Тази възможност е &lt;strong&gt;в разработка&lt;/strong&gt; и изисква вашето &lt;strong&gt;участие&lt;/strong&gt;, за да бъде достъпна скоро.</string>
<string name="html_text_feature_generosity">Тази &lt;strong&gt;тема&lt;/strong&gt; е достъпна, благодарение на вашата щедрост.</string>
<string name="invalid_db_sig">Форматът на хранилището не може да бъде определен.</string>
<string name="list_entries_show_username_summary">Показват се потребителските имена в списъка със записите</string>
<string name="list_entries_show_username_title">Потребители</string>
<string name="list_groups_show_number_entries_title">Брой записи</string>
<string name="list_groups_show_number_entries_summary">Показват се броя записи в група</string>
<string name="list_size_title">Размер на списъка</string>
<string name="contains_duplicate_uuid_procedure">Разрешаване на проблема, чрез създаване на нов идентификатор и продължаване?</string>
<string name="show_uuid_summary">Показва се идентификаторът на даден запис или група</string>
<string name="list_size_summary">Размер на текста на елементите от списъка</string>
<string name="colorize_password_summary">Оцветяване на паролите според вида на знаците</string>
<string name="export_app_properties_title">Изнасяне на настройки</string>
<string name="enable_screenshot_mode_summary">Разрешава на други приложения да записват и правят снимки на екрана</string>
<string name="html_text_dev_feature_thanks">Много благодарим за поддръжката.</string>
<string name="html_text_dev_feature_work_hard">Работим усърдно, за да добавим бързо тази възможност.</string>
<string name="hint_generated_password">Създадена парола</string>
<string name="hint_length">Дължина</string>
<string name="invalid_credentials">Неправилна главна парола или файл с ключ.</string>
<string name="show_otp_token_summary">Показват се кодовете за достъп от OTP в списъка със записите</string>
<string name="show_otp_token_title">Кодове от OTP</string>
<string name="error_can_not_handle_uri">Указаният URI не може да бъде обработен от KeePassDX.</string>
<string name="error_file_not_create">Файлът не може да бъде създаден.</string>
<string name="error_invalid_db">Грешка при четене на хранилището.</string>
<string name="hint_icon_name">Наименование на пиктограмата</string>
<string name="invalid_db_same_uuid">%1$s с идентификатор %2$s вече съществува.</string>
<string name="colorize_password_title">Оцветяване на пароли</string>
<string name="enable_screenshot_mode_title">Режим екранни снимки</string>
<string name="enable_keep_screen_on_title">Екранът винаги включен</string>
<string name="enable_keep_screen_on_summary">Поддържа екрана включен при преглед или промяна на запис</string>
<string name="enable_auto_save_database_summary">Запазва хранилището при важни действия (в режим „четене и запис“)</string>
<string name="html_text_ad_free">За разлика от много други приложения за управление на пароли това е &lt;strong&gt;без реклами&lt;/strong&gt;, &lt;strong&gt;свободно от лицензи&lt;/strong&gt; и не събира лични данни на сървърите си без значение каква версия използвате.</string>
<string name="html_text_dev_feature_upgrade">Не забравяйте да обновявате приложението.</string>
<string name="html_text_dev_feature_encourage">вие поощрявате разработчиците да добавят &lt;strong&gt;нови възможности&lt;/strong&gt; и да &lt;strong&gt;отстраняват дефекти&lt;/strong&gt; според вашите отзиви.</string>
<string name="html_text_buy_pro">Купувайки версията Pro ще имате достъп до тази &lt;strong&gt;тема&lt;/strong&gt; и особено ще помогнете за &lt;strong&gt;изпълнението на проекти на общността&lt;/strong&gt;.</string>
<string name="html_text_donation">За да развиваме проекта и да запазим неговата независимост се нуждаем от вашата &lt;strong&gt;поддръжка&lt;/strong&gt;.</string>
<string name="hint_keyfile">Файл с ключ</string>
<string name="invalid_algorithm">Грешен алгоритъм.</string>
<string name="description_app_properties">Свойства за управление на настройките на KeePassDX</string>
<string name="success_export_app_properties">Настройките на приложението са изнесени</string>
<string name="error_export_app_properties">Грешка при изнасяне на настройки</string>
<string name="error_invalid_OTP">Неприемлива тайна за OTP.</string>
<string name="error_no_name">Въведете име.</string>
<string name="hide_broken_locations_summary">Скрива вече несъществуващи хранилища от списъка с последно отваряните</string>
<string name="registration_mode">Режим регистрация</string>
<string name="remember_database_locations_title">Запомняне използваните хранилища</string>
<string name="show_recent_files_title">Показване на последните хранилища</string>
<string name="search_mode">Режим търсене</string>
<string name="save_mode">Режим запазване</string>
<string name="selection_mode">Режим избиране</string>
<string name="remember_database_locations_summary">Запазва местоположението на хранилищата</string>
<string name="remember_keyfile_locations_title">Запомняне използваните ключове</string>
<string name="remember_keyfile_locations_summary">Запазва местоположението на ключовете</string>
<string name="show_recent_files_summary">Показва местоположението на последно използваните хранилища</string>
<string name="encryption_explanation">Алгоритъм за шифроване на цялата информация</string>
<string name="memory_usage">Използвана памет</string>
<string name="error_invalid_path">Уверете се, че пътят е правилен.</string>
<string name="error_import_app_properties">Грешка при внасяне на настройки</string>
<string name="parallelism">Паралелно изпълняване</string>
<string name="success_import_app_properties">Настройките на приложението са внесени</string>
<string name="read_only_warning">В зависимост от приложението за управление на файлове, KeePassDX може да няма права да пише в паметта на устройството.</string>
<string name="hide_broken_locations_title">Скриване на липсващи хранилища</string>
<string name="rounds_explanation">По-големият брой преобразувания дава по-добра устойчивост срещу атаки с груба сила, но може сериозно да забави зареждането изапазването.</string>
<string name="warning_sure_remove_data">Премахване на данните въпреки това?</string>
<string name="build_label">Компилация %1$s</string>
<string name="warning_permanently_delete_nodes">Безвъзвратно премахване на избраните възли?</string>
<string name="warning_database_read_only">Дайте права за писане на файла, за да бъдат запазени промените в хранилището</string>
<string name="warning_database_link_revoked">Достъпът до файла е оттеглен от приложението за управление на файлове</string>
<string name="warning_empty_password">Продължаване без парола за защита на хранилището?</string>
<string name="warning_no_encryption_key">Продължаване без ключ за шифроване?</string>
<string name="warning_empty_keyfile">Не е препоръчително да бъде добавян празен файл с ключ.</string>
<string name="warning_database_revoked">Достъпът до файла е оттеглен от приложението за управление на файлове, отворете хранилището отново.</string>
<string name="version_label">Издание %1$s</string>
<string name="list_password_generator_options_title">Знаци за парола</string>
<string name="lock_database_screen_off_title">Заключване на екрана</string>
<string name="database_data_remove_unlinked_attachments_title">Премахване на несвързани данни</string>
<string name="warning_sure_add_file">Добавяне на файла въпреки това?</string>
<string name="error_unable_merge_database_kdb">Не е възможно обединяване с хранилище във формат KBD</string>
<string name="memory_usage_explanation">Количество памет, използвана от функцията за извличане на ключове.</string>
<string name="warning_database_already_opened">Има отворено хранилище, затворете го, за да отворите друго</string>
<string name="warning_replace_file">При добавяне на този файл ще бъде заменен вече съществуващ.</string>
<string name="warning_remove_unlinked_attachment">Премахването на несвързаните данни може да намали размера на хранилището, но може да изтрие информация от разширения на KeePass.</string>
<string name="warning_database_info_changed">Информация от хранилището е променена извън приложението.</string>
<string name="warning_database_info_reloaded">При презареждане на хранилището ще бъдат изгубени местните промени.</string>
<string name="merge_success">Обединяването е завършено</string>
<string name="configure">Настройка</string>
<string name="unavailable">Недостъпно</string>
<string name="database_opened">Хранилището е отвоерно</string>
<string name="ask">Питане</string>
<string name="list_password_generator_options_summary">Задава набора от разрешени знаци за създаване на парола</string>
<string name="later">По-късно</string>
<string name="warning_empty_recycle_bin">Безвъзвратно премахване на всички възли в кошчето?</string>
<string name="parallelism_explanation">Степен на едновременно изпълняване (т.е. брой нишки), използвана от функцията за извличане на ключове.</string>
<string name="warning_password_encoding">Избягвайте да използвате в паролите знаци, които не са от кодировката на текста на хранилището (такива знаци ще бъдат превърнати в една буква).</string>
<string name="warning_file_too_big">Предполага се, че хранилищата на KeePass съдържат само малки служебни файлове (например файлове с ключове на PGP).
\n
\nАко добавите този файл, хранилището ще нарасне много и бързодействието ще намалее.</string>
<string name="database_data_remove_unlinked_attachments_summary">Премахва от хранилището прикачени файлове без връзка със запис</string>
<string name="warning_empty_keyfile_explanation">Съдържанието на файла с ключ не трябва да бъде променяно и най-добре е да съдържа случайна стойност.</string>
<string name="warning_database_info_changed_options">Обединете данните, презапишете външните промени или презаредете хранилището с последните промени.</string>
<string name="temp_advanced_unlock_timeout_summary">Време на живот на съдържанието, което се използва за отключване</string>
<string name="advanced_unlock_delete_all_key_warning">Да бъдат ли премахнати всички ключове за шифроване, свързани с разпознаването на отключване на устройството?</string>
<string name="biometric_delete_all_key_summary">Премахване на всички ключове за шифроване, свързани с разпознаването на отключване на устройството</string>
<string name="unavailable_feature_text">Тази възможност не може да бъде използвана.</string>
<string name="unavailable_feature_version">Устройството разполага с Андроид %1$s, но е необходим %2$s или по-нов.</string>
<string name="templates_group_enable_title">Използване на шаблони</string>
<string name="advanced_unlock_prompt_extract_credential_title">Разпознаване на отключване на устройството</string>
<string name="credential_before_click_advanced_unlock_button">Въведете паролата и докоснете бутона.</string>
<string name="lock_database_screen_off_summary">Заключва хранилището нколко секунди след изключване на екрана</string>
<string name="temp_advanced_unlock_enable_summary">За да се възползвате от отключване на устройството не пазете шифровано съдържание</string>
<string name="temp_advanced_unlock_timeout_title">Време на действие</string>
<string name="advanced_unlock_timeout">Времетраене на отключването на устройството</string>
<string name="recycle_bin_title">Използване на кошчето</string>
<string name="recycle_bin_summary">Премества групите и записите в групата „Кошче“ вместо да ги премахва директно</string>
<string name="advanced_unlock_prompt_store_credential_title">Отключване с устройството</string>
<string name="advanced_unlock_scanning_error">Грешка при отключване на устройството: %1$s</string>
<string name="advanced_unlock_not_recognized">Не може да бъде разпознато кога устройството е отключено</string>
<string name="advanced_unlock_prompt_not_initialized">Заявката за отключване не може да бъде подготвена.</string>
<string name="password_size_summary">Подразбирана дължина на създаваните пароли</string>
<string name="advanced_unlock_tap_delete">Докоснете, за да премахнете ключовете за отключване на устройството</string>
<string name="temp_advanced_unlock_enable_title">Временно отключване на устройството</string>
<string name="advanced_unlock_explanation_summary">За по-лесно отключване на хранилището използвайте отключване на устройството</string>
<string name="recycle_bin_group_title">Група „Кошче“</string>
<string name="templates_group_uuid_title">Група „Шаблони“</string>
<string name="advanced_unlock_prompt_extract_credential_message">Извличане на главната парола на хранилището при отключване на устройството</string>
<string name="advanced_unlock_invalid_key">Ключът за отключване на устройството не може да бъде прочетен. Премахнете го и повторете процедурата по разпознаване.</string>
<string name="advanced_unlock_keystore_warning">Това свойство на приложението ще пази шифровани данни за достъп в защитеното хранилище за ключове на устройството.
\n
\nВ зависимост реализацията на ППИ на операционната система то може да не е пълнофункционално.
\n
\nПроверете съвместимостта и степента на сигурност на хранилището за ключове при производителя на устройството или автора на инсталираната операционната система.</string>
<string name="templates_group_enable_summary">Използване на динамични шаблони за попълване на полетата на записи</string>
<string name="max_history_items_title">Максимален брой записи</string>
<string name="max_history_items_summary">Ограничаване на броя на елементите от историята на запис</string>
<string name="max_history_size_title">Максимален размер</string>
<string name="monospace_font_fields_enable_summary">Полетата използват различен шрифт за по-добра четимост на знаците</string>
<string name="magic_keyboard_explanation_summary">Включете потребителска клавиатура, която да попълва пароли и полета за удостоверяване</string>
<string name="clear_clipboard_notification_title">Изчистване при затваряне</string>
<string name="max_history_size_summary">Ограничаване на размера на историята на всеки запис</string>
<string name="keyboard_notification_entry_summary">Показване на известие, когато има достъпен запис</string>
<string name="monospace_font_fields_enable_title">Отделен шрифт за полетата</string>
<string name="enable">Включване</string>
<string name="disable">Изключване</string>
<string name="notification">Известие</string>
<string name="device_keyboard_setting_title">Настройки на клавиатурата на устройството</string>
<string name="keyboard_selection_entry_summary">При преглед на запис в KeePassDX, стойностите на Magikeyboard да бъдат попълнени с неговите данни</string>
<string name="keyboard_notification_entry_title">Известие за наличие</string>
<string name="error_disallow_no_credentials">Трябва да има зададена най-малко една парола.</string>
<string name="error_pass_match">Паролите се различават.</string>
<string name="error_string_type">Текстът не съвпада с търсения елемент.</string>
<string name="error_registration_read_only">Нов запис не може да бъде добавен в хранилище, отворено само за четене</string>
<string name="error_start_database_action">Възникна грешка при извършване на действие с хранилището.</string>
<string name="keyboard_entry_timeout_title">Време за изчакване</string>
<string name="autofill_application_id_blocklist_title">Черен списък на приложения</string>
<string name="autofill_read_only_save">В хранилище, отворено само за четене не могат да бъдат запазвани промени.</string>
<string name="error_move_group_here">Група не може да бъде преместена тук.</string>
<string name="keyboard_notification_entry_clear_close_title">Изчистване при затваряне</string>
<string name="autofill_save_search_info_summary">При ръчен избор на запис прави опит за запазване на информация от търсене за по-лесно бъдещо използване</string>
<string name="keyboard_change">Превключване на клавиатури</string>
<string name="autofill_application_id_blocklist_summary">Списък от приложения, в които автоматично попълване да не работи</string>
<string name="autofill_block">Спиране на автоматичното попълване</string>
<string name="keyboard_previous_lock_title">Заключване на хранилище</string>
<string name="error_word_reserved">Тази дума е запазена и не може да бъде използвана.</string>
<string name="error_load_database">Хранилището не може да бъде заредено.</string>
<string name="error_create_database_file">С тази парола и ключ хранилище не може да бъде създадено.</string>
<string name="error_duplicate_file">Файл с тези данни съществува.</string>
<string name="error_file_to_big">Файлът, който изпращате е твърде голям.</string>
<string name="keyboard_save_search_info_title">Запазване на обща информация</string>
<string name="keyboard_notification_entry_clear_close_summary">Затваря хранилището при затваряне на известието</string>
<string name="keyboard_auto_go_action_summary">Действие на бутона „Напред“ след докоснат бутон „Поле“</string>
<string name="keyboard_previous_database_credentials_summary">Автоматично превключва предната клавиатура на екрана за удостоверяване на хранилището</string>
<string name="error_wrong_length">Полето „Дължина“ трябва да има положителна целочислена стойност.</string>
<string name="error_autofill_enable_service">Услугата за автоматично попълване не може да бъде включена.</string>
<string name="error_move_entry_here">Запис не може да бъде преместен тук.</string>
<string name="error_otp_digits">Кодът за достъп трябва да съдържа от %1$d до %2$d цифри.</string>
<string name="keyboard_key_vibrate_title">Тактилна обратна връзка</string>
<string name="error_copy_entry_here">Запис не може да бъде копиран тук.</string>
<string name="error_pass_gen_type">Изберете един или повече вида знаци.</string>
<string name="error_copy_group_here">Група не може да бъде копирана тук.</string>
<string name="error_create_database">Хранилището не може да бъде създадено.</string>
<string name="error_otp_counter">Броячът трябва да бъде в интервала от %1$d до %2$d.</string>
<string name="keyboard_previous_fill_in_title">Превключване назад</string>
<string name="keyboard_previous_search_summary">Автоматично превключва предната клавиатура на екрана за търсене</string>
<string name="keyboard_previous_fill_in_summary">Автоматично превключва предната клавиатура след докосване на бутона за автоматично действие</string>
<string name="autofill_block_restart">Рестартирайте приложението, съдържащо формуляра, за да влезе в сила ограничението.</string>
<string name="autofill_inline_suggestions_keyboard">Предложения за автом. попълване са добавени.</string>
<string name="error_rounds_too_large">Полето „Брой преобразувания“ има твърде голяма стойност. Променена е на 2147483648.</string>
<string name="error_string_key">Всяко поле трябва да има наименование.</string>
<string name="error_label_exists">Такъв етикет вече съществува.</string>
<string name="error_save_database">Хранилището не може да бъде запазено.</string>
<string name="error_otp_period">Периодът трябва да бъде в интервала от %1$d до %2$d секунди.</string>
<string name="autofill_inline_suggestions_summary">Опит за показване предложения за автоматично попълване от съвместимата клавиатура</string>
<string name="keyboard_save_search_info_summary">При ръчен избор на запис прави опит за запазване на обща информация за по-лесно бъдещо използване</string>
<string name="autofill_ask_to_save_data_title">Питане за запазване на данни</string>
<string name="autofill_ask_to_save_data_summary">Искане на разрешение за запазване на информация след попълване на формуляр</string>
<string name="autofill_web_domain_blocklist_title">Черен списък на домейни</string>
<string name="error_response_already_provided">Отговор вече е получен.</string>
<string name="autofill_web_domain_blocklist_summary">Списък от домейни, на които автоматично попълване да не работи</string>
<string name="error_out_of_memory">Недостатъчно памет за работа с хранилището.</string>
<string name="error_XML_malformed">Повреден XML.</string>
<string name="error_otp_secret_key">Тайният ключ трябва да бъде във формат Base32.</string>
<string name="error_field_name_already_exists">Поле с такова име съществува.</string>
<string name="error_no_response_from_challenge">Не може да бъде получен отговор на предизвикването.</string>
<string name="error_challenge_already_requested">Предизвикване вече е заявено.</string>
<string name="permission">Разрешение</string>
<string name="keyboard_entry_timeout_summary">Изчакване, след което записът се изчиства от клавиатурата</string>
<string name="keyboard_key_sound_title">Звукова обратна връзка</string>
<string name="keyboard_previous_search_title">Екран за търсене</string>
<string name="keyboard_previous_lock_summary">Автоматично превключва предната клавиатура след заключване на хранилището</string>
<string name="autofill_inline_suggestions_title">Предложения на място</string>
<string name="autofill_manual_selection_title">Ръчен избор</string>
<string name="autofill_manual_selection_summary">Показване на възможните записи от хранилището, от които потребителят да избере</string>
<string name="autofill_save_search_info_title">Запазване на информация от търсене</string>
<string name="biometric_unlock_enable_title">Биометрично отключване</string>
<string name="biometric_auto_open_prompt_title">Питане при автоматично отключване</string>
<string name="configure_biometric">Не са регистрирани биометрични или други способи за отключване на устройството.</string>
<string name="biometric_security_update_required">Необходимо е обновяване на биометричната система за сигурност.</string>
<string name="encrypted_value_stored">Шифрованата парола е запазена</string>
<string name="keystore_not_accessible">Хранилището за ключове не е подготвено.</string>
<string name="clipboard">Междинна памет</string>
<string name="device_credential_unlock_enable_title">Отключване на устройството</string>
<string name="error_database_uri_null">Идентификаторът на хранилището не може да бъде получен.</string>
<string name="error_remove_file">Грешка при премахване на файла.</string>
<string name="error_upload_file">Грешка при изпращане на файла.</string>
<string name="error_cancel_by_user">Отказано от потребителя.</string>
<string name="error_driver_required">За %1$s е необходим драйвер.</string>
<string name="error_location_unknown">Мястото на хранилището е неизвестно, действието не може да бъде извършено.</string>
<string name="warning_copy_permission">Разрешението е необходимо за показване на известия за междинната памет.</string>
<string name="unlock_and_link_biometric">Настройка отключване с устройството</string>
<string name="clipboard_warning">При неуспешно автоматично изчистване на междинната памет, изчистете историята ѝ ръчно.</string>
<string name="clipboard_notifications_title">Известия от междинната памет</string>
<string name="clipboard_notifications_summary">Известия от междинната памет за копиране на полета при преглед на запис</string>
<string name="biometric_unlock_enable_summary">Дава възможност за отключване на хранилището посредством биометрични данни</string>
<string name="device_credential_unlock_enable_summary">Дава възможност за отключване на хранилището при отключване на устройството</string>
<string name="biometric_auto_open_prompt_summary">Автоматична заявка за отключване на устройството ако хранилището се отключва с устройството</string>
<string name="allow_copy_password_summary">Разрешава копиране на паролите и защитените полета от записите в междинната памет</string>
<string name="error_rebuild_list">Списъкът не може да бъде изграден отново.</string>
<string name="error_otp_type">Формулярът не разпознава този вид OTP и може да не създава правилни кодове за достъп.</string>
<string name="warning_keyfile_integrity">Отпечатъкът от файла не е сигурен, защото Андроид може да променя данните в движение. Променете разширението на файла на .bin, за бъде невредим.</string>
<string name="allow_copy_password_title">Доверяване на междинната памет</string>
<string name="warning_exact_alarm">Приложението няма права за използване на точен будилник. В резултат на това дейностите, които зависят от него няма да се изпълняват на време.</string>
<string name="clear_clipboard_notification_summary">Заключва хранилището при затваряне на известието или изтече времето за изчакване на междинната памет</string>
<string name="warning_database_notification_permission">Разрешението дава възможност за показване на състоянието на хранилището, както и да го заключвате с леснодостъпен бутон.
\n
\nАко не предоставите това разрешение, отвореното във фонов режим хранилище няма да бъде видимо, ако друго приложение се показва в момента.</string>
<string name="style_name_forest">Горска</string>
<string name="style_name_divine">Божествена</string>
<string name="style_name_classic">Класическа</string>
<string name="style_name_simple">Обикновена</string>
<string name="style_name_moon">Лунна</string>
<string name="style_name_sun">Слънчева</string>
<string name="style_name_reply">Отговор</string>
<string name="style_name_kunzite">Авторска</string>
<string name="style_name_follow_system">Като системната</string>
<string name="style_name_light">Светла</string>
<string name="style_name_dark">Тъмна</string>
<string name="warning_database_info_changed_options_read_only">Презаредете последните промени в хранилището.</string>
<string name="generate_keyfile">Създаване на файл с ключ</string>
<string name="nodes">Възли</string>
</resources>

View File

@@ -30,18 +30,19 @@
<string name="application">Aplicació</string>
<string name="menu_app_settings">Configuració de l\'aplicació</string>
<string name="brackets">Parèntesis</string>
<string name="file_manager_install_description">Un gestor de fitxers que accepta les intencions ACTION_CREATE_DOCUMENT i ACTION_OPEN_DOCUMENT, que us calen per a crear, obrir i desar fitxers de base de dades.</string>
<string name="clipboard_cleared">Porta-retalls netejat.</string>
<string name="file_manager_install_description">Es requereix un gestor de fitxers que accepti les intencions ACTION_CREATE_DOCUMENT i ACTION_OPEN_DOCUMENT per a crear, obrir i desar fitxers de base de dades.</string>
<string name="clipboard_cleared">Porta-retalls netejat</string>
<string name="clipboard_timeout">Temps d\'espera del porta-retalls</string>
<string name="clipboard_timeout_summary">Temps abans de netejar el porta-retalls (si el teu dispositiu ho suporta)</string>
<string name="select_to_copy">Selecciona per copiar %1$s al porta-retalls</string>
<string name="retrieving_db_key">Es recupera la clau de base de dades…</string>
<string name="database">Base de dades</string>
<string name="decrypting_db">Es desxifra el contingut de la base de dades…</string>
<string name="decrypting_db">Desxifrant la base de dades…</string>
<string name="default_checkbox">Utilitza com a base de dades per defecte</string>
<string name="digits">Dígits</string>
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft ve sense cap mena de garantia. Això és programari lliure, i pots redistribuir-lo sota els termes de la llicència GPL versió 3 o posterior.</string>
<string name="select_database_file">Obri una base de dades existent</string>
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft és &lt;strong&gt; programari lliure &lt;/strong&gt; i &lt;strong&gt;sense anuncis&lt;/strong&gt;.
\nEs proporciona tal com està, sota una llicència &lt;strong&gt;GPLv3&lt;/strong&gt;, sense cap garantia.</string>
<string name="select_database_file">Obre una caixa forta existent</string>
<string name="entry_accessed">Accedida</string>
<string name="entry_cancel">Cancel·la</string>
<string name="entry_notes">Comentaris</string>
@@ -97,11 +98,11 @@
<string name="menu_open">Obre</string>
<string name="menu_search">Cerca</string>
<string name="menu_showpass">Mostra la contrasenya</string>
<string name="menu_url">Ves a la URL</string>
<string name="menu_url">Ves a l\'URL</string>
<string name="minus">Menys</string>
<string name="never">Mai</string>
<string name="no_results">Cap resultat de cerca</string>
<string name="no_url_handler">Instal·leu un navegador web per a obri aquesta URL</string>
<string name="no_url_handler">Instal·leu un navegador web per a obrir aquest URL.</string>
<string name="progress_create">Creant nova base de dades…</string>
<string name="progress_title">Treballant…</string>
<string name="content_description_remove_from_list">Elimina</string>
@@ -139,28 +140,28 @@
<string name="database_default_username_title">Nom d\'usuari per defecte</string>
<string name="database_description_title">Descripció de la base de dades</string>
<string name="database_name_title">Nom de la base de dades</string>
<string name="clear_clipboard_notification_title">Neteja en tancar</string>
<string name="clear_clipboard_notification_title">Neteja al tancar</string>
<string name="disable">Desactiva</string>
<string name="enable">Activa</string>
<string name="settings_database_force_changing_master_key_summary">Obliga a canviar la contrasenya mestra (dies)</string>
<string name="settings_database_force_changing_master_key_summary">Força a canviar la clau mestra (dies)</string>
<string name="settings_database_force_changing_master_key_title">Força la renovació</string>
<string name="max_history_size_title">Mida màxima</string>
<string name="max_history_items_title">Nombre màxim</string>
<string name="recycle_bin_group_title">Grup paperera</string>
<string name="recycle_bin_summary">Mou els grups i les entrades al grup \"paperera\" abans de suprimir-los</string>
<string name="recycle_bin_title">Ús de la paperera</string>
<string name="database_data_compression_summary">La compressió de les dades redueix la mida de la base de dades.</string>
<string name="database_data_compression_summary">La compressió de les dades redueix la mida de la base de dades</string>
<string name="database_data_compression_title">Compressió de les dades</string>
<string name="assign_master_key">Assigna una contrasenya mestra</string>
<string name="path">Camí</string>
<string name="file_name">Nom de fitxer</string>
<string name="unavailable_feature_version">La vostra versió d\'Android (%1$s) no compleix els requeriments; la versió mínima és %2$s.</string>
<string name="unavailable_feature_version">El dispositiu està executant Android %1$s, però es necessita %2$s o superior.</string>
<string name="biometric_delete_all_key_title">Suprimeix les claus de xifrat</string>
<string name="lock_database_show_button_summary">Mostra el botó de blocar en la interfície d\'usuari</string>
<string name="lock_database_show_button_title">Mostra el botó de blocar</string>
<string name="lock_database_back_root_summary">Bloca la base de dades quan l\'usuari toca el botó enrere en la pantalla principal</string>
<string name="lock_database_back_root_title">Premeu \'enrere\' per a blocar</string>
<string name="lock_database_screen_off_summary">Bloca la base de dades quan la pantalla està desactivada</string>
<string name="lock_database_screen_off_summary">Bloqueja la base de dades després d\'uns segons de desactivar la pantalla</string>
<string name="lock">Bloca</string>
<string name="clipboard_warning">Si la supressió automàtica del porta-retalls falla, suprimiu-ne la història manualment.</string>
<string name="clipboard_notifications_title">Notificacions del porta-retalls</string>
@@ -176,7 +177,7 @@
<string name="autofill">Autocompleta</string>
<string name="general">General</string>
<string name="biometric">Biomètric</string>
<string name="menu_appearance_settings">Apariència</string>
<string name="menu_appearance_settings">Aparença</string>
<string name="database_history">Història</string>
<string name="encrypted_value_stored">Contrasenya xifrada desada</string>
<string name="warning_permanently_delete_nodes">Voleu suprimir definitivament els nodes seleccionats\?</string>
@@ -197,9 +198,9 @@
<string name="hide_broken_locations_summary">Amaga els enllaços trencats en la llista de bases de dades recents</string>
<string name="show_recent_files_summary">Mostra la ubicació de les bases de dades recents</string>
<string name="show_recent_files_title">Mostra els fitxers recents</string>
<string name="remember_keyfile_locations_title">Desa la ubicació dels fitxers de claus</string>
<string name="remember_database_locations_summary">Recorda la ubicació de les bases de dades</string>
<string name="remember_database_locations_title">Desa la ubicació de les bases de dades</string>
<string name="remember_keyfile_locations_title">Recorda la ubicació dels fitxers de claus</string>
<string name="remember_database_locations_summary">Fes un seguiment d\'on s\'emmagatzemen les bases de dades</string>
<string name="remember_database_locations_title">Recorda l\'ubicació de les bases de dades</string>
<string name="selection_mode">Mode de selecció</string>
<string name="contains_duplicate_uuid_procedure">Voleu resoldre el problema creant nous UUIDs per als duplicats per a continuar\?</string>
<string name="contains_duplicate_uuid">La base de dades conté UUIDs duplicats.</string>
@@ -208,30 +209,30 @@
<string name="protection">Protecció</string>
<string name="auto_focus_search_summary">Sol·licita una cerca quan s\'obre una base de dades</string>
<string name="auto_focus_search_title">Cerca ràpida</string>
<string name="create_keepass_file">Crea una nova base de dades</string>
<string name="create_keepass_file">Crea una caixa forta</string>
<string name="menu_delete_entry_history">Suprimeix la història</string>
<string name="menu_restore_entry_history">Restaura la història</string>
<string name="menu_empty_recycle_bin">Buida la paperera</string>
<string name="menu_open_file_read_and_write">Modificable</string>
<string name="menu_file_selection_read_only">Protegit contra escriptura</string>
<string name="menu_save_database">Desa la base de dades</string>
<string name="menu_save_database">Desa les dades</string>
<string name="menu_cancel">Cancel·lar</string>
<string name="menu_paste">Enganxar</string>
<string name="menu_move">Moure</string>
<string name="menu_copy">Copiar</string>
<string name="menu_master_key_settings">Paràmetres de la contrasenya mestra</string>
<string name="menu_security_settings">Paràmetres de seguretat</string>
<string name="menu_advanced_unlock_settings">Desblocatge avançat</string>
<string name="menu_advanced_unlock_settings">Desblocatge de dispositiu</string>
<string name="menu_form_filling_settings">Emplenat de formularis</string>
<string name="copy_field">Còpia de %1$s</string>
<string name="creating_database">Es crea la base de dades…</string>
<string name="list_groups_show_number_entries_summary">Mostra el nombre d\'entrades en un grup</string>
<string name="list_groups_show_number_entries_title">Mostra el nombre d\'entades</string>
<string name="list_entries_show_username_summary">Mostra els noms d\'usuari en les llistes d\'entrades</string>
<string name="list_entries_show_username_summary">Mostra els noms d\'usuari a les llistes d\'entrades</string>
<string name="list_entries_show_username_title">Mostra noms d\'usuari</string>
<string name="keyfile_is_empty">El fitxer de clau és buit.</string>
<string name="invalid_algorithm">Algorisme incorrecte.</string>
<string name="file_not_found_content">No s\'ha trobat el fitxer. Mireu de reobrir-lo des de l\'explorador de fitxers.</string>
<string name="file_not_found_content">No s\'ha trobat el fitxer. Mireu de tornar-lo a obrir des de l\'explorador de fitxers.</string>
<string name="field_value">Valor del camp</string>
<string name="field_name">Nom del camp</string>
<string name="error_otp_digits">El testimoni ha de tenir entre %1$d i %2$d dígits.</string>
@@ -244,7 +245,7 @@
<string name="error_copy_entry_here">No és possible copiar cap entrada aquí.</string>
<string name="error_move_entry_here">No és possible moure cap entrada aquí.</string>
<string name="error_label_exists">Aquesta etiqueta ja existeix.</string>
<string name="error_load_database">No sha pogut carregar la vostra base de dades.</string>
<string name="error_load_database">No sha pogut carregar la base de dades.</string>
<string name="entry_otp">OTP</string>
<string name="otp_algorithm">Algorisme</string>
<string name="otp_digits">Dígits</string>
@@ -284,7 +285,7 @@
<string name="error_field_name_already_exists">El nom del camp ja existeix.</string>
<string name="error_registration_read_only">No es permet desar un element nou en una base de dades de només lectura</string>
<string name="error_string_type">Aquest text no coincideix amb l\'element sol·licitat.</string>
<string name="error_otp_type">L\'OTP existent no està reconegut per aquest formulari, la seva validació ja no pot generar correctament el token.</string>
<string name="error_otp_type">L\'OTP existent no està reconegut per aquest formulari, la seva validació ja no pot generar correctament el testimoni.</string>
<string name="error_create_database_file">No sha pogut crear una base de dades amb aquesta contrasenya i fitxer de clau.</string>
<string name="error_autofill_enable_service">No sha pogut habilitar el servei de compleció automàtica.</string>
<string name="content_description_node_children">Nodes fill</string>
@@ -294,7 +295,7 @@
<string name="warning_sure_add_file">Voleu afegir el fitxer igualment\?</string>
<string name="warning_empty_password">Voleu continuar sense la protecció contra desblocatge amb contrasenya\?</string>
<string name="error_move_group_here">No és possible moure cap grup aquí.</string>
<string name="error_load_database_KDF_memory">No sha pogut carregar la clau. Proveu de reduir l«Ús de memòria» del KDF.</string>
<string name="error_load_database_KDF_memory">No sha pogut carregar la clau. Proveu de reduir l\'«Ús de memòria» del KDF.</string>
<string name="error_word_reserved">Aquesta paraula està reservada i no es pot usar.</string>
<string name="error_invalid_OTP">El secret OTP no és vàlid.</string>
<string name="education_read_only_title">Protecció contra escriptura de la base de dades</string>
@@ -304,14 +305,14 @@
<string name="html_text_dev_feature_contibute">En &lt;strong&gt;col·laborar-hi&lt;/strong&gt;,</string>
<string name="content_description_keyfile_checkbox">Casella del fitxer de la clau</string>
<string name="content_description_password_checkbox">Casella de la contrasenya</string>
<string name="content_description_otp_information">Informació de la contrasenya dun sol ús</string>
<string name="content_description_credentials_information">Informació de les dades daccés</string>
<string name="content_description_otp_information">Informació de contrasenya d\'únic ús</string>
<string name="content_description_credentials_information">Informació de credencials</string>
<string name="content_description_add_item">Afegeix un element</string>
<string name="education_lock_title">Bloca la base de dades</string>
<string name="html_text_feature_generosity">Aquest &lt;strong&gt;estil visual&lt;/strong&gt; és disponible gràcies a la vostra generositat.</string>
<string name="html_text_dev_feature_upgrade">No us oblideu de mantenir laplicació actualitzada instal·lant les versions noves.</string>
<string name="icon_section_standard">Estàndard</string>
<string name="show_uuid_title">Mostra lUUID</string>
<string name="show_uuid_title">Mostra l\'UUID</string>
<string name="hide_expired_entries_summary">No es mostren les entrades expirades</string>
<string name="hide_expired_entries_title">Amaga les entrades expirades</string>
<string name="contribute">Contribuïu-hi</string>
@@ -326,4 +327,341 @@
<string name="icon_pack_choose_summary">El paquet dicones que sutilitza a laplicació</string>
<string name="icon_pack_choose_title">Paquet dicones</string>
<string name="icon_section_custom">Personalitzat</string>
<string name="template_group_name">Plantilles</string>
<string name="error_unable_merge_database_kdb">No es pot fusionar d\'una base de dades V1.</string>
<string name="auto_type">Auto-Escriptura</string>
<string name="import_app_properties_title">Importar configuració de l\'aplicació</string>
<string name="card_verification_value">CVV</string>
<string name="inherited">Heretar</string>
<string name="remember_hardware_key_title">Recorda les claus físiques</string>
<string name="consider_chars_filter">Considera caràcters</string>
<string name="exclude_ambiguous_chars">Exclou caràcters ambigus</string>
<string name="unlock">Desbloqueja</string>
<string name="bank">Banc</string>
<string name="compression_none">Cap</string>
<string name="info">Info</string>
<string name="content_description_entry_background_color">Color de fons d\'entrada</string>
<string name="error_empty_key">La clau no pot ser buida.</string>
<string name="custom_data">Dades personalitzades</string>
<string name="tags">Etiquetes</string>
<string name="place_of_issue">Lloc d\'expedició</string>
<string name="style_brightness_summary">Escull tema clar o fosc</string>
<string name="hardware_key">Clau física</string>
<string name="registration_mode">Mode de registre</string>
<string name="ignore_chars_filter">Ignora caràcters</string>
<string name="ask">Pregunta</string>
<string name="searchable">Cercable</string>
<string name="html_text_dev_feature_thanks">Moltes gràcies per la teva contribució.</string>
<string name="menu_form_filling_settings_summary">Teclat, autoemplena, porta-retalls</string>
<string name="export_app_properties_title">Exporta la configuració de l\'aplicació</string>
<string name="email">Email</string>
<string name="content_description_nav_header">Títol de navegació</string>
<string name="navigation_drawer_close">Tancar calaix de navegació</string>
<string name="properties">Propietats</string>
<string name="clear_clipboard_notification_summary">Bloca la base de dades quan la duració del porta-retalls caduca o la notificació es tanca un cop s\'ha començat a utilitzar</string>
<string name="html_about_privacy">&lt;strong&gt;No s\'agafa cap dada d\'usuari&lt;/strong&gt;, aquesta aplicació no connecta a cap servidor, només treballa localment i respecta la privacitat dels usuaris en la seva totalitat.</string>
<string name="notification">Notificació</string>
<string name="content_description_entry_foreground_color">Color de primer pla d\'entrada</string>
<string name="advanced_unlock">Desbloqueja dispositiu</string>
<string name="template">Plantilla</string>
<string name="title_case">Primera Majúscula</string>
<string name="navigation_drawer_open">El calaix de navegació està obert</string>
<string name="max_history_size_summary">Limita la mida de l\'historial per entrada</string>
<string name="success_export_app_properties">Configuració de l\'aplicació exportada</string>
<string name="error_export_app_properties">Error a l\'exportar la configuració de l\'aplicació</string>
<string name="type">Tipus</string>
<string name="content_description_hardware_key_checkbox">Casella de clau física</string>
<string name="settings_database_recommend_changing_master_key_title">Recomanar renovació</string>
<string name="name">Nom</string>
<string name="lower_case">minúscula</string>
<string name="import_app_properties_summary">Selecciona un fitxer per importar la configuració de l\'aplicació</string>
<string name="monospace_font_fields_enable_summary">Canvia la font usada en els camps per una millor visibilitat dels caràcters</string>
<string name="html_text_dev_feature_work_hard">Estem treballant de valent per implementar aquesta característica ràpidament.</string>
<string name="autofill_close_database_summary">Tanca la base de dades després d\'auto-completar</string>
<string name="screenshot_mode_banner_text">Mode captura de pantalla</string>
<string name="application_appearance">Interfície</string>
<string name="error_import_app_properties">Error a l\'importar la configuració de l\'aplicació</string>
<string name="case_sensitive">Sensible a majúscules i minúscules</string>
<string name="error_location_unknown">Localització de la base de dades desconeguda, l\'acció no es pot fer.</string>
<string name="membership">Pertinença</string>
<string name="content_description_passphrase_word_count">Nombre de paraules de la contrasenya</string>
<string name="data">Dada</string>
<string name="version">Versió</string>
<string name="regex">Expressió regular</string>
<string name="number">Número</string>
<string name="other">Altre</string>
<string name="account">Compte</string>
<string name="allow_copy_password_title">Confia en el porta-retalls</string>
<string name="holder">Titular</string>
<string name="expired">Expirat</string>
<string name="date_of_issue">Data d\'expedició</string>
<string name="cryptocurrency">Cartera de cryptomoneda</string>
<string name="settings_database_force_changing_master_key_next_time_title">Força renovació el pròxim cop</string>
<string name="waiting_challenge_request">Esperant la sol·licitud de desafiament…</string>
<string name="search_filters">Filtres de cerca</string>
<string name="current_group">Grup actual</string>
<string name="allow_no_password_title">No permetis clau mestra</string>
<string name="public_key">Clau pública</string>
<string name="content_description_repeat_toggle_password_visibility">Repetir canvi de visibilitat de contrasenya</string>
<string name="auto_type_sequence">Seqüència d\'Auto-Escriptura</string>
<string name="personal_identification_number">PIN</string>
<string name="word_separator">Separador</string>
<string name="compression_gzip">Gzip</string>
<string name="waiting_challenge_response">Esperant la resposta de desafiament…</string>
<string name="bank_name">Nom del banc</string>
<string name="wireless">Wi-Fi</string>
<string name="set_autofill_service_title">Estableix el servei d\'emplenament automàtic predeterminat</string>
<string name="compression">Compressió</string>
<string name="id_card">Targeta d\'identificació</string>
<string name="error_hardware_key_unsupported">Clau física no suportada.</string>
<string name="menu_advanced_unlock_settings_summary">Biometria, credencial de dispositiu</string>
<string name="standard">Estàndard</string>
<string name="error_XML_malformed">XML mal format.</string>
<string name="remember_hardware_key_summary">Recorda les claus físiques que s\'han usat</string>
<string name="token">Testimoni</string>
<string name="debit_credit_card">Targeta de Dèbit / Crèdit</string>
<string name="description_app_properties">Propietats de KeePassDX per administrar la configuració de l\'aplicació</string>
<string name="menu_save_copy_to">Desar còpia a …</string>
<string name="ssid">SSID</string>
<string name="allow_copy_password_warning">Alerta: El porta-retalls és compartit per totes les aplicacions. Si es copien dades sensibles, altres programes poden veure-ho.</string>
<string name="private_key">Clau privada</string>
<string name="export_app_properties_summary">Crea un fitxer per exportar la configuració de l\'aplicació</string>
<string name="permission">Permís</string>
<string name="menu_reload_database">Recarregar dada</string>
<string name="international_bank_account_number">IBAN</string>
<string name="menu_merge_from">Fusionar desde …</string>
<string name="content_description_database_color">Color de la base de dades</string>
<string name="character_count">Comptador de caràcters: %1$d</string>
<string name="email_address">Adreça electrònica</string>
<string name="merge_success">Fusió completada satisfactòriament</string>
<string name="seed">Llavor</string>
<string name="settings_database_recommend_changing_master_key_summary">Recomanar canviar la clau mestra (dies)</string>
<string name="autofill_close_database_title">Tanca la base de dades</string>
<string name="bank_identifier_code">SWIFT / BIC</string>
<string name="upper_case">MAJÚSCULA</string>
<string name="monospace_font_fields_enable_title">Tipografia de camp</string>
<string name="corrupted_file">Fitxer corrupte.</string>
<string name="error_no_hardware_key">Selecciona clau física.</string>
<string name="settings_database_force_changing_master_key_next_time_summary">Requereix canviar la clau mestra el pròxim cop (un cop)</string>
<string name="allow_copy_password_summary">Permet copiar la clau i els camps protegits d\'una entrada al porta-retalls</string>
<string name="success_import_app_properties">Configuració de l\'aplicació importada</string>
<string name="passphrase">Contrasenya</string>
<string name="colorize_password_title">Acoloreix les contrasenyes</string>
<string name="colorize_password_summary">Acoloreix les contrasenyes per tipus</string>
<string name="error_remove_file">S\'ha produït un error en suprimir les dades del fitxer.</string>
<string name="error_start_database_action">S\'ha produït un error en realitzar una acció a la base de dades.</string>
<string name="error_response_already_provided">Ja s\'ha proveït la resposta.</string>
<string name="show_otp_token_title">Mostra el testimoni OTP</string>
<string name="error_no_response_from_challenge">No s\'ha pogut obtenir la resposta del desafiament.</string>
<string name="error_upload_file">S\'ha produït un error en pujar les dades del fitxer.</string>
<string name="error_duplicate_file">Les dades del fitxer ja existeixen.</string>
<string name="hint_icon_name">Nom de la icona</string>
<string name="advanced_unlock_prompt_store_credential_message">Us haureu de recordar de la credencial principal de la caixa forta en el cas que feu servir el reconeixement del dispositiu pel desbloqueig.</string>
<string name="secure_note">Nota segura</string>
<string name="error_file_to_big">El fitxer que esteu intentant pujar és massa gros.</string>
<string name="error_challenge_already_requested">El desafiament ja s\'ha sol·licitat</string>
<string name="error_cancel_by_user">S\'ha cancel·lat per l\'usuari.</string>
<string name="error_driver_required">Es requereix un controlador per %1$s.</string>
<string name="warning_empty_recycle_bin">Voleu suprimir permanentment tots els nodes de la paperera de reciclatge?</string>
<string name="warning_file_too_big">Se suposa que una base de dades KeePass només conté petits fitxers d\'utilitat (com ara fitxers de claus PGP).
\n
\nAmb aquesta pujada, la base de dades pot ser molt gran i afectar el rendiment.</string>
<string name="biometric_delete_all_key_summary">Suprimeix totes les claus de xifratge relacionades amb el reconeixement de desbloqueig del dispositiu</string>
<string name="database_data_remove_unlinked_attachments_title">Elimina les dades no enllaçades</string>
<string name="menu_database_settings_summary">Metadades, paperera de reciclatge, plantilles, historial</string>
<string name="encryption_explanation">Algorisme de xifratge de la base de dades utilitzat per a totes les dades</string>
<string name="delete_entered_password_summary">Suprimeix la contrasenya introduïda després d\'un intent de connexió a una base de dades</string>
<string name="enable_read_only_title">Protegit contra l\'escriptura</string>
<string name="enable_read_only_summary">Obre la base de dades en mode només de lectura per defecte</string>
<string name="enable_screenshot_mode_summary">Permet que les aplicacions de tercers gravin o facin captures de pantalla de l\'aplicació</string>
<string name="enable_education_screens_summary">Ressalta els elements per saber com funciona l\'aplicació</string>
<string name="reset_education_screens_title">Reinicia els consells educatius</string>
<string name="enable_education_screens_title">Consells educatius</string>
<string name="education_new_node_title">Afegeix elements a la base de dades</string>
<string name="education_search_summary">Introduïu el títol, el nom d\'usuari o el contingut d\'altres camps per recuperar les contrasenyes.</string>
<string name="education_advanced_unlock_title">Desbloqueig de la base de dades dels dispositius</string>
<string name="autofill_save_search_info_title">Desa la informació de cerca</string>
<string name="education_entry_edit_summary">Editeu l\'entrada amb camps personalitzats. Les dades del fons es poden referenciar entre diferents camps d\'entrada.</string>
<string name="education_generate_password_title">Crea una contrasenya forta</string>
<string name="education_generate_password_summary">Genereu una contrasenya forta per associar-la a l\'entrada, definiu-la fàcilment segons els criteris del formulari i no oblideu la contrasenya segura.</string>
<string name="education_entry_new_field_summary">Registreu un camp addicional, afegiu un valor i, opcionalment, protegiu-lo.</string>
<string name="education_add_attachment_summary">Pengeu un adjunt a la vostra entrada per a desar dades externes importants.</string>
<string name="download_initialization">S\'està inicialitzant…</string>
<string name="education_sort_title">Ordenació d\'elements</string>
<string name="education_sort_summary">Trieu com s\'ordenen les entrades i els grups.</string>
<string name="entropy_high">Entropia: alta</string>
<string name="entropy_calculate">Entropia: Calcula…</string>
<string name="warning_database_revoked">S\'ha revocat l\'accés al fitxer pel gestor de fitxers, tanqueu la base de dades i torneu-la a obrir des de la seva ubicació.</string>
<string name="warning_copy_permission">Cal el permís de notificació per a utilitzar la característica de notificació del porta-retalls.</string>
<string name="device_credential">Credencial del dispositiu</string>
<string name="autofill_web_domain_blocklist_summary">Llista que impedeix l\'emplenament automàtic de determinats dominis web</string>
<string name="autofill_block">Bloqueja l\'emplenament automàtic</string>
<string name="biometric_auto_open_prompt_title">Obre la petició automàticament</string>
<string name="keyboard_notification_entry_summary">Mostra una notificació quan hi hagi una entrada disponible</string>
<string name="keyboard_previous_database_credentials_title">Pantalla de credencials de la base de dades</string>
<string name="keyboard_previous_database_credentials_summary">Torna automàticament al teclat anterior a la pantalla de credencials de la base de dades</string>
<string name="back_to_previous_keyboard">Torna al teclat anterior</string>
<string name="autofill_inline_suggestions_summary">Intenta mostrar els suggeriments d\'emplenament automàtic directament des d\'un teclat compatible</string>
<string name="warning_database_already_opened">Ja hi ha oberta una base de dades, tanqueu-la primer abans d\'obrir-ne una de nova</string>
<string name="build_label">Construeix 2%1$s</string>
<string name="advanced_unlock_prompt_extract_credential_title">Reconeixement de desbloqueig del dispositiu</string>
<string name="clipboard_explanation_summary">Copia els camps d\'entrada utilitzant el porta-retalls del dispositiu</string>
<string name="temp_advanced_unlock_enable_title">Desbloqueig temporal del dispositiu</string>
<string name="temp_advanced_unlock_enable_summary">No emmagatzemeu cap contingut xifrat per utilitzar el desbloqueig del dispositiu</string>
<string name="database_data_remove_unlinked_attachments_summary">Elimina els adjunts continguts a la base de dades però no vinculats a una entrada</string>
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
<string name="keyboard_selection_entry_title">Selecció d\'entrada</string>
<string name="keyboard_selection_entry_summary">Quan es visualitzi una entrada a KeePassDX, emplena el Magikeyboard amb aquesta entrada</string>
<string name="keyboard_notification_entry_clear_close_title">Neteja en tancar</string>
<string name="keyboard_entry_timeout_summary">Temps d\'espera per netejar l\'entrada del teclat</string>
<string name="keyboard_keys_category">Tecles</string>
<string name="keyboard_previous_fill_in_title">Torna enrere</string>
<string name="autofill_manual_selection_title">Selecció manual</string>
<string name="autofill_application_id_blocklist_summary">Llista que impedeix l\'emplenament automàtic en determinades aplicacions</string>
<string name="education_search_title">Cerca a través de les entrades</string>
<string name="menu_merge_database">Fusiona les dades</string>
<string name="menu_keystore_remove_key">Suprimeix la clau de desbloqueig del dispositiu</string>
<string name="warning_password_encoding">Eviteu els caràcters de contrasenya fora del format de codificació de text en el fitxer de base de dades (els caràcters no reconeguts es converteixen a la mateixa lletra).</string>
<string name="warning_database_read_only">Concedeix accés d\'escriptura al fitxer per a desar els canvis a la base de dades</string>
<string name="warning_database_info_changed_options">Fusiona les dades, sobreescriu les modificacions externes desant la base de dades o torna-la a carregar amb els últims canvis.</string>
<string name="warning_database_info_reloaded">En tornar a carregar la base de dades se suprimiran les dades modificades localment.</string>
<string name="advanced_unlock_invalid_key">No es pot llegir la clau de desbloqueig del dispositiu. Si us plau, suprimiu-la i repetiu el procediment de reconeixement de desbloqueig.</string>
<string name="advanced_unlock_not_recognized">No s\'ha pogut reconèixer l\'empremta digital per desbloquejar el dispositiu</string>
<string name="autofill_select_entry">Selecciona una entrada…</string>
<string name="advanced_unlock_tap_delete">Toca per suprimir les claus de desbloqueig del dispositiu</string>
<string name="temp_advanced_unlock_timeout_title">Venciment del desbloqueig del dispositiu</string>
<string name="temp_advanced_unlock_timeout_summary">Durada de l\'ús del desbloqueig del dispositiu abans de suprimir el seu contingut</string>
<string name="advanced_unlock_timeout">Temps d\'espera per desbloquejar el dispositiu</string>
<string name="database_custom_color_title">Color personalitzat de la base de dades</string>
<string name="database_version_title">Versió de la base de dades</string>
<string name="text_appearance">Text</string>
<string name="keyboard_notification_entry_clear_close_summary">Tanca la base de dades en tancar la notificació</string>
<string name="keyboard_entry_timeout_title">Temps d\'espera</string>
<string name="keyboard_key_vibrate_title">Vibració del teclat</string>
<string name="autofill_inline_suggestions_title">Suggeriments integrats</string>
<string name="autofill_inline_suggestions_keyboard">S\'han afegit els suggeriments d\'emplenament automàtic.</string>
<string name="allow_no_password_summary">Permet prémer el botó \"Obre\" sense seleccionar cap credencial</string>
<string name="delete_entered_password_title">Suprimeix la contrasenya</string>
<string name="enable_auto_save_database_title">Desa automàticament la base de dades</string>
<string name="enable_auto_save_database_summary">Desa la base de dades després de cada acció important (en el mode «Modificable»)</string>
<string name="enable_keep_screen_on_title">Manté la pantalla activada</string>
<string name="education_create_database_summary">Creeu el vostre primer fitxer de gestió de contrasenyes.</string>
<string name="show_entry_colors_title">Colors de l\'entrada</string>
<string name="keyboard_appearance_category">Aparença</string>
<string name="keyboard_auto_go_action_summary">Acció de la tecla «Ves» després de prémer una tecla «Camp»</string>
<string name="autofill_ask_to_save_data_title">Demana desar les dades</string>
<string name="keyboard_change">Commuta el teclat</string>
<string name="backspace">Retrocés</string>
<string name="enter">Introdueix</string>
<string name="autofill_save_search_info_summary">Això intenta desar la informació de cerca en fer una selecció d\'entrada manual per a usos futurs més fàcils</string>
<string name="autofill_web_domain_blocklist_title">Llista de bloqueig de dominis web</string>
<string name="autofill_block_restart">Reinicieu l\'aplicació que conté el formulari per activar el bloqueig.</string>
<string name="enable_keep_screen_on_summary">Manté la pantalla activada en veure o editar una entrada</string>
<string name="education_create_database_title">Creeu el fitxer de la base de dades</string>
<string name="education_new_node_summary">Les entrades ajuden a gestionar les identitats digitals.
\n
\nEls grups (carpetes) organitzen entrades a la base de dades.</string>
<string name="download_attachment">Baixa %1$s</string>
<string name="download_progression">En curs: %1$d%%</string>
<string name="download_complete">S\'ha completat.</string>
<string name="advanced_unlock_prompt_extract_credential_message">Extreu la credencial de la base de dades amb les dades de desbloqueig del dispositiu</string>
<string name="keyboard">Teclat</string>
<string name="magic_keyboard_title">Magikeyboard</string>
<string name="custom_fields">Camps personalitzats</string>
<string name="advanced_unlock_prompt_store_credential_title">Enllaç al desbloqueig del dispositiu</string>
<string name="education_entry_edit_title">Edita l\'entrada</string>
<string name="filter">Filtra</string>
<string name="keyboard_auto_go_action_title">Acció de la tecla automàtica</string>
<string name="configure_biometric">No hi ha cap credencial biomètrica ni de dispositiu inscrita.</string>
<string name="advanced_unlock_explanation_summary">Utilitza el desbloqueig del dispositiu per obrir una base de dades més fàcilment</string>
<string name="device_credential_unlock_enable_summary">Us permet utilitzar la credencial del dispositiu per obrir la base de dades</string>
<string name="biometric_auto_open_prompt_summary">Sol·licita automàticament el desbloqueig del dispositiu si la base de dades està configurada per utilitzar-lo</string>
<string name="advanced_unlock_delete_all_key_warning">Voleu suprimir totes les claus de xifratge relacionades amb el reconeixement de desbloqueig del dispositiu?</string>
<string name="biometric_unlock_enable_title">Desbloqueig biomètric</string>
<string name="biometric_unlock_enable_summary">Us permet escanejar la vostra biomètrica per obrir la base de dades</string>
<string name="autofill_application_id_blocklist_title">Llista de bloqueig d\'aplicacions</string>
<string name="enable_screenshot_mode_title">Mode captura de pantalla</string>
<string name="search_mode">Mode de cerca</string>
<string name="save_mode">Desa el mode</string>
<string name="keyboard_save_search_info_title">Desa la informació compartida</string>
<string name="keyboard_notification_entry_content_title">%1$s disponbile al Magikeyboard</string>
<string name="warning_empty_keyfile_explanation">El contingut del fitxer clau no s\'ha de canviar mai, i en el millor dels casos, ha de contenir dades generades aleatòriament.</string>
<string name="invalid_db_same_uuid">%1$s amb el mateix UUID %2$s ja existeix.</string>
<string name="menu_external_icon">Icona externa</string>
<string name="remember_keyfile_locations_summary">Fa un seguiment d\'on s\'emmagatzemen els fitxers de claus</string>
<string name="hide_broken_locations_title">Amaga els enllaços trencats de la base de dades</string>
<string name="autofill_manual_selection_summary">Mostra l\'opció de permetre que l\'usuari seleccioni l\'entrada de la base de dades</string>
<string name="download_canceled">S\'ha cancel·lat.</string>
<string name="do_not_kill_app">No matis l\'aplicació…</string>
<string name="lock_database_screen_off_title">Bloqueig de pantalla</string>
<string name="at_least_one_char">Com a mínim un caràcter de cada</string>
<string name="show_entry_colors_summary">Mostra els colors de primer pla i de fons per a una entrada</string>
<string name="keystore_not_accessible">El magatzem de claus no està correctament inicialitzat.</string>
<string name="autofill_service_name">Emplenament automàtic de formularis de KeePassDX</string>
<string name="show_otp_token_summary">Mostra els testimonis OTP a la llista d\'entrades</string>
<string name="show_uuid_summary">Mostra l\'UUID enllaçat a una entrada o un grup</string>
<string name="menu_app_settings_summary">Cerca, bloqueja, historial, propietats</string>
<string name="menu_security_settings_summary">Xifratge, funció de derivació de la clau</string>
<string name="master_key_settings_summary">Canvi, renovació</string>
<string name="subdomain_search_title">Cerca de subdomini</string>
<string name="subdomain_search_summary">Cerca dominis web amb restriccions de subdominis</string>
<string name="warning_replace_file">La pujada d\'aquest fitxer substituirà l\'existent.</string>
<string name="warning_remove_unlinked_attachment">Eliminar les dades desenllaçades pot disminuir la mida de la base de dades, però també pot eliminar les dades utilitzades per als connectors del KeePass.</string>
<string name="warning_sure_remove_data">Voleu suprimir aquestes dades de totes maneres?</string>
<string name="warning_database_info_changed">La informació continguda al fitxer de la base de dades s\'ha modificat fora de l\'aplicació.</string>
<string name="later">Més tard</string>
<string name="configure">Configura</string>
<string name="biometric_security_update_required">Cal actualitzar la seguretat biomètrica.</string>
<string name="unlock_and_link_biometric">Enllaç de desbloqueig del dispositiu</string>
<string name="advanced_unlock_scanning_error">Error en desbloquejar el dispositiu: %1$s</string>
<string name="unavailable">No disponible</string>
<string name="advanced_unlock_prompt_not_initialized">No s\'ha pogut inicialitzar l\'indicador de desbloqueig del dispositiu.</string>
<string name="credential_before_click_advanced_unlock_button">Escriviu la contrasenya i, a continuació, feu clic en aquest botó.</string>
<string name="menu_appearance_settings_summary">Temes, colors, atributs</string>
<string name="clipboard_notifications_summary">Mostra les notificacions del porta-retalls per a copiar camps en visualitzar una entrada</string>
<string name="content">Contingut</string>
<string name="device_credential_unlock_enable_title">Desbloqueig de les credencials del dispositiu</string>
<string name="unavailable_feature_text">No s\'ha pogut iniciar aquesta característica.</string>
<string name="unavailable_feature_hardware">No s\'ha pogut trobar el maquinari corresponent.</string>
<string name="templates_group_enable_title">Ús de plantilles</string>
<string name="templates_group_enable_summary">Utilitza plantilles dinàmiques per omplir els camps d\'una entrada</string>
<string name="templates_group_uuid_title">Grup de plantilles</string>
<string name="max_history_items_summary">Limita el nombre d\'elements de l\'historial per entrada</string>
<string name="recycle_bin">Paperera de reciclatge</string>
<string name="templates">Plantilles</string>
<string name="magic_keyboard_explanation_summary">Activeu un teclat personalitzat que empleni les contrasenyes i tots els camps d\'identitat</string>
<string name="device_keyboard_setting_title">Configuració del teclat del dispositiu</string>
<string name="keyboard_name">Magikeyboard</string>
<string name="keyboard_setting_label">Configuració del Magikeyboard</string>
<string name="keyboard_entry_category">Entrada</string>
<string name="keyboard_notification_entry_title">Informació de la notificació</string>
<string name="keyboard_notification_entry_content_title_text">Entrada</string>
<string name="keyboard_notification_entry_content_text">%1$s</string>
<string name="keyboard_theme_title">Tema del teclat</string>
<string name="keyboard_key_sound_title">Prémer les tecles amb so</string>
<string name="keyboard_save_search_info_summary">Això intenta desar la informació compartida en fer una selecció d\'entrada manual per a usos futurs més fàcils</string>
<string name="keyboard_previous_search_title">Pantalla de cerca</string>
<string name="keyboard_previous_search_summary">Torna automàticament al teclat anterior a la pantalla de cerca</string>
<string name="keyboard_previous_fill_in_summary">Torna automàticament al teclat anterior després d\'executar «Acció de la tecla automàtica»</string>
<string name="keyboard_previous_lock_title">Bloqueja la base de dades</string>
<string name="keyboard_previous_lock_summary">Torna automàticament al teclat anterior després de bloquejar la base de dades</string>
<string name="select_entry">Selecciona una entrada</string>
<string name="autofill_ask_to_save_data_summary">Demana desar les dades quan es completi l\'emplenament d\'un formulari</string>
<string name="autofill_read_only_save">No es permet desar dades en una base de dades oberta en mode només de lectura.</string>
<string name="reset_education_screens_summary">Torna a mostrar tota la informació educativa</string>
<string name="reset_education_screens_text">Reinicialitza els consells educatius</string>
<string name="education_select_database_title">Obre una base de dades existent</string>
<string name="education_select_database_summary">Obriu el fitxer anterior de la base de dades des del navegador de fitxers per a continuar utilitzant-lo.</string>
<string name="education_advanced_unlock_summary">Enllaça la contrasenya a una credencial biomètrica escanejada o de dispositiu per desbloquejar ràpidament la base de dades.</string>
<string name="education_validate_entry_title">Valida l\'entrada</string>
<string name="education_entry_new_field_title">Afegeix camps personalitzats</string>
<string name="education_add_attachment_title">Afegeix un adjunt</string>
<string name="education_setup_OTP_title">Configura l\'OTP</string>
<string name="education_unlock_title">Desbloqueja la base de dades</string>
<string name="education_setup_OTP_summary">Configureu la gestió de contrasenyes d\'un sol ús (HOTP / TOTP) per generar un testimoni sol·licitat per a l\'autenticació de dos factors (2FA).</string>
<string name="education_field_copy_title">Copia un camp</string>
<string name="html_text_donation">Per tal de mantenir la nostra llibertat i estar sempre actius, comptem amb la seva &lt;strong&gt;aportació. &lt;/strong&gt;</string>
<string name="upload_attachment">Puja %1$s</string>
<string name="download_finalization">S\'està finalitzant…</string>
<string name="entropy">Entropia: %1$s bit</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More