Compare commits

..

1622 Commits

Author SHA1 Message Date
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
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
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
J-Jamet
e4c3baa344 Merge branch 'release/4.0.0beta02' 2023-08-07 16:00:15 +02:00
J-Jamet
1e60d7e637 fix: Crash 2023-08-07 15:47:20 +02:00
J-Jamet
262b0227c1 fix: Selection switch 2023-08-07 15:27:38 +02:00
J-Jamet
226e461324 fix: Item entry alignment 2023-08-07 13:57:47 +02:00
J-Jamet
151eb26d56 fix: Tab in entry 2023-08-07 13:52:48 +02:00
J-Jamet
335e767426 fix: Small bugs 2023-08-07 13:36:19 +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
91bbc6d84e fix: tags 2023-08-06 22:59:48 +02:00
J-Jamet
6dbd16c5f6 Merge branch 'translations' into develop 2023-08-06 22:57:18 +02:00
J-Jamet
76e040c585 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2023-08-06 22:55:11 +02:00
J-Jamet
8de6382a64 fix: update CHANGELOG 2023-08-06 22:54:06 +02:00
J-Jamet
53532ead9f fix: Dialog buttons color 2023-08-06 22:47:33 +02:00
J-Jamet
f4e6baeac2 fix: Entry path style 2023-08-06 21:46:36 +02:00
J-Jamet
5c46fdf41a fix: Replace boolean parcelable 2023-08-06 20:57:39 +02:00
J-Jamet
22073e4bbd fix: Deactivated color 2023-08-06 20:29:01 +02:00
J-Jamet
41e7376b7b feat: Cut and Copy from search CHANGELOG 2023-08-05 17:37:20 +02:00
J-Jamet
3fc26c8c4e feat: Cut and Copy from search CHANGELOG 2023-08-05 17:37:15 +02:00
J-Jamet
14f070a942 feat: Cut and Copy from search CHANGELOG 2023-08-05 17:36:13 +02:00
J-Jamet
c078bd05e2 feat: Cut and Copy from search 2023-08-05 17:29:32 +02:00
J-Jamet
8ce9757b7c fix: Error with coordinator 2023-08-05 17:06:07 +02:00
bowornsin
e028738dc2 Translated using Weblate (Thai)
Currently translated at 83.9% (543 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2023-08-03 11:08:42 +02:00
Masowick
9f4a302b72 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-03 11:08:42 +02:00
C. Rüdinger
2ef17e0c7a 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-03 11:08:42 +02:00
VfBFan
b86a8c8633 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-03 11:08:41 +02:00
Masowick
5a3be0853e 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-01 21:36:43 +02:00
Reza Almanda
99568db10c Translated using Weblate (Indonesian)
Currently translated at 96.1% (622 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2023-08-01 07:36:19 +02:00
Milo Ivir
bf892f5b6a 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-08-01 07:36:19 +02:00
Eric
8e2c7ba1f0 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-08-01 07:36:18 +02:00
solokot
fd3bb4b243 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-01 07:36:18 +02:00
André Marcelo Alvarenga
7f4a1d6896 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-08-01 07:36:17 +02:00
Retrial
d62734e8ac 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-08-01 07:36:17 +02:00
VfBFan
fbebc12a38 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-01 07:36:16 +02:00
Masowick
3c65be2a72 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-01 07:36:16 +02:00
Fjuro
a29a9f28ef Translated using Weblate (Czech)
Currently translated at 93.9% (608 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2023-08-01 07:36:15 +02:00
J-Jamet
eb14dadb3c fix: Scroll and color flickering 2023-07-31 22:28:53 +02:00
J-Jamet
8d926a306b fix: Shadow on logo 2023-07-31 22:19:55 +02:00
J-Jamet
5699359099 fix: Toolbar flickering 2023-07-31 22:07:41 +02:00
J-Jamet
e3176033dc fix: Margin bug 2023-07-31 22:03:29 +02:00
J-Jamet
9df6215c02 Merge branch 'feature/delete_search_entry_1308' into develop 2023-07-31 21:49:34 +02:00
J-Jamet
93a0e4c0a6 fix: Upgrade CHANGELOG 2023-07-31 21:49:20 +02:00
J-Jamet
f55a824cdc fix: Search in special mode 2023-07-31 21:45:35 +02:00
J-Jamet
766026d3be Merge branch 'develop' into feature/delete_search_entry_1308 2023-07-31 21:24:41 +02:00
J-Jamet
c64fc56496 Merge branch 'develop' of github.com:Kunzisoft/KeePassDX into develop 2023-07-31 21:19:46 +02:00
J-Jamet
6e2fb21431 fix: Better theme colors 2023-07-31 21:19:16 +02:00
Jérémy JAMET
2bb70abc39 Merge pull request #1582 from MarijnS95/icon-pack-JavaVersion
Add `JavaVersion` compatible to `icon-pack`
2023-07-31 16:08:35 +02:00
Darin Avdeyeva
a6cb1dbe5c 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-07-30 15:18:59 +02:00
Alexthegib
5222a72cc6 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-07-30 15:18:59 +02:00
Stephan Paternotte
5d3aa44545 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-07-30 15:18:58 +02:00
random r
61cfda93a5 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-07-30 15:18:58 +02:00
Htet Oo Hlaing
b490295b90 Translated using Weblate (Burmese)
Currently translated at 4.6% (30 of 647 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/my/
2023-07-30 11:56:12 +02:00
Alexthegib
61035ca47b 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-07-30 11:56:11 +02:00
Eric
1dc08bbfef 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-07-30 11:56:10 +02:00
Ihor Hordiichuk
9ea7c86da7 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-07-30 11:56:09 +02:00
solokot
4fa3fb86cb 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-07-30 11:56:08 +02:00
marfS2
df089f4415 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-07-30 11:56:07 +02:00
Matthaiks
6be12eb440 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-07-30 11:56:06 +02:00
Stephan Paternotte
84efd1c497 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-07-30 11:56:05 +02:00
Kunzisoft
4817654d58 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-07-30 11:56:04 +02:00
Deleted User
70d45e0bba 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-07-30 11:56:02 +02:00
C. Rüdinger
a4c7e3860b 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-07-30 11:56:01 +02:00
VfBFan
2a890091d7 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-07-30 11:56:01 +02:00
Htet Oo Hlaing
cc593e6e1f Added translation using Weblate (Burmese) 2023-07-30 04:40:47 +02:00
J-Jamet
552684fd90 feat: Delete entry from search 2023-07-29 21:40:00 +02:00
J-Jamet
a260e1d4e3 fix: Encapsulate Keyboard code 2023-07-29 18:59:16 +02:00
J-Jamet
07bbf232b6 Merge tag '4.0.0beta01' into develop
4.0.0beta01
2023-07-29 12:45:50 +02:00
J-Jamet
64b4a2f317 Merge branch 'release/4.0.0beta01' 2023-07-29 12:45:31 +02:00
J-Jamet
f0455fbca6 fix: Upgrade CHANGELOG 2023-07-29 12:35:07 +02:00
J-Jamet
2fa973f34a fix: Upgrade Gemfile and version to 4.0.0 2023-07-29 12:02:50 +02:00
J-Jamet
470497b8ef fix: Small size bug 2023-07-28 21:02:05 +02:00
J-Jamet
215cc641c3 feat: Switch keyboard only if focus #1351 2023-07-28 20:52:35 +02:00
J-Jamet
a98fa0d7bb feat: add simple theme in free version 2023-07-28 18:48:35 +02:00
J-Jamet
c70841d3e5 feat: add simple theme in free version 2023-07-28 18:47:55 +02:00
J-Jamet
3fdcd3c43d feat: Build title from webDomain 2023-07-28 18:44:13 +02:00
J-Jamet
b32bb609de fix: Notification for missing notification permission 2023-07-28 17:30:32 +02:00
J-Jamet
4db03fe034 fix: Remove URL in menu 2023-07-28 17:26:00 +02:00
J-Jamet
68430ef62c fix: Null when unbind service 2023-07-28 17:02:57 +02:00
J-Jamet
d46f48f317 fix: Special toolbar style 2023-07-28 16:43:08 +02:00
J-Jamet
e68e4dac46 fix: Unchecked auto key action by default 2023-07-28 15:35:56 +02:00
J-Jamet
3a79f94698 fix: Add validate entry education 2023-07-28 13:06:48 +02:00
J-Jamet
b913913bf1 fix: Add validate entry education 2023-07-28 12:59:20 +02:00
J-Jamet
16f92fc895 fix: Change wording for screen on option 2023-07-28 12:27:44 +02:00
J-Jamet
189e98b3fe fix: Small biometric changes 2023-07-28 12:27:23 +02:00
J-Jamet
64fea078e8 fix: Update device unlock wording 2023-07-28 11:06:07 +02:00
J-Jamet
4ad5d35be7 fix: Theme in settings 2023-07-27 01:40:11 +02:00
J-Jamet
82015953b9 Merge branch 'feature/Material_You' into develop 2023-07-27 01:12:06 +02:00
J-Jamet
630318dbef fix: Remove context themed 2023-07-27 01:10:30 +02:00
J-Jamet
d289e8acaa feat: Add Material You with dynamic color 2023-07-27 00:07:41 +02:00
J-Jamet
4632a202a9 fix: Small color change 2023-07-25 13:04:41 +02:00
J-Jamet
4a9282ee53 fix: Titles 2023-07-25 01:07:56 +02:00
J-Jamet
45ec38ecab fix: Parcelable for action 2023-07-24 23:32:03 +02:00
J-Jamet
b82fc4659a Merge branch 'feature/Material_You_1469' into develop 2023-07-24 21:12:29 +02:00
J-Jamet
aade780f92 fix: Image database modified 2023-07-24 21:03:32 +02:00
J-Jamet
6001f68cce fix: Breadcrumb and colors 2023-07-24 20:32:40 +02:00
J-Jamet
d0a072554e fix: Refactoring text styles 2023-07-24 19:14:33 +02:00
J-Jamet
53ccac0e9c fix: Preference flickering 2023-07-24 14:39:07 +02:00
J-Jamet
14e2a3f79e fix: Titles 2023-07-24 14:17:26 +02:00
J-Jamet
9afe5aaaf4 fix: Title and small bugs 2023-07-24 13:51:29 +02:00
J-Jamet
b992c9eb65 fix: Better preference implementation and fix colors 2023-07-24 13:21:24 +02:00
J-Jamet
fa2a79bc6c fix: Breadcrumb and buttons 2023-07-24 09:47:17 +02:00
J-Jamet
b1d4310b93 fix: OTP clipboard as sensitive 2023-07-23 22:57:22 +02:00
J-Jamet
1811b02fc8 fix: colors Kitkat selection and progressCircular 2023-07-23 22:54:09 +02:00
J-Jamet
5bbf436e4e fix: color selection 2023-07-23 12:40:39 +02:00
J-Jamet
d47a12c3d9 fix: Collapsing title 2023-07-23 12:00:35 +02:00
J-Jamet
dd7f6b389c fix: Custom entry color 2023-07-23 11:49:17 +02:00
J-Jamet
e829e3eedf fix: Dialog implementation 2023-07-22 21:02:58 +02:00
J-Jamet
178de4dd99 fix: Colors in styles 2023-07-22 20:45:05 +02:00
J-Jamet
a4cfc8ff49 fix: Chips 2023-07-22 20:08:54 +02:00
J-Jamet
b607cce691 fix: Kunzite style 2023-07-22 19:49:11 +02:00
J-Jamet
5986f39041 fix: Date and Time Picker as Material 2023-07-22 19:09:12 +02:00
J-Jamet
8ab39aaea6 fix: Style Reply 2023-07-22 17:46:58 +02:00
J-Jamet
4114d5aeb1 fix: Styles moon and sun 2023-07-21 22:11:39 +02:00
J-Jamet
2a1a5d9bd4 fix: Styles 2023-07-21 18:17:00 +02:00
J-Jamet
72b347bc85 fix: Search view 2023-07-20 23:23:47 +02:00
J-Jamet
44628f6fc4 fix: Lock button position 2023-07-20 23:09:00 +02:00
J-Jamet
9191fd4a21 fix: colors 2023-07-20 22:54:32 +02:00
J-Jamet
02c4eba676 fix: Many style issues 2023-07-19 21:42:31 +02:00
J-Jamet
a45b5605a1 fix: group icon 2023-07-11 22:54:57 +02:00
J-Jamet
8570f47372 fix: Large pass to add Material 3 2023-07-10 20:11:39 +02:00
J-Jamet
71fd17c0ac fix: Add color for tabs 2023-07-09 13:28:22 +02:00
J-Jamet
eb4e45cb69 fix: Add tertiary color, change color accent to color secondary 2023-07-09 11:40:58 +02:00
J-Jamet
3891bb1c8f fix: Add configuration cache 2023-07-09 10:14:07 +02:00
J-Jamet
a3c5237c2b fix: Null 2023-07-08 17:40:08 +02:00
J-Jamet
e05b904e78 fix: Styles 2023-07-08 16:35:25 +02:00
J-Jamet
0423dd7295 fix: Settings and biometric button 2023-07-08 15:59:51 +02:00
J-Jamet
8fa8043ff4 feat: Fingerprint button as real button 2023-07-08 00:38:58 +02:00
J-Jamet
244174e494 fix: Fingerprint button 2023-07-07 23:53:01 +02:00
J-Jamet
db8920ae69 fix: move advanced unlock button to the bottom 2023-07-07 22:32:47 +02:00
J-Jamet
670e949e9f fix: Buttons and wording 2023-06-27 23:20:51 +02:00
J-Jamet
c4daafea6d fix: rollback AlertDialog 2023-06-26 20:20:15 +02:00
J-Jamet
c8f07ffa7c fix: red and blue styles 2023-06-26 20:05:55 +02:00
J-Jamet
7f721427b6 fix: switch and color 2023-06-26 20:01:46 +02:00
J-Jamet
ad670151c8 fix: radius and color 2023-06-26 19:26:01 +02:00
J-Jamet
800335e416 fix: DateTime dialog color and switch to the right 2023-06-26 18:44:38 +02:00
J-Jamet
2da58f5899 fix: Lot of styles bugs 2023-06-26 18:03:36 +02:00
J-Jamet
0850b19aec fix: Crash on kitkat 2023-06-26 13:38:59 +02:00
Marijn Suijten
b6d32999b9 Add JavaVersion compatible to icon-pack
This now also contains Kotlin code.
2023-06-22 01:11:06 +02:00
J-Jamet
4f96a300c2 fix: CardView Radius 2023-06-19 19:03:31 +02:00
J-Jamet
c630b9d0c0 fix: Button color 2023-06-19 18:00:42 +02:00
J-Jamet
7324f630ba fix: File selection screen 2023-06-19 17:08:37 +02:00
J-Jamet
519da9c4ef fix: First pass to Material3 2023-06-19 16:10:36 +02:00
J-Jamet
6fc26ef6e6 fix: update strings 2023-06-18 23:03:29 +02:00
J-Jamet
dfb7e6f3bd fix: check permission 2023-06-18 23:02:09 +02:00
J-Jamet
5a883b83a5 fix: bn string 2023-06-18 21:20:53 +02:00
J-Jamet
dfef51fd27 fix: replace strong tag 2023-06-18 21:11:31 +02:00
J-Jamet
8bb7c7c8af Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2023-06-18 21:09:20 +02:00
J-Jamet
98370a03b5 fix: better intent to ask fingerprint enrollment 2023-06-18 20:46:48 +02:00
J-Jamet
82875ff832 fix: ask for notification permission 2023-06-18 18:12:17 +02:00
J-Jamet
9b4b5914d6 fix: allowCreateDocumentByStorageAccessFramework method 2023-06-18 12:23:37 +02:00
J-Jamet
7b9576841d fix: Menu deprecation 2023-06-18 12:05:08 +02:00
J-Jamet
59794557b3 fix: PackageInfo compat 2023-06-18 11:00:22 +02:00
J-Jamet
c3e4504a1a fix: TokenAutoComplete as lib 2023-06-18 10:43:07 +02:00
J-Jamet
65d7fdbf7e fix: Resolve dependencies and small changes 2023-06-18 10:33:58 +02:00
J-Jamet
d5310e5c58 fix: Deprecated parcelable 2023-06-18 10:08:58 +02:00
J-Jamet
f02b7c16d2 fix: Upgrade to SDK 33 2023-06-17 19:01:35 +02:00
J-Jamet
7cd456ecbc fix: Manifest tag 2023-06-17 18:39:30 +02:00
J-Jamet
1aeff9684e fix: Upgrade gradle to 7.4.2 2023-06-17 18:20:05 +02:00
Jeanluc Henrot
4b0ad75e7b Translated using Weblate (French)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2023-06-06 14:50:16 +02:00
Masowick
055b3c6002 Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-05-19 10:48:28 +02:00
abidin toumi
9ad4858224 Translated using Weblate (Arabic)
Currently translated at 75.4% (477 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2023-05-18 09:47:41 +02:00
ctntt
33422f90ce Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-05-18 09:47:41 +02:00
ctntt
b9f4f9380b Translated using Weblate (German)
Currently translated at 99.2% (627 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-05-15 16:52:04 +02:00
J-Jamet
56a1601d79 Merge branch 'feature/Module_Refactoring' into develop 2023-05-15 16:43:46 +02:00
J-Jamet
a7d04e573a fix: Better database action implementation 2023-05-15 16:21:49 +02:00
J-Jamet
0c4d827469 fix: Remove unused assign password runnable 2023-05-15 00:13:02 +02:00
J-Jamet
5656f6afb5 fix: Small changes 2023-05-14 23:43:45 +02:00
J-Jamet
4bd12b8a95 fix: Refactoring database actions 2023-05-14 23:38:08 +02:00
J-Jamet
939b319563 fix: Change ContextualDatabase 2023-05-14 22:21:34 +02:00
J-Jamet
05865fe8c3 fix: Encapsulate BASE64_FLAG 2023-05-14 22:05:08 +02:00
J-Jamet
09cf8aabf6 Revert "fix: Base64 encoder as external library"
This reverts commit 13f2003fed.
2023-05-14 21:56:11 +02:00
J-Jamet
111a77d984 Revert "fix: Base64 encoder as external library"
This reverts commit 1b96747187.
2023-05-14 21:56:11 +02:00
J-Jamet
c2cc0a77ab fix: NDKVersion in the right package 2023-05-14 21:54:52 +02:00
J-Jamet
5b052b02a2 fix: crypto module at the upper level 2023-05-14 21:33:37 +02:00
J-Jamet
3b3908dd7c fix: Better icon pack implementation 2023-05-14 21:25:24 +02:00
J-Jamet
1b96747187 fix: Base64 encoder as external library 2023-05-14 20:19:22 +02:00
J-Jamet
13f2003fed fix: Base64 encoder as external library 2023-05-14 20:06:51 +02:00
J-Jamet
4d6dbc9e30 fix: Create unit tests in right package 2023-05-14 19:40:43 +02:00
J-Jamet
a235b21fbf feat: Move modules 2023-05-14 18:40:45 +02:00
J-Jamet
158ed26f6f fix: Remove unused libs 2023-05-14 18:03:05 +02:00
J-Jamet
81930bf3a1 fix: Remove AndroidX dependency and format code 2023-05-14 17:52:40 +02:00
J-Jamet
e1ecebb4a0 fix: Remove unnecessary coroutine lib 2023-05-14 15:55:04 +02:00
J-Jamet
52fd576f55 fix: Delete color lib dependency 2023-05-14 15:51:32 +02:00
J-Jamet
6742a8893c fix: Separate Main credential, remove ContentProvider from Database 2023-05-14 15:33:39 +02:00
J-Jamet
7db0c4f7d3 fix: Locale warning 2023-05-14 13:26:23 +02:00
J-Jamet
372b2aebe0 fix: Smaller isSearchable implementation 2023-05-14 13:22:51 +02:00
J-Jamet
b713237ec3 fix: Small warning 2023-05-14 13:14:27 +02:00
J-Jamet
ee1a0a53a6 fix: Better icon builder implementation, add ContextualDatabase 2023-05-14 13:04:49 +02:00
VfBFan
45ece887a2 Translated using Weblate (German)
Currently translated at 99.2% (627 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-05-14 12:49:11 +02:00
ctntt
0f59aaf4f7 Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-05-13 02:50:29 +02:00
J-Jamet
0d2c814b3d fix: Small changes 2023-05-08 21:17:00 +02:00
J-Jamet
64bdcc2f32 fix: Remove unused interface 2023-05-08 20:50:59 +02:00
J-Jamet
dfb418c12a fix: better static utils implementation 2023-05-08 20:30:16 +02:00
J-Jamet
c8868f31e6 Refactoring code, better encapsulation 2023-05-08 18:49:42 +02:00
J-Jamet
48cc8b3f75 Merge branch 'extract-database' of github.com:GianpaMX/KeePassDX into GianpaMX-extract-database 2023-05-08 15:19:32 +02:00
Aitor Elorza
62777373a4 Translated using Weblate (Basque)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-05-05 16:48:19 +02:00
Aitor Elorza
ce987237ae Translated using Weblate (Basque)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-05-03 18:48:25 +02:00
Aitor Elorza
77b99f9ef4 Translated using Weblate (Bengali)
Currently translated at 57.1% (361 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bn/
2023-04-29 14:51:26 +02:00
Aitor Elorza
049ac4cb21 Translated using Weblate (Basque)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-04-29 14:51:25 +02:00
Éfrit
41e3c60632 Translated using Weblate (French)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2023-04-28 11:27:27 +02:00
Aitor Elorza
5b2c846f7d Translated using Weblate (Basque)
Currently translated at 94.3% (596 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-04-28 11:27:26 +02:00
C. Rüdinger
8a0192bcac Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-04-28 11:27:25 +02:00
Subham Jena
3d2fce78c6 Translated using Weblate (Odia)
Currently translated at 0.4% (3 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/or/
2023-04-24 00:51:47 +02:00
Ihor Hordiichuk
120bfd47e2 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2023-04-24 00:51:47 +02:00
Aitor Elorza
408ac08059 Translated using Weblate (Basque)
Currently translated at 69.7% (441 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-04-24 00:51:47 +02:00
Subham Jena
9ae2377bd9 Added translation using Weblate (Odia) 2023-04-23 00:13:42 +02:00
J-Jamet
f126a9ab09 Merge branch 'jkrasuk-jkrasuk-patch-1' into develop 2023-04-22 22:41:38 +02:00
J-Jamet
c2d4bf67d0 Merge branch 'jkrasuk-patch-1' of github.com:jkrasuk/KeePassDX into jkrasuk-jkrasuk-patch-1 2023-04-22 22:39:25 +02:00
J-Jamet
d0367ea7f8 fix: Replace strong tags 2023-04-22 22:34:50 +02:00
J-Jamet
73c6c97637 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2023-04-22 22:31:42 +02:00
J-Jamet
3f63fa9c30 fix: Upgrade to 3.5.2 and add new default configuration for protected memory 2023-04-22 22:15:49 +02:00
J-Jamet
2884d12b4b fix: Upgrade GemFile 2023-04-22 22:10:58 +02:00
Aitor Elorza
24dd966eab Translated using Weblate (Basque)
Currently translated at 35.4% (224 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-04-18 07:14:03 +02:00
ctntt
47b2464297 Translated using Weblate (German)
Currently translated at 97.9% (619 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-04-18 07:14:02 +02:00
Masowick
08bb11a4d7 Translated using Weblate (German)
Currently translated at 97.9% (619 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-04-18 07:14:02 +02:00
Martin
e0c2c14b98 Translated using Weblate (German)
Currently translated at 97.9% (619 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-04-16 19:27:55 +02:00
Alexandru
481b818619 Translated using Weblate (Romanian)
Currently translated at 65.5% (414 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2023-04-12 10:32:45 +02:00
Aitor Elorza
138efebd8c Translated using Weblate (Basque)
Currently translated at 28.0% (177 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-04-05 18:48:12 +02:00
Aitor Elorza
3251f02ab2 Translated using Weblate (Basque)
Currently translated at 22.7% (144 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-04-01 15:37:39 +02:00
Aitor Elorza
8f74cdfac0 Translated using Weblate (Basque)
Currently translated at 20.5% (130 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-03-29 18:39:08 +02:00
VfBFan
75f795b6ab Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-29 18:39:07 +02:00
C. Rüdinger
dd901f3b16 Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-29 18:39:07 +02:00
Masowick
cf2d641303 Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-29 18:39:07 +02:00
Ettore Atalan
489c820ab9 Translated using Weblate (German)
Currently translated at 99.0% (626 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-28 09:37:14 +02:00
Masowick
dd21382b29 Translated using Weblate (German)
Currently translated at 99.0% (626 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-28 09:37:14 +02:00
VfBFan
05b2ccf0ed Translated using Weblate (German)
Currently translated at 99.0% (626 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-28 09:37:14 +02:00
J-Jamet
428efd2bb6 fix: CHANGELOG 2023-03-26 14:53:27 +02:00
J-Jamet
512b4cd16e Merge tag '3.5.1' into develop
3.5.1
2023-03-26 14:48:43 +02:00
J-Jamet
4d648b77b9 Merge branch 'release/3.5.1' 2023-03-26 14:48:32 +02:00
J-Jamet
02f6caf4dd fix: Loading dialog with Yubikey #1506 2023-03-26 14:46:11 +02:00
J-Jamet
2b23649674 feat: upgrade to 3.5.1 2023-03-26 14:44:20 +02:00
WB
1693be7776 Translated using Weblate (Galician)
Currently translated at 97.3% (615 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2023-03-25 16:40:20 +01:00
Aitor Elorza
c97be80a3a Translated using Weblate (Basque)
Currently translated at 13.2% (84 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-03-25 16:40:19 +01:00
Aitor Elorza
29d4d5232d Translated using Weblate (Basque)
Currently translated at 11.3% (72 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-03-22 16:38:00 +01:00
Tom Sawyer
90ee9d8c40 Translated using Weblate (Swedish)
Currently translated at 61.2% (387 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sv/
2023-03-20 08:40:54 +01:00
C. Rüdinger
5c0a82ba38 Translated using Weblate (German)
Currently translated at 98.8% (625 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-20 08:40:53 +01:00
Aitor Elorza
13aee1072f Translated using Weblate (Basque)
Currently translated at 11.3% (72 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-03-17 17:37:53 +01:00
VfBFan
b158cf1323 Translated using Weblate (German)
Currently translated at 98.7% (624 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-17 17:37:53 +01:00
C. Rüdinger
22be5ecbca Translated using Weblate (German)
Currently translated at 98.7% (624 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-16 08:07:05 +01:00
Aitor Elorza
4b16d9394a Translated using Weblate (Basque)
Currently translated at 10.7% (68 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/eu/
2023-03-15 19:37:20 +01:00
Masowick
c0ad54219f Translated using Weblate (German)
Currently translated at 99.8% (631 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-15 19:37:20 +01:00
76c72cfe
4af6f776b0 Translated using Weblate (Swedish)
Currently translated at 60.9% (385 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sv/
2023-03-12 17:37:26 +01:00
P.O
76373658d8 Translated using Weblate (Swedish)
Currently translated at 60.9% (385 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sv/
2023-03-12 17:37:26 +01:00
Anonimas
f9f6e69a95 Translated using Weblate (Lithuanian)
Currently translated at 51.7% (327 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/lt/
2023-03-08 20:37:37 +01:00
C. Rüdinger
61354df795 Translated using Weblate (German)
Currently translated at 99.8% (631 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-08 20:37:37 +01:00
Masowick
3a5c42b138 Translated using Weblate (German)
Currently translated at 99.8% (631 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-07 07:41:09 +01:00
jc
55e7544739 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2023-03-05 22:40:37 +01:00
Masowick
ad0dcdd54a Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-03-05 22:40:37 +01:00
Masowick
caa208c847 Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-25 19:38:55 +01:00
VfBFan
067d00376d Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-22 10:35:42 +01:00
Masowick
07f0521ef9 Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-22 10:35:42 +01:00
Masowick
3be3593b1b Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-21 07:53:12 +01:00
VfBFan
71db66d174 Translated using Weblate (German)
Currently translated at 99.5% (629 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-21 07:53:11 +01:00
Masowick
cd58a8e1b5 Translated using Weblate (German)
Currently translated at 99.6% (630 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-20 22:05:26 +01:00
VfBFan
256a579b1c Translated using Weblate (German)
Currently translated at 99.6% (630 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-20 22:05:25 +01:00
Masowick
97a427ea24 Translated using Weblate (German)
Currently translated at 99.6% (630 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-20 19:37:59 +01:00
VfBFan
b848587901 Translated using Weblate (German)
Currently translated at 99.6% (630 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-20 19:37:58 +01:00
VfBFan
fd90af3757 Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-20 18:42:57 +01:00
Ivan
cb1c9e1103 Translated using Weblate (Slovak)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sk/
2023-02-20 13:13:00 +01:00
Masowick
c14092d52b Translated using Weblate (German)
Currently translated at 99.8% (631 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-20 13:12:59 +01:00
Deleted User
27c19bd708 Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-14 18:39:31 +01:00
VfBFan
13d5273314 Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-13 17:59:14 +01:00
HudobniVolk
a0f93b5441 Translated using Weblate (Slovenian)
Currently translated at 8.5% (54 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sl/
2023-02-13 07:12:36 +01:00
gallegonovato
4c4c92527e Translated using Weblate (Galician)
Currently translated at 97.3% (615 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2023-02-13 07:12:35 +01:00
Deleted User
ff9999f39c Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-13 07:12:35 +01:00
HudobniVolk
45d06f269c Added translation using Weblate (Slovenian) 2023-02-12 13:45:47 +01:00
Ivan
acf92c0f8e Translated using Weblate (Slovak)
Currently translated at 99.0% (626 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sk/
2023-02-11 19:32:18 +01:00
Joaquín Krasuk
4b7de3b85f Update es translation 2023-02-11 12:16:34 -03:00
Milo Ivir
0502bfb986 Translated using Weblate (Croatian)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2023-02-05 20:38:52 +01:00
bowornsin
eacecd9b0d Translated using Weblate (Thai)
Currently translated at 87.6% (554 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2023-02-02 11:38:08 +01:00
SC
38245b4807 Translated using Weblate (Portuguese)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2023-02-02 11:38:07 +01:00
Oğuz Ersen
95228e67c2 Translated using Weblate (Turkish)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2023-02-02 11:38:07 +01:00
Eric
33cb4a55f5 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2023-02-02 11:38:07 +01:00
Ihor Hordiichuk
7beb13d859 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2023-02-02 11:38:07 +01:00
solokot
f0e0d26923 Translated using Weblate (Russian)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2023-02-02 11:38:06 +01:00
SC
5326322356 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2023-02-02 11:38:06 +01:00
Sengeku Ferreira Lima
ebe1c0bcdd Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2023-02-02 11:38:06 +01:00
Matthaiks
42100d4cb9 Translated using Weblate (Polish)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2023-02-02 11:38:06 +01:00
Stephan Paternotte
369f3d240e Translated using Weblate (Dutch)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2023-02-02 11:38:05 +01:00
random r
d40e83fb52 Translated using Weblate (Italian)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2023-02-02 11:38:05 +01:00
gallegonovato
6776b0867f Translated using Weblate (Spanish)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2023-02-02 11:38:05 +01:00
Retrial
5b1e945883 Translated using Weblate (Greek)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2023-02-02 11:38:05 +01:00
VfBFan
2f2f5e6f43 Translated using Weblate (German)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2023-02-02 11:38:05 +01:00
Fjuro
dfc7654842 Translated using Weblate (Czech)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2023-02-02 11:38:04 +01:00
Linerly
183015707f Translated using Weblate (Indonesian)
Currently translated at 100.0% (632 of 632 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2023-01-29 15:10:28 +01:00
Hosted Weblate
2bc4908452 Merge branch 'origin/develop' into Weblate. 2023-01-29 14:36:53 +01:00
bowornsin
213e5c40d7 Translated using Weblate (Thai)
Currently translated at 84.7% (535 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2023-01-29 14:36:53 +01:00
J-Jamet
e7cce21c51 Merge tag '3.5.0' into develop
3.5.0
2023-01-26 23:25:50 +01:00
J-Jamet
128ce5657e Merge branch 'release/3.5.0' 2023-01-26 23:25:40 +01:00
J-Jamet
861911ad63 fix: update fastlane changelogs 2023-01-26 23:21:10 +01:00
J-Jamet
9093c65235 feat: upgrade to 3.5.0 2023-01-26 23:15:02 +01:00
J-Jamet
e6ab8f82ff fix: url to download driver 2023-01-26 23:01:54 +01:00
J-Jamet
77ff1850f3 fix: url to download driver 2023-01-26 23:01:26 +01:00
J-Jamet
e985bd2a20 fix: dialog to download driver 2023-01-26 22:29:01 +01:00
bowornsin
a1e91bb26f Translated using Weblate (Thai)
Currently translated at 8.8% (56 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2023-01-24 18:58:28 +01:00
J-Jamet
a6cd02d146 feat: new year 2023-01-22 21:30:37 +01:00
J-Jamet
eb51f6712b fix: changelog length 2023-01-22 21:12:43 +01:00
J-Jamet
0a19ecb715 fi: translation strong tags 2023-01-22 20:59:11 +01:00
J-Jamet
d7e7020244 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2023-01-22 20:54:48 +01:00
J-Jamet
ea3349eea4 fix: autofill with hardware key 2023-01-22 20:33:29 +01:00
J-Jamet
9cec64ded4 fix: better challenge channel implementation 2023-01-22 20:21:17 +01:00
J-Jamet
f9dc456032 fix: remove ChallengeResponseViewModel and add HardwareKeyActivity 2023-01-22 15:10:36 +01:00
Linerly
6416aad823 Translated using Weblate (Indonesian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2023-01-12 22:48:40 +01:00
Kornelijus Tvarijanavičius
10b5c9c261 Translated using Weblate (Lithuanian)
Currently translated at 40.5% (256 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/lt/
2023-01-12 22:48:40 +01:00
ERYpTION
bc0e364164 Translated using Weblate (Danish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2023-01-12 22:48:40 +01:00
bowornsin
83ab5223a8 Translated using Weblate (Thai)
Currently translated at 8.2% (52 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2023-01-08 06:48:05 +01:00
Ahmad0a
94c6710f22 Translated using Weblate (Arabic)
Currently translated at 75.2% (475 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2023-01-06 02:49:44 +01:00
solokot
a1e5266161 Translated using Weblate (Russian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2023-01-04 18:47:52 +01:00
J-Jamet
adbdb9a642 first code to manage merge with yubikey 2023-01-02 19:30:19 +01:00
bowornsin
527f734fcf Translated using Weblate (Thai)
Currently translated at 5.5% (35 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2023-01-02 08:50:00 +01:00
Stephan Paternotte
f1a29af0c6 Translated using Weblate (Dutch)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-12-29 16:51:03 +01:00
WB
b69a277769 Translated using Weblate (Galician)
Currently translated at 97.3% (614 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-12-26 22:49:03 +01:00
J-Jamet
d049ed39e8 fix: upgrade to 3.5.0Beta03 2022-12-18 23:58:10 +01:00
J-Jamet
ecfe767068 fix: replace error method 2022-12-18 23:46:33 +01:00
J-Jamet
8d827eb562 Merge branch 'develop' of github.com:Kunzisoft/KeePassDX into develop 2022-12-18 12:24:19 +01:00
Jérémy JAMET
9048f618c5 Merge pull request #1447 from flawedworld/vanadium-rebrand
Add support for Vanadium in GrapheneOS
2022-12-18 12:21:47 +01:00
Salih Ail
66377ded62 Translated using Weblate (Arabic)
Currently translated at 75.1% (474 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2022-12-18 04:50:51 +01:00
VfBFan
04c4c82953 Translated using Weblate (German)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-12-10 09:49:31 +01:00
Besnik Bleta
ccd8467cba Translated using Weblate (Albanian)
Currently translated at 57.3% (362 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sq/
2022-12-08 18:48:14 +01:00
Besnik Bleta
4eee9e95c4 Translated using Weblate (Albanian)
Currently translated at 54.5% (344 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sq/
2022-12-07 17:48:59 +01:00
Besnik Bleta
c64b4b8d62 Translated using Weblate (Albanian)
Currently translated at 5.8% (37 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sq/
2022-12-07 12:44:47 +01:00
Besnik Bleta
72ef0f2f3f Added translation using Weblate (Albanian) 2022-12-07 12:34:56 +01:00
Michael
9b5a95a10f Translated using Weblate (German)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-12-06 07:43:25 +01:00
Yudong
1a3baa6523 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-12-04 16:48:49 +01:00
Matthaiks
a745ed1c28 Translated using Weblate (Polish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-11-26 20:48:46 +01:00
WaldiS
39ff112b42 Translated using Weblate (Polish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-11-25 20:13:07 +01:00
WB
b3aab27c9b Translated using Weblate (Galician)
Currently translated at 88.7% (560 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-11-24 20:38:26 +01:00
WB
9b3c751a49 Translated using Weblate (Galician)
Currently translated at 80.1% (506 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-11-19 21:46:56 +01:00
flawedworld
d29f4e0097 Add support for Vanadium in GrapheneOS 2022-11-19 02:11:56 +00:00
Abhi
0645fbe938 Translated using Weblate (Malayalam)
Currently translated at 60.6% (383 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ml/
2022-11-17 14:47:11 +01:00
Jacek
ee6c8fc041 Translated using Weblate (Polish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-11-16 02:49:13 +01:00
bowornsin
d93e3a1c2d Translated using Weblate (Thai)
Currently translated at 4.1% (26 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/th/
2022-11-09 11:50:24 +01:00
bowornsin
d4e0c008b8 Added translation using Weblate (Thai) 2022-11-08 07:37:59 +01:00
ssantos
0ca392f312 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2022-11-07 09:05:08 +01:00
solokot
c6c14c2354 Translated using Weblate (Russian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-11-06 09:03:25 +01:00
Darin Avdeyeva
652616226b Translated using Weblate (Russian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-11-05 09:54:16 +01:00
Retrial
d2101fd3e5 Translated using Weblate (Greek)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-11-02 06:36:25 +01:00
GianpaMX
3b967dd4e3 clean up 2022-10-27 17:31:48 +01:00
GianpaMX
e5d58721dd icon size 2022-10-26 17:19:40 +01:00
GianpaMX
1495c442ac default template group name 2022-10-26 17:16:38 +01:00
GianpaMX
2206184bcb recycler bin title 2022-10-26 16:37:08 +01:00
GianpaMX
9e0b6fa800 named compression algorithm 2022-10-26 15:25:38 +01:00
GianpaMX
b11533f9fe exceptions refactor 2022-10-26 12:20:19 +01:00
GianpaMX
50343193e1 template field 2022-10-26 11:33:51 +01:00
GianpaMX
7d7e3f4ad6 extract database module 2022-10-25 18:00:31 +01:00
WB
e22d9f6bdf Translated using Weblate (Galician)
Currently translated at 66.4% (419 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-10-24 23:37:12 +02:00
magnum Choi
affcc28f13 Translated using Weblate (Korean)
Currently translated at 50.2% (317 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ko/
2022-10-22 15:02:26 +02:00
Jacek
7a151bc2fe Translated using Weblate (Polish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-10-22 15:02:24 +02:00
Anonimas
5349c4783e Translated using Weblate (Lithuanian)
Currently translated at 39.7% (251 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/lt/
2022-10-22 15:02:24 +02:00
Óscar Fernández Díaz
96a72d9842 Translated using Weblate (Spanish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-10-22 15:02:23 +02:00
GianpaMX
04eae1ae3d new module 2022-10-22 07:57:40 +01:00
Gabriel Cardoso
67afa55f1d Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-10-17 02:53:24 +02:00
J-Jamet
efa8fd9f17 fix: replace strong tags 2022-10-14 21:21:27 +02:00
J-Jamet
64128991a6 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2022-10-14 21:16:09 +02:00
J-Jamet
3fa38c29f6 fix: fix channel closing 2022-10-14 21:06:52 +02:00
J-Jamet
86a335768c fix: update CHANGELOG 2022-10-14 20:49:26 +02:00
J-Jamet
2d29092c52 fix: update CHANGELOG 2022-10-14 20:43:49 +02:00
J-Jamet
2d7e76a279 Merge branch 'issue-1412' of github.com:ryg-git/KeePassDX into ryg-git-issue-1412 2022-10-14 20:39:26 +02:00
J-Jamet
1514dbb1de fix: comment FIDO2 code #304 2022-10-14 13:59:20 +02:00
J-Jamet
1707d3c3ba Revert "fix: Smaller advanced unlock UI"
This reverts commit 2882bb30d7.
2022-10-14 13:53:11 +02:00
J-Jamet
3fee162c4d fix: rollback mime-types */* #1211 #1408, add monochrome icon #1403 #1404 2022-10-14 13:40:01 +02:00
J-Jamet
78fd9d616b Merge branch 'Sandelinos-themed-icons' into release/3.5.0 2022-10-14 13:30:02 +02:00
J-Jamet
46828c3317 Revert "fix: remove application/octet-stream file recognition #1211"
This reverts commit e367051b80.
Mimetype */* #1408
2022-10-14 13:25:39 +02:00
ryg-git
5126bd4fb6 remove onRegularBackPressed method call as lockAndExit handles exiting app 2022-10-01 20:54:01 +05:30
Digger
6440e5e054 Translated using Weblate (Japanese)
Currently translated at 98.4% (621 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-10-01 04:18:30 +02:00
J-Jamet
0474e5b1fe Merge branch 'Sandelinos-themed-icons' into develop 2022-09-29 16:44:43 +02:00
Fjuro
15b84739e7 Translated using Weblate (Czech)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-09-28 19:19:26 +02:00
Fjuro
4bfe296e1a Translated using Weblate (Czech)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-09-27 08:57:42 +02:00
Stephan Paternotte
3fcc0db4f8 Translated using Weblate (Dutch)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-09-25 13:53:18 +02:00
Suman Garai
a8238565f3 Translated using Weblate (Bengali)
Currently translated at 57.2% (361 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bn/
2022-09-24 15:19:38 +02:00
Digger
53114462b3 Translated using Weblate (Japanese)
Currently translated at 98.2% (620 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-09-24 15:19:34 +02:00
Roee Hershberg
094da79cea Translated using Weblate (Hebrew)
Currently translated at 45.1% (285 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2022-09-24 15:19:33 +02:00
SC
f093206a1c Translated using Weblate (Portuguese)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-09-20 20:19:37 +02:00
Digger
5b4940d017 Translated using Weblate (Japanese)
Currently translated at 97.4% (615 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-09-20 20:19:36 +02:00
VfBFan
aee36eeec6 Translated using Weblate (German)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-09-20 20:19:36 +02:00
Digger
cc783f8be1 Translated using Weblate (Japanese)
Currently translated at 95.5% (603 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-09-18 06:24:10 +02:00
WB
a20f491cf1 Translated using Weblate (Galician)
Currently translated at 62.2% (393 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-09-17 18:16:24 +02:00
Anonimas
f5ff9bf263 Translated using Weblate (Lithuanian)
Currently translated at 30.4% (192 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/lt/
2022-09-17 18:16:23 +02:00
random r
dcba54b499 Translated using Weblate (Italian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-09-17 18:16:22 +02:00
zeritti
d1e103c1d7 Translated using Weblate (Czech)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-09-17 18:16:21 +02:00
Sandelinos
542daba206 Added monochrome icon 2022-09-17 00:42:47 +03:00
J-Jamet
94b61b1bbd Change KeePassX by KeeWeb 2022-09-16 09:19:43 +02:00
WB
718e590bfd Translated using Weblate (Galician)
Currently translated at 52.9% (334 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-09-15 21:22:54 +02:00
J-Jamet
9ce5e184c0 fix: try to not call BiometricManager methods if disabled #1400 2022-09-15 18:47:19 +02:00
J-Jamet
dbc477765f fix: upgrade to 3.5.0beta02 2022-09-15 15:05:38 +02:00
J-Jamet
92fcadf3f3 fix: attachment download button #1401 2022-09-15 15:04:24 +02:00
WB
c437fd96a8 Translated using Weblate (Galician)
Currently translated at 41.0% (259 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-09-14 05:15:57 +02:00
Vitor Henrique
10d33ecb82 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.6% (629 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-09-14 05:15:54 +02:00
Vitor Henrique
d506c0cb27 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.0% (606 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-09-11 22:18:00 +02:00
Milo Ivir
acac7f7540 Translated using Weblate (Croatian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-09-10 19:49:28 +02:00
Roee Hershberg
c853bd282a Translated using Weblate (Hebrew)
Currently translated at 37.7% (238 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/he/
2022-09-10 19:49:28 +02:00
J-Jamet
ecc4550261 Add Deutsh description 2022-09-07 22:42:18 +02:00
Linerly
c26ece7166 Translated using Weblate (Indonesian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-09-07 02:15:21 +02:00
nautilusx
88b50c7902 Translated using Weblate (German)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-09-07 02:15:20 +02:00
J-Jamet
7ba2cdd6ff Revert "fix: Change key driver url"
This reverts commit 941f9bcd48.
2022-09-06 09:29:41 +02:00
J-Jamet
589d9a2f1d Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2022-09-04 18:24:06 +02:00
Oğuz Ersen
a92411b95b Translated using Weblate (Turkish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-09-04 17:54:45 +02:00
Eric
472051bd24 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-09-04 17:54:44 +02:00
Ihor Hordiichuk
e5109a1f43 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-09-04 17:54:44 +02:00
solokot
f7ae9e3574 Translated using Weblate (Russian)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-09-04 17:54:43 +02:00
Matthaiks
170ec3c636 Translated using Weblate (Polish)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-09-04 17:54:43 +02:00
Retrial
1ab3fa8b3b Translated using Weblate (Greek)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-09-04 17:54:43 +02:00
J-Jamet
8b046512e3 fix: upgrade Gemfile.lock 2022-09-04 14:20:36 +02:00
J-Jamet
228a10c8e0 Merge branch 'translations' into develop 2022-09-04 12:24:32 +02:00
J-Jamet
9c53bea190 fix: replace <strong> tags 2022-09-04 12:23:49 +02:00
J-Jamet
11cf991498 Merge branch 'develop' of https://hosted.weblate.org/projects/keepass-dx/strings into translations 2022-09-04 12:15:55 +02:00
J-Jamet
a88c3721b2 Merge branch 'translations' into develop 2022-09-04 12:14:33 +02:00
J-Jamet
0b4b6d4d91 feat: upgrade to 3.5.0 2022-09-04 12:13:19 +02:00
J-Jamet
941f9bcd48 fix: Change key driver url 2022-09-03 23:03:11 +02:00
Jérémy JAMET
09988a858d Add badge in README.md 2022-09-03 22:12:17 +02:00
solokot
f1bf9fb25c Translated using Weblate (Russian)
Currently translated at 99.5% (628 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-09-03 19:24:05 +02:00
Matthaiks
1751fa49c0 Translated using Weblate (Polish)
Currently translated at 99.6% (629 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-09-03 19:24:05 +02:00
Kunzisoft
6b4fc9a4fa Translated using Weblate (French)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-09-03 19:24:04 +02:00
Retrial
7c8d85e428 Translated using Weblate (Greek)
Currently translated at 99.5% (628 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-09-03 19:24:04 +02:00
Allan Nordhøy
e335140f23 Translated using Weblate (English)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en/
2022-09-03 19:24:03 +02:00
Kunzisoft
d85f398b5f Translated using Weblate (English)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en/
2022-09-03 19:24:03 +02:00
Wilker Santana da Silva
a16082a59d Translated using Weblate (English)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en/
2022-09-03 19:11:24 +02:00
Kunzisoft
456269a343 Translated using Weblate (English)
Currently translated at 100.0% (631 of 631 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en/
2022-09-03 19:11:23 +02:00
J-Jamet
eb8e1e20eb fix: Remove cancel button for development dialog 2022-09-03 17:30:31 +02:00
Hosted Weblate
ed3c84fec0 Merge branch 'origin/develop' into Weblate. 2022-09-03 17:27:29 +02:00
J-Jamet
be40416a2d feat: Add privacy text in About section 2022-09-03 17:25:20 +02:00
PiQuark6046
5b5476a513 Translated using Weblate (Korean)
Currently translated at 35.0% (221 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ko/
2022-09-01 19:19:15 +02:00
random r
dc64dd6400 Translated using Weblate (Italian)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-09-01 19:19:14 +02:00
atilluF
eca02d3bde Translated using Weblate (Italian)
Currently translated at 97.4% (614 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-08-31 15:15:20 +02:00
SC
176b6c2936 Translated using Weblate (Portuguese)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-08-26 20:21:24 +02:00
J-Jamet
5b22350bdf fix: Hide clipboard text when copy entry field #1386 2022-08-23 11:56:29 +02:00
J-Jamet
6e1e011234 fix: exec gradlew version 7.5.1 to update scripts 2022-08-23 11:32:10 +02:00
J-Jamet
ac65ef6a5c Merge branch 'develop' of github.com:Kunzisoft/KeePassDX into develop 2022-08-23 11:26:35 +02:00
Jérémy JAMET
fc198dde74 Merge pull request #1387 from lberrymage/update-gradle
Upgrade Gradle to 7.5.1
2022-08-23 11:25:59 +02:00
lberrymage
15ac51b2fc Upgrade Gradle to 7.5.1
Generated by `./gradlew wrapper --gradle-version 7.5.1`
2022-08-22 18:09:13 -08:00
J-Jamet
34214432e1 fix: upgrade libs 2022-08-17 23:01:45 +02:00
J-Jamet
361ca92493 fix: upgrade gradle plugin to 7.2.2 2022-08-17 22:56:50 +02:00
J-Jamet
e367051b80 fix: remove application/octet-stream file recognition #1211 2022-08-17 22:25:47 +02:00
Linerly
a2a4a50c5e Translated using Weblate (Indonesian)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-08-14 14:20:41 +02:00
Milo Ivir
afc74b2f2a Translated using Weblate (Croatian)
Currently translated at 99.2% (625 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-08-14 14:20:40 +02:00
devchung
fc756d1eaf Translated using Weblate (Chinese (Traditional))
Currently translated at 97.3% (613 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2022-08-14 14:20:39 +02:00
Eric
eb8a4b1e49 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-08-14 14:20:39 +02:00
Ihor Hordiichuk
8d258b3538 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-08-14 14:20:38 +02:00
solokot
a59cfa3477 Translated using Weblate (Russian)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-08-14 14:20:38 +02:00
Matthaiks
f1e513006e Translated using Weblate (Polish)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-08-14 14:20:37 +02:00
Retrial
9df5c8f439 Translated using Weblate (Greek)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-08-14 14:20:36 +02:00
Deleted User
3ae099accf Translated using Weblate (German)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-08-14 14:20:36 +02:00
VfBFan
bb3e9396f2 Translated using Weblate (German)
Currently translated at 100.0% (630 of 630 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-08-14 14:20:35 +02:00
Hosted Weblate
1628749bde Merge branch 'origin/develop' into Weblate. 2022-08-11 12:47:58 +02:00
J-Jamet
f2006b5e42 fix: show lock button hidden by screenshot mode banner #1377 2022-08-11 12:37:28 +02:00
GianpaMX
80d387d9e7 Add screenshot mode
* Add new screenshot mode entry under Settings -> App -> General
* Disable Screenshot mode  by default
* Add a screenshot mode indication at the bottom of the screen
* Set or clear window FLAG_SECURE accordingly
* Translate strings into Spanish
2022-08-10 15:19:09 +01:00
J-Jamet
4452b4d599 Merge branch 'feature/Hardware_Key' into develop 2022-08-08 14:00:21 +02:00
J-Jamet
dfeaeb9888 feature: todo open external app in f-droid 2022-08-08 13:57:51 +02:00
J-Jamet
7e45a20ee7 fix: Refactoring key driver app id 2022-08-07 23:27:59 +02:00
J-Jamet
f3fe92e4de Merge branch 'develop' into feature/Hardware_Key 2022-08-02 22:25:44 +02:00
J-Jamet
b606909c65 fix: Update libs and SDK to 32 2022-08-02 22:25:19 +02:00
J-Jamet
2882bb30d7 fix: Smaller advanced unlock UI 2022-08-02 21:47:33 +02:00
eamz8jpajok
5b62227e3f Translated using Weblate (German)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-07-28 23:21:09 +02:00
J-Jamet
8b6af6fd8a feat: Derive master key exception 2022-07-05 18:09:35 +02:00
J-Jamet
99e9a92953 fix: KDB opening 2022-07-05 17:55:12 +02:00
Noël Krähenbühl
9f626309c3 Translated using Weblate (English (United Kingdom))
Currently translated at 8.3% (51 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en_GB/
2022-06-25 17:16:13 +02:00
Anonimas
3fe7cf2bfd Translated using Weblate (Lithuanian)
Currently translated at 23.4% (143 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/lt/
2022-06-19 16:16:36 +02:00
Matthaiks
9b5c274b49 Translated using Weblate (Polish)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-06-18 00:19:02 +02:00
WB
46b350e7ac Translated using Weblate (Galician)
Currently translated at 23.4% (143 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/gl/
2022-06-16 00:19:34 +02:00
Óscar Fernández Díaz
22a4aeb108 Translated using Weblate (Spanish)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-06-14 00:19:14 +02:00
random r
332e116ba7 Translated using Weblate (Italian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-06-04 11:15:25 +02:00
Anonimas
8b594a1a1f Translated using Weblate (Lithuanian)
Currently translated at 22.9% (140 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/lt/
2022-06-02 18:17:01 +02:00
J-Jamet
ab23ec6d4d Merge tag '3.4.5' into develop
3.4.5
2022-06-02 11:29:08 +02:00
J-Jamet
0ef574d675 Merge branch 'release/3.4.5' 2022-06-02 11:29:00 +02:00
J-Jamet
6d15a2462d Merge branch 'translations' into develop 2022-06-02 11:02:57 +02:00
J-Jamet
24fcdeb7aa Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-06-02 11:01:11 +02:00
J-Jamet
13905db732 fix: searchable selection 2022-06-01 14:15:41 +02:00
J-Jamet
6e1c8e5bec fix: custom data in group (fix KeeShare) #1335 2022-06-01 12:41:01 +02:00
J-Jamet
9aa1d11b94 Change the order of the search filters 2022-05-31 18:46:46 +02:00
J-Jamet
6c9f359fae New clipboard manager #1343 2022-05-31 18:22:01 +02:00
J-Jamet
531ebcae85 Fix device credential unlocking #1344 2022-05-31 11:44:42 +02:00
J-Jamet
fe9601b510 Change to 3.4.5 2022-05-31 10:25:34 +02:00
Oymate
bdf7cc6ea0 Translated using Weblate (Bengali)
Currently translated at 15.7% (96 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bn/
2022-05-30 21:18:06 +02:00
Douglas Han
1cfe02af6f Translated using Weblate (Korean)
Currently translated at 28.0% (171 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ko/
2022-05-30 21:18:05 +02:00
J-Jamet
647e3f9383 Change intent challenge recognition 2022-05-30 18:19:01 +02:00
J-Jamet
597f52799d Cache to capture exception during database save 2022-05-30 16:59:33 +02:00
J-Jamet
a59e052ed8 Merge branch 'develop' into feature/Hardware_Key 2022-05-30 10:31:46 +02:00
J-Jamet
11da0a4500 Keep screen on by default when viewing an entry
Upgrade to 3.5.0
2022-05-30 10:31:18 +02:00
J-Jamet
fd736bd1c2 Keep screen on entry by default 2022-05-30 10:24:47 +02:00
Oymate
ca6a4bfeef Translated using Weblate (Bengali)
Currently translated at 7.2% (44 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bn/
2022-05-27 16:16:54 +02:00
Oymate
02e9debc42 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 15.2% (93 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bn_BD/
2022-05-27 16:16:53 +02:00
Oymate
9bc9bd8b95 Added translation using Weblate (Bengali) 2022-05-26 15:10:24 +02:00
Park JM
d810f79b7a Translated using Weblate (Korean)
Currently translated at 20.5% (125 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ko/
2022-05-24 11:17:53 +02:00
Milo Ivir
f3468951f1 Translated using Weblate (Croatian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-05-22 19:32:57 +02:00
Kunzisoft
7ec5badabb Translated using Weblate (French)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-05-20 22:17:36 +02:00
J-Jamet
1ff2f501ca Fix capture database exception 2022-05-19 21:22:13 +02:00
J-Jamet
cfcb49e233 Better management of exceptions 2022-05-19 21:16:29 +02:00
J-Jamet
467df2020e Fix merge 2022-05-19 19:48:43 +02:00
J-Jamet
a961b41de0 Fix file save outside of the app 2022-05-19 19:20:21 +02:00
J-Jamet
40e8d5225e Fix notification and save state 2022-05-19 15:54:34 +02:00
J-Jamet
bc755ae1df Fix progress message 2022-05-19 15:00:12 +02:00
J-Jamet
b1cb0c3786 Fix infinite loop 2022-05-19 13:41:38 +02:00
J-Jamet
090d0fa2db Encapsulate channels 2022-05-19 12:53:12 +02:00
J-Jamet
27918a12b0 Fix small bugs 2022-05-19 11:47:53 +02:00
J-Jamet
ba1498b0b2 Fix error message and better implementation 2022-05-19 11:15:28 +02:00
J-Jamet
cbde96dd82 Add waiting task message and cancellable 2022-05-18 19:49:18 +02:00
J-Jamet
344118a755 Better error management 2022-05-18 18:35:24 +02:00
J-Jamet
259c8a4bd9 Setting to remember hardware key 2022-05-18 16:39:35 +02:00
SHINJI.K
fe92e41e91 Translated using Weblate (Japanese)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-05-15 15:18:25 +02:00
zeritti
e58c2f2a99 Translated using Weblate (Czech)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-05-15 15:18:24 +02:00
J-Jamet
f4d5bd1bea Fix save and better write implementation 2022-05-11 15:26:49 +02:00
J-Jamet
20b352cabe Better code encapsulation 2022-05-11 14:19:32 +02:00
J-Jamet
20e35f1a69 Encapsulate database operations 2022-05-11 13:42:48 +02:00
J-Jamet
d963f56d0f Merge branch 'develop' into feature/Hardware_Key 2022-05-11 11:36:20 +02:00
J-Jamet
aecfbc7728 Upgrade gradle 2022-05-11 10:59:14 +02:00
J-Jamet
5734df89f0 Merge branch 'develop' into feature/Hardware_Key 2022-05-11 10:10:52 +02:00
J-Jamet
bdf9b864d4 Merge tag '3.4.4' into develop
3.4.4
2022-05-11 10:00:50 +02:00
J-Jamet
1c0f1a036b Merge branch 'release/3.4.4' 2022-05-11 10:00:42 +02:00
J-Jamet
327c9de464 Change main credential validation 2022-05-10 19:59:56 +02:00
J-Jamet
8b2f994769 Save database with challenge response 2022-05-10 15:02:22 +02:00
J-Jamet
a5e53d872b Open database with challenge response in service 2022-05-09 15:56:53 +02:00
Claudio
1868d90693 Translated using Weblate (Italian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-05-08 16:00:54 +02:00
bondlxv
da0c19e068 Translated using Weblate (Italian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-05-08 16:00:54 +02:00
jazzyjabroni
d1103d8db4 Translated using Weblate (Danish)
Currently translated at 84.8% (517 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2022-05-07 21:13:46 +02:00
solokot
b2e92646a1 Translated using Weblate (Russian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-05-06 18:36:13 +02:00
J-Jamet
19bc2444bc Merge branch 'develop' into feature/Hardware_Key 2022-05-05 16:15:03 +02:00
J-Jamet
831b649cbb Merge branch 'translations' into develop 2022-05-05 15:59:37 +02:00
Kunzisoft
ded3c204b9 Translated using Weblate (French)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-05-05 15:58:56 +02:00
Hosted Weblate
23eec5f066 Merge branch 'origin/develop' into Weblate. 2022-05-05 15:54:24 +02:00
J-Jamet
6c167090e1 Small changes 2022-05-05 15:50:51 +02:00
J-Jamet
7d9eca0d46 Small changes 2022-05-05 15:29:56 +02:00
J-Jamet
c551aff474 Upgrade libs 2022-05-05 15:10:30 +02:00
J-Jamet
e627745358 Prevent Tapjacking #1318 2022-05-05 14:49:36 +02:00
J-Jamet
5a30d9d2b5 * Fix crash in New Android 13 #1321
* Better backstack management for selection mode
2022-05-05 12:45:07 +02:00
Santosh Anantwal
0a46817bbc Translated using Weblate (Marathi)
Currently translated at 1.9% (12 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/mr/
2022-05-04 20:13:11 +02:00
Hosted Weblate
a4134fa8c8 Merge branch 'origin/develop' into Weblate. 2022-05-03 19:23:33 +02:00
Santosh Anantwal
683535a5a6 Translated using Weblate (Marathi)
Currently translated at 1.4% (9 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/mr/
2022-05-03 19:23:33 +02:00
Santosh Anantwal
edb53112c2 Added translation using Weblate (Marathi) 2022-05-03 19:01:31 +02:00
SHINJI.K
83a77af520 Translated using Weblate (Japanese)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-05-03 15:13:15 +02:00
SC
df3ae17c7b Translated using Weblate (Portuguese)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-05-01 10:10:24 +02:00
abidin toumi
4a1624a443 Translated using Weblate (Arabic)
Currently translated at 78.3% (477 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2022-05-01 10:10:24 +02:00
wqk317
a8de9f9f9f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-05-01 10:10:23 +02:00
hokonch
3aa5b40acd Translated using Weblate (Japanese)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-05-01 10:10:23 +02:00
wqk317
8400f3e874 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.6% (607 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 09:35:42 +02:00
wqk317
b40bca1913 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (608 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 09:18:00 +02:00
wqk317
7100257f31 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.1% (604 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 09:17:06 +02:00
SHINJI.K
17df1a4d8a Translated using Weblate (Japanese)
Currently translated at 98.0% (597 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:53:45 +02:00
hokonch
d7a5209c68 Translated using Weblate (Japanese)
Currently translated at 98.0% (597 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:53:45 +02:00
wqk317
076220eacd Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (608 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 08:43:03 +02:00
SHINJI.K
99a50f271a Translated using Weblate (Japanese)
Currently translated at 96.8% (590 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:43:03 +02:00
hokonch
63d265da06 Translated using Weblate (Japanese)
Currently translated at 96.8% (590 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:43:03 +02:00
wqk317
30e3624eb1 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (608 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 08:25:13 +02:00
Eric
88f3713e28 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (608 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 08:25:13 +02:00
wqk317
90f0c22545 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 08:23:43 +02:00
wqk317
8deed8468d Translated using Weblate (Chinese (Simplified))
Currently translated at 99.8% (608 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-30 08:21:23 +02:00
hokonch
923ad26b1b Translated using Weblate (Japanese)
Currently translated at 96.0% (585 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:17:37 +02:00
SHINJI.K
3bc858e4c2 Translated using Weblate (Japanese)
Currently translated at 96.0% (585 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:17:37 +02:00
SHINJI.K
f5a7fa41a7 Translated using Weblate (Japanese)
Currently translated at 95.5% (582 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:10:18 +02:00
hokonch
bf71d5508b Translated using Weblate (Japanese)
Currently translated at 95.5% (582 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-30 08:10:17 +02:00
J-Jamet
b44c9cfc51 Opening refactoring 2022-04-28 20:39:26 +02:00
J-Jamet
5b4338abae Better implementation for challenge response intent 2022-04-27 14:39:08 +02:00
John Veness
aa5adc28cb Translated using Weblate (English (United Kingdom))
Currently translated at 3.6% (22 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en_GB/
2022-04-26 20:07:59 +02:00
abidin toumi
2dad013cc0 Translated using Weblate (Arabic)
Currently translated at 75.8% (462 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2022-04-26 20:07:59 +02:00
solokot
7ade66f3ac Translated using Weblate (Russian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-04-26 20:07:58 +02:00
Stephan Paternotte
ed75a64b46 Translated using Weblate (Dutch)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-04-26 20:07:58 +02:00
Kunzisoft
e156b80d91 Translated using Weblate (French)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-04-26 20:07:58 +02:00
J-Jamet
e8f79ae467 Fix to open challenge-response dynamically / refactoring methods #8 2022-04-25 21:47:43 +02:00
Kunzisoft
90e4862280 Added translation using Weblate (English (United Kingdom)) 2022-04-25 18:22:17 +02:00
André Marcelo Alvarenga
438080d3d6 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-04-23 13:08:01 +02:00
SHINJI.K
3c17605764 Translated using Weblate (Japanese)
Currently translated at 94.2% (574 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-04-23 13:08:00 +02:00
VfBFan
3f68bc0eda Translated using Weblate (German)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-04-23 13:08:00 +02:00
J-Jamet
ecbee73eae Add view and first implementation of hardware key #8 2022-04-21 18:03:32 +02:00
J-Jamet
3e4452da00 Fix inherited view after orientation change 2022-04-21 17:43:24 +02:00
Linerly
549c690b56 Translated using Weblate (Indonesian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-04-21 01:11:05 +02:00
Oğuz Ersen
aabe06f29b Translated using Weblate (Turkish)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-04-21 01:11:05 +02:00
Eric
82693c5cd3 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-21 01:11:04 +02:00
Ihor Hordiichuk
37a4f26d2f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-04-21 01:11:04 +02:00
solokot
ca94063c7b Translated using Weblate (Russian)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-04-21 01:11:04 +02:00
Matthaiks
eadc4bf6c2 Translated using Weblate (Polish)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-04-21 01:11:03 +02:00
Retrial
b1c307c86b Translated using Weblate (Greek)
Currently translated at 100.0% (609 of 609 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-04-21 01:11:03 +02:00
J-Jamet
1874a0056d Merge branch 'develop' into feature/Hardware_Key 2022-04-20 14:24:10 +02:00
J-Jamet
48331f9552 Merge tag '3.4.3' into develop
3.4.3
2022-04-19 21:17:37 +02:00
J-Jamet
f907aa578a Merge branch 'release/3.4.3' 2022-04-19 21:17:31 +02:00
J-Jamet
41e2620cc1 Generate auto description for github repo 2022-04-19 21:16:55 +02:00
J-Jamet
e7a82b167a fix Fastfile 2022-04-19 18:18:15 +02:00
J-Jamet
088c556b00 Update fastlane to copy the release file with name 2022-04-19 18:04:12 +02:00
J-Jamet
c80343b6d4 Remove unused import 2022-04-19 16:41:13 +02:00
J-Jamet
4e52a8cf60 Show visual title when entry is available in Magikeyboard 2022-04-19 16:10:40 +02:00
J-Jamet
1ed1d4233f Allow to add entry with no info in Magikeyboard 2022-04-19 16:06:16 +02:00
J-Jamet
6e4626bc02 Fix ask lock when database can be saved 2022-04-19 15:47:21 +02:00
J-Jamet
2608ae247f Fix quick search and better loadGroup implementation #1302 2022-04-19 14:35:28 +02:00
J-Jamet
785586bfe9 Remove "Select share info" setting for Magikeyboard #1304 2022-04-19 12:24:51 +02:00
J-Jamet
bdcbb177ae Upgrade to 3.4.3 2022-04-19 11:36:04 +02:00
J-Jamet
15ac365d79 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-04-15 19:29:56 +02:00
Braja Yudhistira
debbcb753b Translated using Weblate (Indonesian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-04-15 18:27:39 +02:00
Linerly
69d73aeaa4 Translated using Weblate (Indonesian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-04-15 18:27:39 +02:00
solokot
dffe53370f Translated using Weblate (Russian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-04-15 18:27:37 +02:00
Darin Avdeyeva
4334e6dcdf Translated using Weblate (Russian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-04-15 18:27:37 +02:00
Stephan Paternotte
c2c6c093d5 Translated using Weblate (Dutch)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-04-15 18:27:36 +02:00
Cow
77e539eec2 Translated using Weblate (Spanish)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-04-15 18:27:36 +02:00
J-Jamet
a57970210e Merge tag '3.4.2' into develop
3.4.2
2022-04-15 13:42:49 +02:00
J-Jamet
1b31a46fb7 Merge branch 'release/3.4.2' 2022-04-15 13:42:43 +02:00
J-Jamet
87f19c74fc Add clean in fastlane 2022-04-15 13:23:25 +02:00
J-Jamet
bd157a9724 Fix small UI color 2022-04-15 13:18:11 +02:00
J-Jamet
5a327eb0db Catch reset app timeout for unexpected exceptions 2022-04-15 13:00:41 +02:00
J-Jamet
4b9c0b0109 Fix navigation bar color in dark mode 2022-04-15 12:54:10 +02:00
J-Jamet
df6b75cdbb Fix color 2022-04-15 12:47:50 +02:00
J-Jamet
0b4f8c122b Fix color 2022-04-15 12:46:37 +02:00
J-Jamet
2a87eaf3e5 Upgrade to 3.4.2 and fix service parameter and workflow 2022-04-15 12:21:14 +02:00
J-Jamet
c52266f5cf Merge branch 'master' of github.com:Kunzisoft/KeePassDX 2022-04-14 19:28:49 +02:00
J-Jamet
3b21f8add2 Merge tag '3.4.1' into develop
3.4.1
2022-04-14 19:28:12 +02:00
J-Jamet
6574bd10a0 Merge branch 'release/3.4.1' 2022-04-14 19:28:05 +02:00
J-Jamet
23f3335988 Update version code for deployment 2022-04-14 19:17:49 +02:00
J-Jamet
a5d7f33c82 Fix unexpected lock of the app #1294 2022-04-14 19:11:33 +02:00
J-Jamet
3782c4dac0 Fix styles 2022-04-14 17:17:38 +02:00
J-Jamet
1fc02fd2fe Small UI changes 2022-04-14 15:16:32 +02:00
J-Jamet
cc347c1dbe Update strings 2022-04-14 15:07:32 +02:00
J-Jamet
79ff20eb18 Remove irrelevant Autofill autosearch setting 2022-04-14 14:55:00 +02:00
J-Jamet
e6e8a447da Clear focus in autosearch and update CHANGELOG 2022-04-14 14:32:34 +02:00
J-Jamet
233f0c5bdb Fix another entry in selection mode with Magikeyboard #1293 2022-04-14 14:12:35 +02:00
J-Jamet
9ed4271a14 Fix search mode with Magikeyboard #1292 2022-04-14 12:50:33 +02:00
J-Jamet
470c0b6b43 Update README description 2022-04-14 11:54:16 +02:00
J-Jamet
afa8ae42b9 Upgrade gradle to 3.4.1 2022-04-14 11:45:55 +02:00
Jérémy JAMET
63d426503f Update FUNDING.yml
Fix issuehunt
2022-04-12 20:43:48 +02:00
Jérémy JAMET
ffb7f80b26 Create FUNDING.yml 2022-04-12 20:42:35 +02:00
J-Jamet
63f8826fd8 Merge branch 'master' into develop 2022-04-12 20:08:21 +02:00
J-Jamet
ef836e8b84 Change screenshots 2022-04-12 20:08:10 +02:00
J-Jamet
abc1c43a51 Merge tag '3.4.0' into develop
3.4.0
2022-04-12 19:45:17 +02:00
J-Jamet
6b54dd9e0d Merge branch 'release/3.4.0' 2022-04-12 19:45:10 +02:00
J-Jamet
1f54e7752d Disable keyboard timeout by default 2022-04-12 15:04:12 +02:00
J-Jamet
6ac941f276 Upgrade to 3.4.0 2022-04-12 14:58:13 +02:00
Hosted Weblate
a4fe92562f Merge branch 'origin/develop' into Weblate. 2022-04-12 12:39:39 +02:00
SC
b9bd1d9d4b Translated using Weblate (Portuguese)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-04-12 12:39:39 +02:00
Milo Ivir
3b6c28488a Translated using Weblate (Croatian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-04-12 12:39:38 +02:00
Eric
875eb3500d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-12 12:39:38 +02:00
Ihor Hordiichuk
3a88a2451c Translated using Weblate (Ukrainian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-04-12 12:39:37 +02:00
solokot
6800b73a4f Translated using Weblate (Russian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-04-12 12:39:37 +02:00
Matthaiks
983404e6d8 Translated using Weblate (Polish)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-04-12 12:39:37 +02:00
Retrial
b95c0a18a7 Translated using Weblate (Greek)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-04-12 12:39:36 +02:00
VfBFan
36b317cad8 Translated using Weblate (German)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-04-12 12:39:36 +02:00
Sebastian
35d74888fb Translated using Weblate (Danish)
Currently translated at 84.3% (517 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2022-04-12 12:39:36 +02:00
J-Jamet
6c308483f7 Upgrade gradle and kotlin 2022-04-12 12:31:18 +02:00
J-Jamet
9d25fb74ec Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-04-12 12:14:23 +02:00
J-Jamet
d217b52744 Upgrade to 3.4.0_beta02
Fix #1282 with workaround
2022-04-12 12:12:05 +02:00
J-Jamet
319da4b174 Rollback openOutputStream in "rwt" 2022-04-12 11:32:49 +02:00
nautilusx
9bee467942 Translated using Weblate (German)
Currently translated at 99.6% (611 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-04-12 07:46:27 +02:00
VfBFan
44ac70fc97 Translated using Weblate (German)
Currently translated at 99.6% (611 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-04-12 07:46:26 +02:00
J-Jamet
d897611d62 Change main screenshot 2022-04-10 17:21:35 +02:00
J-Jamet
c2ae251e73 Change screenshots 2022-04-10 17:10:01 +02:00
J-Jamet
35ad285864 Fix education screen 2022-04-09 16:52:25 +02:00
J-Jamet
97bdae21eb Small change 2022-04-09 16:37:11 +02:00
J-Jamet
d6dc6e43c7 Update strings 2022-04-09 16:35:20 +02:00
Oğuz Ersen
01e6e530d5 Translated using Weblate (Turkish)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-04-09 16:28:35 +02:00
Kunzisoft
9ec0178beb Translated using Weblate (French)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-04-09 16:28:35 +02:00
Hosted Weblate
d66f2f6d24 Merge branch 'origin/develop' into Weblate. 2022-04-09 16:15:08 +02:00
Milo Ivir
79cd4004cc Translated using Weblate (Croatian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-04-09 16:15:08 +02:00
VfBFan
991243e2df Translated using Weblate (German)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-04-09 16:15:07 +02:00
J-Jamet
b91cf11d86 Upgrade to 3.4 beta01 2022-04-09 16:14:15 +02:00
J-Jamet
d182ec09fa Upgrade CHANGELOG 2022-04-09 16:12:57 +02:00
J-Jamet
8641822358 Fix small bugs 2022-04-09 16:03:12 +02:00
J-Jamet
9665cbb428 Fix small visual bug 2022-04-08 18:37:06 +02:00
J-Jamet
a280dfaf3b Better magikeyboard views 2022-04-08 18:23:02 +02:00
J-Jamet
3e56521ea8 Empty Magikeyboard memory when the main service is killed #1261 2022-04-08 16:53:03 +02:00
SC
b205230ea9 Translated using Weblate (Portuguese)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-04-08 09:31:01 +02:00
Oğuz Ersen
51645ab126 Translated using Weblate (Turkish)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-04-08 09:31:00 +02:00
Eric
5d04897e75 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-04-08 09:30:59 +02:00
Ihor Hordiichuk
1ac0ea5cc6 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-04-08 09:30:59 +02:00
solokot
a07e8b51e5 Translated using Weblate (Russian)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-04-08 09:30:58 +02:00
Vitor Henrique
a81f0238f4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-04-08 09:30:57 +02:00
Matthaiks
2b81eb8ec7 Translated using Weblate (Polish)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-04-08 09:30:56 +02:00
Retrial
e5eb642781 Translated using Weblate (Greek)
Currently translated at 100.0% (613 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-04-08 09:30:56 +02:00
VfBFan
a4cbe25733 Translated using Weblate (German)
Currently translated at 99.8% (612 of 613 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-04-08 09:30:55 +02:00
J-Jamet
2042c85b22 Ask confirmation to lock if changes without save #970 2022-04-07 18:06:47 +02:00
J-Jamet
3149f8745c Fix passkey view 2022-04-07 17:39:46 +02:00
J-Jamet
15b9f1616f Fix keyboard search and selection 2022-04-07 14:28:45 +02:00
J-Jamet
94c02b7288 Fix selection mode instance issue 2022-04-07 13:26:07 +02:00
J-Jamet
7e70b59a59 Fix selection mode instance issue 2022-04-07 13:22:19 +02:00
Hosted Weblate
2c7f5e41ed Merge branch 'origin/develop' into Weblate. 2022-04-05 18:00:37 +02:00
J-Jamet
108b8df280 Fix CHANGELOG issue number 2022-04-05 15:32:42 +02:00
J-Jamet
553098f9be Manage package name from Magikeyboard #1010 2022-04-05 15:28:15 +02:00
J-Jamet
131eb78407 Setting to change the keyboard during a search #1254 2022-04-05 13:38:36 +02:00
J-Jamet
f956a279a5 Save search parameters #1254 2022-04-05 13:07:36 +02:00
J-Jamet
7150686b92 Fix search parameter parcelable 2022-04-05 11:59:02 +02:00
J-Jamet
4b1fb2c173 Upgrade CHANGELOG 2022-04-05 11:28:58 +02:00
J-Jamet
94464bf608 Save pass generator options in app.properties 2022-04-04 15:30:57 +02:00
J-Jamet
2faa88784a Update CHANGELOG 2022-04-04 15:09:32 +02:00
J-Jamet
e6607b53d8 Better search implementation #175 2022-04-04 15:08:11 +02:00
J-Jamet
3f6a6c864a Show TOTP in 3-digit grouping #1270 2022-04-04 13:25:01 +02:00
J-Jamet
30a578257d Update CHANGELOG 2022-04-04 13:07:38 +02:00
J-Jamet
8411134adf Save files with "wt" #1282 2022-04-04 12:21:35 +02:00
J-Jamet
f86a5d1a19 Fix small bug 2022-04-01 19:19:47 +02:00
J-Jamet
be72492537 Merge branch 'feature/Mnemonics' into develop 2022-04-01 19:14:07 +02:00
J-Jamet
76f9e8ec6e Generate passphrase #218 2022-04-01 19:08:50 +02:00
Milo Ivir
8fb1c44e58 Translated using Weblate (Croatian)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-04-01 13:08:19 +02:00
J-Jamet
f607b35cf3 Change max slider to 64 2022-04-01 11:01:00 +02:00
J-Jamet
0e56bec35a Key generator as tabs 2022-04-01 10:51:38 +02:00
Hosted Weblate
c890d10114 Merge branch 'origin/develop' into Weblate. 2022-03-31 12:09:22 +02:00
Milo Ivir
dee2fe5ce7 Translated using Weblate (Croatian)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-03-31 12:09:21 +02:00
J-Jamet
4a4d767bce Manage setting to hide password #696 2022-03-29 17:18:49 +02:00
J-Jamet
d57e0cf601 Add setting to colorize password 2022-03-29 16:41:23 +02:00
J-Jamet
7fa141dd1b Merge branch 'develop' into feature/Mnemonics 2022-03-29 16:01:50 +02:00
J-Jamet
c261a0cbca Smaller tab buttons 2022-03-29 16:01:20 +02:00
J-Jamet
66661cbd49 Add bold and change password colors 2022-03-29 15:54:37 +02:00
J-Jamet
100c126c3d Update CHANGELOG 2022-03-29 15:32:51 +02:00
J-Jamet
d466e3077d Add color for special password chars #454 2022-03-29 15:32:29 +02:00
J-Jamet
24587dc34e Small refactorization 2022-03-29 12:42:53 +02:00
J-Jamet
32cc57dd03 Add editable chars fields #539 2022-03-28 22:14:24 +02:00
J-Jamet
a55488846b Add advanced password filters #1052 2022-03-28 21:26:26 +02:00
J-Jamet
dcf61fd4e2 Update CHANGELOG 2022-03-28 16:34:37 +02:00
J-Jamet
5bf998468a Save password preferences dynamically 2022-03-28 16:24:25 +02:00
J-Jamet
01c9625c59 Dynamic filter change and fix bugs 2022-03-28 15:08:56 +02:00
Dixon Huang
772c378922 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hant/
2022-03-28 13:09:14 +02:00
J-Jamet
ee50a91379 Move entropy to the top 2022-03-27 21:40:13 +02:00
J-Jamet
9cfda3bad8 Fix small bugs 2022-03-27 21:33:44 +02:00
J-Jamet
aa19b08bd9 Fix password entropy and add chips 2022-03-27 20:41:51 +02:00
J-Jamet
87f69bb7e2 Entropy #869 2022-03-27 18:56:12 +02:00
J-Jamet
41c0aeedbe Show visual password strength indicator #631 2022-03-27 17:22:52 +02:00
Eric
3cbe53d76f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-03-27 00:27:21 +01:00
Ihor Hordiichuk
aed60d6c1e Translated using Weblate (Ukrainian)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-03-27 00:27:21 +01:00
Stephan Paternotte
be7d35490d Translated using Weblate (Dutch)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-03-27 00:27:20 +01:00
VfBFan
d0ea997c63 Translated using Weblate (German)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-03-27 00:27:20 +01:00
J-Jamet
1fecffeba2 Merge branch 'master' of github.com:Kunzisoft/KeePassDX 2022-03-26 16:28:39 +01:00
J-Jamet
76319a56a2 Merge tag '3.3.3' into develop
3.3.3
2022-03-26 16:27:23 +01:00
J-Jamet
1d71de7031 Merge branch 'release/3.3.3' 2022-03-26 16:27:15 +01:00
Oğuz Ersen
e9a1cfea11 Translated using Weblate (Turkish)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-03-26 04:15:30 +01:00
solokot
9115856d19 Translated using Weblate (Russian)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-03-26 04:15:30 +01:00
Matthaiks
8c45266c18 Translated using Weblate (Polish)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-03-26 04:15:29 +01:00
Retrial
6b4130df89 Translated using Weblate (Greek)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-03-26 04:15:29 +01:00
J-Jamet
e3e10e7dfa Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-03-25 16:03:08 +01:00
Kunzisoft
cbf900004d Translated using Weblate (French)
Currently translated at 100.0% (595 of 595 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-03-25 16:03:01 +01:00
J-Jamet
51b36dc460 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-03-25 16:02:20 +01:00
Hosted Weblate
9f8016afe2 Merge branch 'origin/develop' into Weblate. 2022-03-25 15:56:17 +01:00
abidin toumi
d5a36db50a Translated using Weblate (Arabic)
Currently translated at 77.0% (457 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2022-03-25 15:56:17 +01:00
J-Jamet
ecd458d8d0 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-03-25 15:52:56 +01:00
J-Jamet
9088297c41 Fix small bugs 2022-03-25 15:48:33 +01:00
J-Jamet
5282deb088 Tabs to show main and advanced content separately 2022-03-25 15:32:48 +01:00
J-Jamet
75d661f12b Add a warning to inform about KeyStore usage #1269 2022-03-25 13:09:08 +01:00
J-Jamet
83bc769d9e Upgrade CHANGELOG 2022-03-23 20:10:39 +01:00
J-Jamet
8324acadc8 Toast when trying to open another database 2022-03-23 18:31:20 +01:00
J-Jamet
6e42db41be Fix shared otpauth link if database not open #1274 2022-03-23 18:03:32 +01:00
J-Jamet
3917bfc9e6 Update CHANGELOG 2022-03-23 17:46:42 +01:00
J-Jamet
d11febb1ce Ellipsize attachment name #1253 2022-03-23 17:41:51 +01:00
J-Jamet
360eb6f9cc Fix URL color 2022-03-23 15:40:08 +01:00
J-Jamet
e4ac5d01d0 Fingerprint unlock no more by default 2022-03-23 15:01:07 +01:00
J-Jamet
6a51fc0668 Fix settings title 2022-03-23 14:18:26 +01:00
J-Jamet
ba03f07fbe Replace Libre UI logo when no biometric 2022-03-23 13:34:04 +01:00
J-Jamet
7bf7d63f64 Better UI when no biometric is available 2022-03-23 13:13:29 +01:00
J-Jamet
d3efaabc24 Rollback algorithm 2022-03-23 09:29:45 +01:00
J-Jamet
b4283ed98b Small improvement 2022-03-23 09:15:36 +01:00
J-Jamet
de407e4cf9 Remove unused package 2022-03-20 16:40:19 +01:00
J-Jamet
60ed3a9836 Upgrade to 3.3.3 2022-03-19 15:53:00 +01:00
Jérémy JAMET
7948358d85 Add spaces in issue template 2022-03-18 19:46:32 +01:00
Jérémy JAMET
96b82bb9b2 Remove "please report..." in issue template 2022-03-18 19:45:39 +01:00
Stephan Paternotte
699ccf13f0 Translated using Weblate (Dutch)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-03-18 06:55:47 +01:00
Pavel Borecki
ae88aa4e42 Translated using Weblate (Czech)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-03-18 06:55:47 +01:00
J-Jamet
bcce13b12f Merge tag '3.3.2' into develop
3.3.2
2022-03-15 20:21:53 +01:00
J-Jamet
4fd4f660a7 Merge branch 'release/3.3.2' 2022-03-15 20:21:45 +01:00
J-Jamet
518e59b33c Merge branch 'App_Store_Merge' into release/3.3.2 2022-03-15 18:56:44 +01:00
J-Jamet
165cdcc00d Upgrade to 3.3.2 2022-03-15 18:52:05 +01:00
J-Jamet
48c2115fdf Fix small bugs 2022-03-15 13:17:23 +01:00
Stephan Paternotte
d7d68ccdeb Translated using Weblate (Dutch)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-03-11 00:00:32 +01:00
abidin toumi
5cf6362db4 Translated using Weblate (Arabic)
Currently translated at 77.5% (460 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2022-03-10 17:56:43 +01:00
Matthaiks
4efcc48160 Translated using Weblate (Polish)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-03-10 17:56:43 +01:00
Raghav Kabra
383274ce0f Translated using Weblate (Hindi)
Currently translated at 25.1% (149 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hi/
2022-03-07 12:00:12 +01:00
abidin toumi
c9dec3a2f7 Translated using Weblate (Arabic)
Currently translated at 77.2% (458 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2022-03-07 12:00:11 +01:00
Wilker Santana da Silva
2d4bf2903b Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-03-07 12:00:11 +01:00
Nextross
2b88cfbda0 Translated using Weblate (Czech)
Currently translated at 98.6% (585 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-03-07 12:00:10 +01:00
Raghav Kabra
eb6ab7a156 Translated using Weblate (Hindi)
Currently translated at 23.9% (142 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hi/
2022-03-05 17:21:22 +01:00
J-Jamet
9bed7bf213 Remove Pro version in fastlane 2022-03-03 16:58:28 +01:00
J-Jamet
99c2796014 Change icons and remove pro version 2022-03-03 16:50:46 +01:00
J-Jamet
9ee9bf12ae Replace icons 2022-03-03 13:10:10 +01:00
SC
688cbe50f2 Translated using Weblate (Portuguese)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-03-02 19:55:26 +01:00
VfBFan
e0577d1628 Translated using Weblate (German)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-03-02 19:55:25 +01:00
J-Jamet
de70925f8a Upgrade Gradle 2022-03-02 16:46:12 +01:00
Stephan Paternotte
0f8dd17fde Translated using Weblate (Dutch)
Currently translated at 99.4% (590 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-02-27 22:57:39 +01:00
Óscar Fernández Díaz
4bc8a08606 Translated using Weblate (Spanish)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-02-27 19:54:08 +01:00
Retrial
cf34433186 Translated using Weblate (Greek)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-02-27 19:54:07 +01:00
J-Jamet
21113d6fc8 Merge tag '3.3.1' into develop
3.3.1
2022-02-26 18:17:07 +01:00
J-Jamet
d7decba3f5 Merge branch 'release/3.3.1' 2022-02-26 18:16:59 +01:00
Oğuz Ersen
671364f395 Translated using Weblate (Turkish)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-02-26 17:20:50 +01:00
Eric
d0072237e7 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-02-26 17:20:50 +01:00
Ihor Hordiichuk
d11c001e0d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-02-26 17:20:50 +01:00
solokot
a197453ce0 Translated using Weblate (Russian)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-02-26 17:20:49 +01:00
Matthaiks
d1586a8d80 Translated using Weblate (Polish)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-02-26 17:20:49 +01:00
Kunzisoft
6e959e415f Translated using Weblate (French)
Currently translated at 100.0% (593 of 593 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-02-26 17:20:49 +01:00
J-Jamet
8a8e14701b Merge branch 'translations' into develop 2022-02-26 17:14:07 +01:00
J-Jamet
60bb144020 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-02-26 17:13:29 +01:00
J-Jamet
b561db3a67 Workaround to fill OTP token in multiple fields with Magikeyboard (long press) #1158 2022-02-26 15:19:06 +01:00
J-Jamet
b0e722acce Best autofill recognition #1250 2022-02-26 15:18:08 +01:00
J-Jamet
279bd16b74 Best autofill recognition #1250 2022-02-26 13:13:07 +01:00
J-Jamet
2e0081b66c Prepare hardware key in main credential 2022-02-26 12:51:00 +01:00
J-Jamet
f79d32b22b Fix temp advanced unlocking #1245 2022-02-26 12:45:59 +01:00
Hosted Weblate
3579606d1e Merge branch 'origin/develop' into Weblate. 2022-02-26 12:31:54 +01:00
J-Jamet
b93c6266a6 Upgrade CHANGELOG 2022-02-26 12:30:28 +01:00
J-Jamet
ea9c530667 Fix "other" search filter 2022-02-26 12:29:07 +01:00
J-Jamet
6ea95c050a Fix filter string #1249 2022-02-26 12:14:04 +01:00
SC
5a99a28195 Translated using Weblate (Portuguese)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-02-25 20:55:58 +01:00
Vitor Henrique
0cd5351c07 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.8% (585 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-02-25 20:55:58 +01:00
VfBFan
148bed801b Translated using Weblate (German)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-02-25 20:55:57 +01:00
Larry Day
87a1a3ba1b Translated using Weblate (Czech)
Currently translated at 96.7% (573 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-02-25 20:55:57 +01:00
J-Jamet
20d2c10bba Upgrade room to 2.4.2 2022-02-25 12:50:01 +01:00
J-Jamet
3eed5e395e Upgrade to 3.3.1
Fix Japanese keyboard in search #1248
2022-02-25 12:44:38 +01:00
Oğuz Ersen
870fbaa05c Translated using Weblate (Turkish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-02-22 01:54:58 +01:00
Eric
55868f68da Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-02-22 01:54:58 +01:00
Ihor Hordiichuk
e6f0fbeab5 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-02-22 01:54:58 +01:00
solokot
8a554349b5 Translated using Weblate (Russian)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-02-22 01:54:57 +01:00
Matthaiks
ab87d4e564 Translated using Weblate (Polish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-02-22 01:54:57 +01:00
Éfrit
8400a83b70 Translated using Weblate (French)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-02-22 01:54:57 +01:00
Jeffree Romero
5d2caa37a9 Translated using Weblate (Spanish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-02-22 01:54:57 +01:00
Retrial
a6b7cfc2d3 Translated using Weblate (Greek)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-02-22 01:54:56 +01:00
J-Jamet
74107b90bb Max binary byte as 10 MB to prevent OOM #256 2022-02-20 17:16:36 +01:00
Hosted Weblate
9f4a915d43 Merge branch 'origin/develop' into Weblate. 2022-02-19 11:29:30 +01:00
Ismael Mirabile
3f1f22e1c3 Translated using Weblate (German)
Currently translated at 99.6% (590 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-02-19 11:29:30 +01:00
J-Jamet
1d98eb2b95 Merge tag '3.3.0' into develop
3.3.0
2022-02-19 11:01:11 +01:00
J-Jamet
f1b56fed16 Merge branch 'release/3.3.0' 2022-02-19 11:01:02 +01:00
J-Jamet
23e75c56ed Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-02-19 10:35:52 +01:00
J-Jamet
eafc9cc1fa Fix merge in kdb database 2022-02-19 10:31:29 +01:00
J-Jamet
3e3dbb22df Upgrade to version code 102 2022-02-19 10:21:24 +01:00
J-Jamet
127b8ba0bd Smaller time to the back to app handler 2022-02-18 17:46:12 +01:00
J-Jamet
8a8e588a01 Fix save search info 2022-02-18 17:30:25 +01:00
J-Jamet
3c1b010821 Default https if scheme is null 2022-02-18 15:27:49 +01:00
J-Jamet
739c938576 Fix save and app instance in selection mode 2022-02-18 15:09:15 +01:00
J-Jamet
69fed0c347 Remove redundant label 2022-02-18 13:37:25 +01:00
J-Jamet
d040258296 Fix lock button in settings 2022-02-18 13:14:33 +01:00
J-Jamet
abee18839b Fix selection mode 2022-02-18 13:12:01 +01:00
J-Jamet
9c0eb4e27e Upgrade to version 3.3.0_beta04 2022-02-18 11:32:00 +01:00
J-Jamet
10598ef5e5 Fix education hints #1192 2022-02-18 10:31:24 +01:00
J-Jamet
fa09e2d21d Refactoring education 2022-02-18 09:39:29 +01:00
Oğuz Ersen
11ddfe3445 Translated using Weblate (Turkish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-02-17 20:55:25 +01:00
Eric
9abbc8876b Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-02-17 20:55:24 +01:00
Ihor Hordiichuk
c5cf99e13d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-02-17 20:55:24 +01:00
solokot
82ac1c8f5e Translated using Weblate (Russian)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-02-17 20:55:24 +01:00
Matthaiks
837f8146e4 Translated using Weblate (Polish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-02-17 20:55:24 +01:00
Kunzisoft
9698c3f2ee Translated using Weblate (French)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-02-17 20:55:23 +01:00
Retrial
85290b8f9d Translated using Weblate (Greek)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-02-17 20:55:23 +01:00
J-Jamet
1ccf48d7a5 Simpler fragment main credential view 2022-02-16 19:40:47 +01:00
J-Jamet
2cbec9f2b6 Change version code -> 100 Happy Bithcode 2022-02-16 19:30:12 +01:00
J-Jamet
692be415fa Fix small string 2022-02-16 19:16:45 +01:00
J-Jamet
83d5218f92 Fix view init for timeout 2022-02-16 19:13:41 +01:00
J-Jamet
324b016324 Remove unused file 2022-02-16 19:09:38 +01:00
J-Jamet
005c9673f7 Fix history banner color 2022-02-16 18:55:04 +01:00
J-Jamet
b8762dc6e0 Upgrade CHANGELOG number 2022-02-16 13:31:56 +01:00
J-Jamet
93abff0768 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-02-16 13:19:49 +01:00
Hosted Weblate
ac1cfb43d8 Merge branch 'origin/develop' into Weblate. 2022-02-16 13:19:07 +01:00
Oğuz Ersen
30ec712782 Translated using Weblate (Turkish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-02-16 13:18:57 +01:00
Eric
bbd93fbc5b Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-02-16 13:18:57 +01:00
Ihor Hordiichuk
c46cbaff4b Translated using Weblate (Ukrainian)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-02-16 13:18:56 +01:00
solokot
1e979b256a Translated using Weblate (Russian)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-02-16 13:18:56 +01:00
Vitor Henrique
50429b419f Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.6% (578 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-02-16 13:18:55 +01:00
Matthaiks
2c540be5a3 Translated using Weblate (Polish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-02-16 13:18:54 +01:00
random r
155d3d222f Translated using Weblate (Italian)
Currently translated at 99.8% (591 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-02-16 13:18:54 +01:00
Kunzisoft
3fc3bf1302 Translated using Weblate (French)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-02-16 13:18:53 +01:00
Óscar Fernández Díaz
f0fafbbc6e Translated using Weblate (Spanish)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-02-16 13:18:53 +01:00
Retrial
5f7d980d89 Translated using Weblate (Greek)
Currently translated at 100.0% (592 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-02-16 13:18:52 +01:00
C. Rüdinger
c3799ed7fe Translated using Weblate (German)
Currently translated at 99.4% (589 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-02-16 13:18:52 +01:00
J-Jamet
f7533af5d8 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-02-16 13:12:58 +01:00
J-Jamet
2c9504fb93 Upgrade strings 2022-02-16 13:12:26 +01:00
J-Jamet
c22b3f5335 Upgrade libs 2022-02-16 13:01:05 +01:00
J-Jamet
2aea7fd46d Upgrade to 3.3.0_beta02 2022-02-16 13:00:49 +01:00
J-Jamet
bb9dda0cf1 Fix warning 2022-02-16 12:07:48 +01:00
VfBFan
ced6f05e59 Translated using Weblate (German)
Currently translated at 99.4% (589 of 592 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-02-15 22:13:47 +01:00
J-Jamet
cc14b5d4d4 Fix bad folder modification #1239 2022-02-15 11:29:50 +01:00
J-Jamet
2922f7110d Merge branch 'develop' into release/3.3.0 2022-02-14 16:35:08 +01:00
J-Jamet
762a877c5e Fix compilation 2022-02-14 16:34:42 +01:00
J-Jamet
aace7a8260 Change version to 3.3.0_beta01 2022-02-14 16:30:31 +01:00
J-Jamet
ac91abcb45 Fix color in Switch 2022-02-14 16:24:19 +01:00
J-Jamet
5d6ccd84c9 Fix icon selection colors 2022-02-14 16:20:31 +01:00
J-Jamet
bd2f980f8e Add new theme "Reply" and fix colors 2022-02-14 16:00:27 +01:00
J-Jamet
69af330ba1 Fix nav header 2022-02-14 15:24:11 +01:00
J-Jamet
b7bc3bfa8f Fix color flickering 2022-02-14 14:10:31 +01:00
J-Jamet
678663ad66 Add "Simple" theme 2022-02-14 12:51:27 +01:00
Hosted Weblate
ec3aa14112 Merge branch 'origin/develop' into Weblate. 2022-02-14 10:58:41 +01:00
Milo Ivir
3cdd98dc1a Translated using Weblate (Croatian)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-02-14 10:58:41 +01:00
Vitor Henrique
fc3270efd2 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-02-14 10:58:40 +01:00
J-Jamet
0dd871d3b5 Harmonize "cannot" 2022-02-14 10:53:33 +01:00
J-Jamet
41108ff407 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-02-14 10:49:42 +01:00
J-Jamet
99de8cf220 Update CHANGELOG 2022-02-13 17:06:44 +01:00
J-Jamet
a60e887eb3 Fix custom data parcelable #1236 2022-02-13 17:03:36 +01:00
J-Jamet
5133cb5c8f Fix auto type 2022-02-13 15:52:30 +01:00
J-Jamet
1607d84c21 Fix entry properties #1236 2022-02-13 15:47:20 +01:00
J-Jamet
cc0a990af8 Fix TOKEN translation #1232 2022-02-13 15:08:38 +01:00
J-Jamet
fec5bdcfc8 Harmonisation of main credential views 2022-02-13 14:59:39 +01:00
J-Jamet
648514d150 Refactor Password in MainCredential 2022-02-13 14:36:45 +01:00
J-Jamet
37b9745b6b Add lock in drawer menu 2022-02-13 14:21:49 +01:00
J-Jamet
f858b1144c Merge develop and selectable text 2022-02-13 13:49:41 +01:00
J-Jamet
c7cd7b83fa Change navigation view 2022-02-12 19:34:48 +01:00
J-Jamet
3cef086b69 Fix merge and save copy 2022-02-12 19:17:32 +01:00
J-Jamet
ca51f591de Visual point to see if a database is modified 2022-02-12 18:49:38 +01:00
Óscar Fernández Díaz
da63404a84 Translated using Weblate (Spanish)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-02-12 17:56:13 +01:00
J-Jamet
de2160f992 Fix small bugs 2022-02-12 16:01:30 +01:00
J-Jamet
8b7bb36e66 Merge branch 'feature/Merge_from' into develop #1221 #1204 #840 2022-02-12 14:57:44 +01:00
J-Jamet
6ade91dafa Update CHANGELOG 2022-02-12 14:57:29 +01:00
J-Jamet
2ef66f3011 Add data modified after a merge 2022-02-12 14:50:54 +01:00
J-Jamet
5b2fd0bfbb Fix small issues 2022-02-12 14:44:47 +01:00
J-Jamet
ab392e2cf3 Show URI in drawer 2022-02-12 13:53:05 +01:00
J-Jamet
8eb922e93f Fix menu 2022-02-12 13:34:36 +01:00
J-Jamet
20900dce07 Merge branch 'develop' into feature/Merge_from 2022-02-12 13:27:41 +01:00
J-Jamet
c2705ff5d2 Fix small bugs 2022-02-12 13:27:22 +01:00
J-Jamet
8af70fa7b5 Fix merge and save copy in KDB database 2022-02-12 13:20:22 +01:00
J-Jamet
e7eb8099ac Revert code to merge same KDB database 2022-02-12 13:02:34 +01:00
J-Jamet
cedf2eafbb Revert "Remove unused code"
This reverts commit cea7f1c2d1.
2022-02-12 12:57:57 +01:00
J-Jamet
e7553c68a0 Merge attachment from KDB database 2022-02-12 12:57:26 +01:00
J-Jamet
cea7f1c2d1 Remove unused code 2022-02-12 12:40:34 +01:00
J-Jamet
45937f9c9c Do not import meta stream entries 2022-02-12 12:37:49 +01:00
J-Jamet
ee2a1ea924 Add merge for KDB database 2022-02-12 12:33:40 +01:00
J-Jamet
1851c205e9 Merge branch 'develop' into feature/Merge_from 2022-02-12 11:51:16 +01:00
J-Jamet
c4a3947cb3 Fix null pointer with cipher database entity 2022-02-12 11:51:05 +01:00
J-Jamet
d3e76bcf21 Ask for new credential with a merge #1221 2022-02-12 11:42:36 +01:00
J-Jamet
cf4e64d6c5 Merge branch 'develop' into feature/Merge_from 2022-02-12 00:29:19 +01:00
J-Jamet
4cac571f1b Refactoring password view to prepare hardware key #8 2022-02-12 00:24:58 +01:00
J-Jamet
445ed92ff7 Update open database methods 2022-02-11 20:58:23 +01:00
J-Jamet
6686ce15c1 Implementation fo "Merge from" and "Save a copy to" 2022-02-11 19:40:56 +01:00
J-Jamet
59f134e0cd Change icons 2022-02-11 18:33:22 +01:00
J-Jamet
aab3f8c56f Nav header as dedicated view 2022-02-11 15:53:21 +01:00
J-Jamet
17c26e2a96 Add navigation drawer 2022-02-11 15:24:59 +01:00
Ciki Momogi
aec9124ef5 Translated using Weblate (Indonesian)
Currently translated at 90.3% (526 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-02-10 19:54:43 +01:00
random r
2df1e9bc2e Translated using Weblate (Italian)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-02-08 20:12:00 +01:00
J-Jamet
6ceecbfd0f Upgrade libs 2022-02-08 18:33:49 +01:00
J-Jamet
460726cadb Upgrade gradle 2022-02-08 18:14:09 +01:00
J-Jamet
32baa7b9f1 Fix searchable group 2022-02-08 15:45:24 +01:00
J-Jamet
f44e648ccc Fix and update max search 2022-02-08 14:49:25 +01:00
J-Jamet
2ad385acb6 Fix search filters depending on database version 2022-02-08 14:11:24 +01:00
J-Jamet
ebaec2eaf0 Fix visible available features 2022-02-08 13:39:16 +01:00
J-Jamet
dac8c2c15d Fix database v1 available features 2022-02-08 13:25:56 +01:00
J-Jamet
60965491b0 Add background to simple button 2022-02-08 12:50:51 +01:00
SC
19a3faa85a Translated using Weblate (Portuguese)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-02-08 00:15:38 +01:00
SC
3779346eed Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-02-08 00:15:38 +01:00
Stephan Paternotte
185e263ddd Translated using Weblate (Dutch)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-02-08 00:15:38 +01:00
J-Jamet
8c0d984955 Fix expires padding 2022-02-07 20:15:12 +01:00
J-Jamet
8d1012eda0 Upgrade CHANGELOG 2022-02-07 19:37:00 +01:00
J-Jamet
03f147e3d0 Merge branch 'feature/Searchable_Auto_Type' into develop 2022-02-07 19:35:07 +01:00
J-Jamet
13ef5d640c Add searchable group #1006 #905 2022-02-07 19:34:47 +01:00
J-Jamet
2e8eed5afe Visually remove auto type 2022-02-07 17:25:21 +01:00
J-Jamet
54653a5bea Add searchable and Auto-type in Group 2022-02-07 17:02:39 +01:00
Gabriel Cardoso
e29082eba3 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-02-05 18:57:49 +01:00
hokonch
b635e9bb0d Translated using Weblate (Japanese)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2022-02-05 18:57:48 +01:00
J-Jamet
179bfdc3d2 Update CHANGELOG 2022-02-05 16:55:29 +01:00
J-Jamet
631cb104cd Fix styles 2022-02-05 16:48:30 +01:00
J-Jamet
1aeaf6855e Change search filters positions 2022-02-05 15:30:55 +01:00
J-Jamet
6bac1ace30 Fix multiple calls in search view 2022-02-05 15:20:51 +01:00
J-Jamet
488bab7c4d Fix UUID search 2022-02-05 14:43:53 +01:00
J-Jamet
69fbfd7723 Fix tag filter 2022-02-05 14:34:10 +01:00
J-Jamet
7697713c44 Search with regular expression #175 2022-02-05 14:23:30 +01:00
J-Jamet
ee9b072f45 Fix filter selection 2022-02-05 13:38:42 +01:00
J-Jamet
741defd31e Keep search context #1141 2022-02-05 13:33:57 +01:00
J-Jamet
e259b37f74 Add green in divine theme 2022-02-04 22:09:18 +01:00
Jérémy JAMET
9a87de797c Update README 2022-02-04 21:52:29 +01:00
J-Jamet
5d44ba658e Move case sensitive filter 2022-02-03 20:02:19 +01:00
J-Jamet
00518b8231 Default activity animation 2022-02-03 19:58:16 +01:00
J-Jamet
6a3a99d2ac Fix orange color and FAB color 2022-02-03 19:28:16 +01:00
J-Jamet
819434968c Fix and simpler colors for divine theme 2022-02-03 19:12:40 +01:00
J-Jamet
9f55ca2fdb Fix status bar and navigation bar color 2022-02-03 18:25:30 +01:00
J-Jamet
7f69563edb Upgrade CHANGELOG and version to 3.3.0 2022-02-03 17:25:36 +01:00
J-Jamet
b5cf0f987e Merge branch 'feature/Search_Refactoring' into develop 2022-02-03 17:21:43 +01:00
J-Jamet
28ad0b39c3 Remove search view hint 2022-02-03 17:21:25 +01:00
J-Jamet
b4e9040d5c Code encapsulation 2022-02-03 17:17:16 +01:00
J-Jamet
18a6ff0aa5 Fix quick search 2022-02-03 16:06:30 +01:00
J-Jamet
66e8c25265 Show current group title 2022-02-03 15:45:07 +01:00
J-Jamet
aba1f2d35b Fix orientation change 2022-02-03 15:31:05 +01:00
J-Jamet
5f29bcea8f Fix orientation change 2022-02-03 15:12:06 +01:00
J-Jamet
fac6fd7926 Dynamic height of filters 2022-02-03 14:56:05 +01:00
J-Jamet
5f4ab201af Merge branch 'develop' into feature/Search_Refactoring 2022-02-02 20:25:54 +01:00
J-Jamet
9591d36f9d Fix small translation 2022-02-02 20:25:38 +01:00
J-Jamet
a38f34995d Manage search keyboard 2022-02-02 20:25:08 +01:00
J-Jamet
f72564e48d Fix node action 2022-02-02 19:39:50 +01:00
J-Jamet
39ae743c64 Reorder filters 2022-02-02 19:26:58 +01:00
J-Jamet
9cdb355878 Enable filters depending on database 2022-02-02 19:14:23 +01:00
J-Jamet
6bdabbc96b Refactor group elements 2022-02-02 19:02:00 +01:00
solokot
d9e7d5ff6f Translated using Weblate (Russian)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-02-02 18:38:07 +01:00
J-Jamet
9f41da7868 Reorganize code 2022-02-02 18:36:07 +01:00
J-Jamet
d4f7258ed1 Search in current group 2022-02-02 18:32:43 +01:00
J-Jamet
aa34d78052 Fix chip style 2022-02-02 17:30:10 +01:00
J-Jamet
72712e8e0e Merge branch 'develop' into feature/Search_Refactoring 2022-02-02 12:39:59 +01:00
Hosted Weblate
bf25054ef2 Merge branch 'origin/develop' into Weblate. 2022-02-02 11:48:44 +01:00
Stephan Paternotte
32efafb404 Translated using Weblate (Dutch)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-02-02 11:48:44 +01:00
J-Jamet
3748ba1afa Merge tag '3.2.0' into develop
3.2.0
2022-02-02 11:30:55 +01:00
J-Jamet
5baf91dc77 Merge branch 'release/3.2.0' 2022-02-02 11:30:47 +01:00
J-Jamet
a152a48402 Upgrade to 3.2.0 2022-02-01 17:10:04 +01:00
J-Jamet
5fb4c4c20c Fix dialog when no modification performed 2022-02-01 17:06:51 +01:00
J-Jamet
80cf4f05f8 Better unknown KDF exception 2022-02-01 16:03:54 +01:00
J-Jamet
ce8e532f61 Larger view for breadcrumb 2022-02-01 15:50:20 +01:00
Allan Nordhøy
7e04fcbb6c Translated using Weblate (Norwegian Bokmål)
Currently translated at 88.8% (517 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nb_NO/
2022-02-01 05:53:21 +01:00
J-Jamet
71c37d0b8b Fix orientation change 2022-01-31 22:09:12 +01:00
J-Jamet
518375e29a Fix add button listeners 2022-01-31 14:23:46 +01:00
J-Jamet
25c845c1c7 Change max entry search 2022-01-31 14:21:38 +01:00
J-Jamet
6a468b339f Add search filters view 2022-01-31 13:46:17 +01:00
J-Jamet
05a52dd482 Fix search empty string 2022-01-31 11:23:52 +01:00
J-Jamet
5f1413ea1f Fix collapse animation 2022-01-31 00:07:48 +01:00
J-Jamet
84e45482a4 Fix fade animation 2022-01-30 23:45:19 +01:00
J-Jamet
32bfdca562 Advance search expand animation 2022-01-30 23:26:47 +01:00
J-Jamet
547971545e Merge branch 'develop' into feature/Search_Refactoring 2022-01-30 22:33:56 +01:00
J-Jamet
c12b16faf9 Merge branch 'develop' into feature/Search_Refactoring 2022-01-30 22:33:14 +01:00
J-Jamet
858d6c8723 Upgrade to 3.2.0_beta4 2022-01-30 19:44:46 +01:00
J-Jamet
0f021fae9f Fix Kdbx4 tag in Kdbx3 database #1222 2022-01-30 19:34:59 +01:00
J-Jamet
5cb42264c5 First commit for new search 2022-01-30 18:37:06 +01:00
Salih Ail
c17af4098f Translated using Weblate (Arabic)
Currently translated at 75.6% (440 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2022-01-30 15:57:02 +01:00
VfBFan
e6c094b433 Translated using Weblate (German)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-01-30 15:57:02 +01:00
Oğuz Ersen
b15a86618b Translated using Weblate (Turkish)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-01-29 03:55:09 +01:00
Eric
2e66cee551 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-01-29 03:55:09 +01:00
Ihor Hordiichuk
c6e3d0125a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-01-29 03:55:09 +01:00
solokot
f60f7d32dc Translated using Weblate (Russian)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-01-29 03:55:08 +01:00
Matthaiks
dd7175d0c6 Translated using Weblate (Polish)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-01-29 03:55:08 +01:00
J-Jamet
ba0e87f32a Fix warning 2022-01-28 15:56:16 +01:00
J-Jamet
cebba5a09d Upgrade to 3.2.0 beta3 2022-01-28 15:49:59 +01:00
J-Jamet
7b0c31c641 Fix search #1219 2022-01-28 15:49:00 +01:00
Kunzisoft
487be74e83 Translated using Weblate (English)
Currently translated at 99.8% (581 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/en/
2022-01-28 15:46:34 +01:00
J-Jamet
3c7c88e0f5 Hot fix for search #1219 2022-01-28 12:01:32 +01:00
J-Jamet
e876e89b41 Upgrade version code 2022-01-28 10:09:45 +01:00
J-Jamet
065fd9632c Update string 2022-01-27 18:56:13 +01:00
J-Jamet
f7d8641e31 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-01-27 18:50:34 +01:00
J-Jamet
ed6456599b Update string 2022-01-27 18:47:48 +01:00
Hosted Weblate
649538846a Merge branch 'origin/develop' into Weblate. 2022-01-27 18:44:48 +01:00
Kunzisoft
7468db5269 Translated using Weblate (French)
Currently translated at 99.6% (580 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-01-27 18:44:47 +01:00
Retrial
8291e94de4 Translated using Weblate (Greek)
Currently translated at 100.0% (582 of 582 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-01-27 18:44:47 +01:00
J-Jamet
94d30fc7ec Change string 2022-01-27 18:44:06 +01:00
Hosted Weblate
36c6f371c5 Merge branch 'origin/develop' into Weblate. 2022-01-27 18:32:27 +01:00
Balázs Meskó
94b3f66e14 Translated using Weblate (Hungarian)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2022-01-27 18:32:27 +01:00
J-Jamet
c9527ddacd Update CHANGELOG 2022-01-27 18:31:20 +01:00
J-Jamet
805c728e92 Change "show" strings by "displays" 2022-01-27 18:29:00 +01:00
J-Jamet
7812a86adb Add entry colors setting 2022-01-27 18:26:01 +01:00
J-Jamet
d22defcd83 Move settings position 2022-01-27 18:06:38 +01:00
J-Jamet
d06829ff7b Fix empty tag 2022-01-27 17:33:05 +01:00
J-Jamet
9110a1aca6 Fix checkboxes position with an error 2022-01-27 16:51:19 +01:00
J-Jamet
d7c90601d0 Add warning integrity message when keyfile is an image #1188 2022-01-27 16:47:47 +01:00
J-Jamet
7b5fc600f5 Merge branch 'feature/Tags' into develop 2022-01-27 16:12:01 +01:00
J-Jamet
0e699a1918 Add Tokenautocomplete from sources until https://github.com/splitwise/TokenAutoComplete/pull/422 fixed 2022-01-27 16:08:34 +01:00
J-Jamet
49f9964bc7 Add pool of tags 2022-01-27 15:37:37 +01:00
J-Jamet
ee3ec4b14d Add tags to group 2022-01-26 19:40:28 +01:00
J-Jamet
cdcc9f0aff Change tags views 2022-01-26 19:02:54 +01:00
J-Jamet
d56a01998f Merge branch 'develop' into feature/Tags 2022-01-26 18:43:21 +01:00
J-Jamet
4e7f7f7fa0 Fix lock in settings 2022-01-26 18:16:33 +01:00
J-Jamet
201d8f8aee Fix merge menu 2022-01-26 17:47:40 +01:00
J-Jamet
3847cb4d2d Merge branch 'feature/Keyboard_Refactoring' into develop 2022-01-26 15:12:01 +01:00
J-Jamet
89a338ac33 Suppress deprecation 2022-01-26 15:11:11 +01:00
J-Jamet
0084d113d3 Remove unused deprecated attribute 2022-01-26 15:10:21 +01:00
J-Jamet
6d49cc3577 Remove unused deprecated attribute 2022-01-26 15:10:06 +01:00
J-Jamet
910c45a6be Fix key press 2022-01-26 14:23:45 +01:00
J-Jamet
1d16ad764f First KeyboardView implementation 2022-01-26 14:01:08 +01:00
J-Jamet
142021c849 Update CHANGELOG 2022-01-25 18:18:40 +01:00
J-Jamet
c87b9768b1 small changelog change 2022-01-25 18:11:05 +01:00
J-Jamet
fbc3c1a9a4 Merge branch 'feature/Keep_Screen_On' of git://github.com/SUPERYAO541/KeePassDX into SUPERYAO541-feature/Keep_Screen_On 2022-01-25 18:04:49 +01:00
J-Jamet
05d1656a9e Inherit colors and icon from template #1213 #1130 2022-01-25 17:59:06 +01:00
J-Jamet
98804db478 Better kdf engine implementation 2022-01-25 16:37:18 +01:00
J-Jamet
c90f18c45a Better cipher engine implementation 2022-01-25 16:11:40 +01:00
J-Jamet
553783bfce Revert encryption commit 3426b3cdeb to prevent crash 2022-01-25 14:51:27 +01:00
J-Jamet
fbf67f28f5 Upgrade database version after a modification 2022-01-25 14:22:26 +01:00
J-Jamet
b8005466cd Inherit color from template #1213 2022-01-25 12:41:44 +01:00
J-Jamet
82177a386e Add copyright 2022-01-25 11:25:38 +01:00
J-Jamet
176b276835 Upgrade CHANGELOG 2022-01-25 11:04:18 +01:00
J-Jamet
a4732194ef Better quick search implementation and add path 2022-01-25 10:59:39 +01:00
I. Musthafa
4a815daf4d Translated using Weblate (Indonesian)
Currently translated at 89.9% (518 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-01-25 06:53:13 +01:00
Victor Mihalache
8aa7804e8d Translated using Weblate (Romanian)
Currently translated at 69.6% (401 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2022-01-25 06:53:13 +01:00
Oğuz Ersen
3b7086627d Translated using Weblate (Turkish)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-01-25 06:53:12 +01:00
Eric
20fb4036d1 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-01-25 06:53:11 +01:00
Ihor Hordiichuk
3679ad3d70 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-01-25 06:53:11 +01:00
solokot
63f23c571f Translated using Weblate (Russian)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-01-25 06:53:11 +01:00
André Marcelo Alvarenga
7e96303c7d Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-01-25 06:53:11 +01:00
Matthaiks
4f5879179e Translated using Weblate (Polish)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-01-25 06:53:10 +01:00
Stephan Paternotte
5a81f54a1b Translated using Weblate (Dutch)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-01-25 06:53:10 +01:00
Retrial
d8ccaf3578 Translated using Weblate (Greek)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-01-25 06:53:09 +01:00
C. Rüdinger
7d0848f22b Translated using Weblate (German)
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-01-25 06:53:09 +01:00
André Marcelo Alvarenga
b02cffab56 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (576 of 576 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-01-23 23:49:47 +01:00
J-Jamet
59b6deb7be Fix color during selection 2022-01-23 12:38:35 +01:00
J-Jamet
1b734051d5 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-01-23 11:30:37 +01:00
J-Jamet
037fe41961 Merge branch 'Nickoriginal-patch-1' into develop 2022-01-23 11:23:56 +01:00
Nickoriginal
7bf1263c04 Update strings.xml
Fix mistyping
2022-01-22 16:01:13 +02:00
random r
0e4afd4681 Translated using Weblate (Italian)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-01-22 14:52:47 +01:00
Balázs Meskó
21930021ed Translated using Weblate (Hungarian)
Currently translated at 88.3% (507 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2022-01-22 14:52:46 +01:00
Oğuz Ersen
748b5c54c9 Translated using Weblate (Turkish)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-01-20 00:01:00 +01:00
Eric
82d305008b Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-01-20 00:01:00 +01:00
Ihor Hordiichuk
1f24955533 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-01-20 00:00:59 +01:00
solokot
ccfa28b895 Translated using Weblate (Russian)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-01-20 00:00:59 +01:00
Matthaiks
2e3562d87e Translated using Weblate (Polish)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-01-20 00:00:59 +01:00
Oliver Cervera
f1be109c15 Translated using Weblate (Italian)
Currently translated at 99.6% (572 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2022-01-20 00:00:59 +01:00
Balázs Meskó
b09bd39ad4 Translated using Weblate (Hungarian)
Currently translated at 83.2% (478 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2022-01-20 00:00:58 +01:00
Kunzisoft
d812c3d61b Translated using Weblate (French)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2022-01-20 00:00:58 +01:00
Óscar Fernández Díaz
0d7772a4c6 Translated using Weblate (Spanish)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-01-20 00:00:58 +01:00
Retrial
a5abf4d186 Translated using Weblate (Greek)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-01-20 00:00:57 +01:00
VfBFan
c938a13482 Translated using Weblate (German)
Currently translated at 100.0% (574 of 574 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-01-20 00:00:57 +01:00
J-Jamet
0bfc395986 Merge branch 'feature/Merge_Data' into develop #840 2022-01-19 20:40:47 +01:00
J-Jamet
60c536f444 Fix save database info 2022-01-19 20:33:54 +01:00
J-Jamet
8129e6e0c1 First code to merge KDB and add doc 2022-01-19 20:10:50 +01:00
J-Jamet
223a8e9a5e Fix concurrent modification exception 2022-01-19 19:12:44 +01:00
J-Jamet
0e21c75007 replace updateGroup by addGroupIndex 2022-01-19 18:28:21 +01:00
J-Jamet
6ca031e8fd Merge custom data 2022-01-19 16:33:15 +01:00
J-Jamet
f02e86fb50 Confirm reload dialog if local modification #1196 2022-01-19 15:11:17 +01:00
J-Jamet
b17f8244da Remove merge menu in read only mode 2022-01-18 14:41:12 +01:00
J-Jamet
4c02ce138b Remove merge with kdb database 2022-01-18 14:37:46 +01:00
J-Jamet
5eba208b00 Upgrade to 3.2.0 and update CHANGELOG 2022-01-18 13:09:28 +01:00
J-Jamet
2a4fbbfb35 Merge branch 'develop' into feature/Merge_Data 2022-01-18 13:05:07 +01:00
Hosted Weblate
5dd8bdcae6 Merge branch 'origin/develop' into Weblate. 2022-01-18 13:04:51 +01:00
I. Musthafa
c3e82eea5d Translated using Weblate (Indonesian)
Currently translated at 90.8% (519 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2022-01-18 13:04:50 +01:00
Milo Ivir
2cfb96be33 Translated using Weblate (Croatian)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2022-01-18 13:04:49 +01:00
Stephan Paternotte
715eedfab1 Translated using Weblate (Dutch)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2022-01-18 13:04:49 +01:00
J-Jamet
7f3a1c9a7d Merge tag '3.1' into develop
3.1
2022-01-18 12:44:57 +01:00
J-Jamet
8413d2b31a Merge branch 'release/3.1' 2022-01-18 12:44:44 +01:00
J-Jamet
04a03da382 Merge branch 'master' into release/3.1 2022-01-18 12:44:30 +01:00
J-Jamet
e3274657ea /bin/bash: q: command not found 2022-01-18 12:13:03 +01:00
J-Jamet
f3b25cb792 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2022-01-18 12:08:48 +01:00
J-Jamet
d181f886fe Update CHANGELOG 2022-01-18 12:02:33 +01:00
J-Jamet
616d073395 Capture duplicate error exception 2022-01-18 11:44:45 +01:00
J-Jamet
d36fc19585 Add try catch exception when populate view 2022-01-18 11:32:11 +01:00
J-Jamet
95d9e07e2f TODO fix meta stream 2022-01-17 23:51:37 +01:00
J-Jamet
25077a7b9a Fix history merge 2022-01-17 23:33:20 +01:00
J-Jamet
6971cd1a6b Start merge database v1 2022-01-17 22:35:27 +01:00
J-Jamet
1e43a65743 Do not close the database when a merge failed 2022-01-17 22:18:46 +01:00
J-Jamet
2f2cbf343e Fix object deletion 2022-01-17 22:07:32 +01:00
J-Jamet
3426b3cdeb Better algorithm implementation 2022-01-17 21:31:05 +01:00
J-Jamet
e1d4c172f4 Merge settings 2022-01-17 20:29:10 +01:00
J-Jamet
4c4a67afaf Merge icons 2022-01-17 17:23:33 +01:00
J-Jamet
d33f210940 Add TODO and copyright 2022-01-15 22:31:28 +01:00
J-Jamet
ead59bd410 Merge entry history 2022-01-15 21:37:24 +01:00
J-Jamet
f9445de71f Merge database metadata 2022-01-15 21:03:40 +01:00
J-Jamet
c26995779a Change strings 2022-01-15 20:31:41 +01:00
J-Jamet
c6277453a3 Better binary management 2022-01-15 20:31:31 +01:00
solokot
91ebf2ba6f Translated using Weblate (Russian)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-01-15 11:13:08 +01:00
J-Jamet
0f87bdd5a3 Merge branch 'develop' into feature/Merge_Data 2022-01-14 18:52:55 +01:00
J-Jamet
9e97042dd1 Larger database color view 2022-01-14 18:42:32 +01:00
J-Jamet
b7c4a99e71 Upgrade README Year 2022-01-14 18:37:29 +01:00
J-Jamet
48e315453e Smooth counter 2022-01-14 18:11:36 +01:00
J-Jamet
a8a6d14ca3 Merge branch 'feature/Entry_Color' into develop 2022-01-14 18:05:21 +01:00
J-Jamet
e895dd3430 Upgrade CHANGELOG 2022-01-14 18:05:03 +01:00
J-Jamet
f59859137a Upgrade libs 2022-01-14 18:03:00 +01:00
J-Jamet
dee92e9e40 Upgrade libs 2022-01-14 18:01:35 +01:00
J-Jamet
6701f4f95e Fix color in KitKat 2022-01-14 17:55:54 +01:00
J-Jamet
e20f769854 Fix theme refresh 2022-01-14 16:00:36 +01:00
J-Jamet
4f762a9432 Change background color icon 2022-01-14 15:54:41 +01:00
J-Jamet
3c49eb1635 Fix color picker 2022-01-14 15:45:54 +01:00
J-Jamet
bdc6a282e2 Colorize entry view 2022-01-14 14:25:06 +01:00
J-Jamet
8392ab2cc4 Fix icon color 2022-01-14 01:13:37 +01:00
Allan Nordhøy
93c7c09f8c Translated using Weblate (Norwegian Bokmål)
Currently translated at 90.0% (514 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nb_NO/
2022-01-14 00:53:27 +01:00
Allan Nordhøy
120116414f Translated using Weblate (Danish)
Currently translated at 91.5% (523 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/da/
2022-01-14 00:53:24 +01:00
J-Jamet
11794e5819 Add color change listener 2022-01-14 00:39:20 +01:00
J-Jamet
edce3d7bec Add color in entry 2022-01-13 20:22:10 +01:00
J-Jamet
e133e32e7c Add color in app bar 2022-01-13 19:15:18 +01:00
J-Jamet
471859e448 Add color in entry edit 2022-01-13 18:08:20 +01:00
Óscar Fernández Díaz
d8de66eb14 Translated using Weblate (Spanish)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2022-01-12 22:22:29 +01:00
J-Jamet
cfdc0237d7 Add foreground and background colors in list 2022-01-12 19:50:38 +01:00
J-Jamet
05fad24eda Fix color picker fragment 2022-01-12 17:01:35 +01:00
J-Jamet
d4818c5567 Select entry colors 2022-01-12 14:19:04 +01:00
J-Jamet
8e8e6a7b93 Invert info container visibility 2022-01-11 18:02:43 +01:00
J-Jamet
6547f0ffad First entry color test 2022-01-11 17:46:50 +01:00
Ngô Ngọc Đức Huy
6f172fffa8 Translated using Weblate (Vietnamese)
Currently translated at 29.5% (169 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2022-01-11 13:49:38 +01:00
Matthaiks
ed16e06676 Translated using Weblate (Polish)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-01-11 13:49:38 +01:00
Ngô Ngọc Đức Huy
1874f06f42 Translated using Weblate (Vietnamese)
Currently translated at 29.4% (168 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2022-01-09 01:54:52 +01:00
zeritti
e9db24429a Translated using Weblate (Czech)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2022-01-09 01:54:51 +01:00
J-Jamet
a59f4d45ca Better color implementation 2022-01-08 22:29:43 +01:00
J-Jamet
c7b3e0926c Fix save database color 2022-01-08 21:45:11 +01:00
J-Jamet
f0f5258bc9 Fix refresh UI 2022-01-08 20:36:59 +01:00
J-Jamet
12c07cf793 Fix refresh database metadata 2022-01-08 20:22:39 +01:00
J-Jamet
d2b8c85015 Add database color #913 2022-01-08 20:03:56 +01:00
J-Jamet
b9652291bd Manage default user name and color in KDB 2022-01-08 19:35:42 +01:00
J-Jamet
b0d1f93bfc Change header sig 2022-01-08 16:06:10 +01:00
J-Jamet
a6d6c247a8 Merge branch 'develop' into feature/Merge_Data 2022-01-07 19:02:22 +01:00
J-Jamet
553416c927 Fix number of entries and refactor GroupFragment 2022-01-07 18:59:23 +01:00
J-Jamet
b83696bc60 Fix create entry in the right group 2022-01-07 18:28:44 +01:00
J-Jamet
23ce320d75 Fix output KDB and private indexes 2022-01-07 18:12:45 +01:00
J-Jamet
dd170aafee Merge branch 'develop' into feature/Merge_Data 2022-01-07 14:39:17 +01:00
J-Jamet
27d5733dbc Strike out expires group 2022-01-07 14:38:18 +01:00
J-Jamet
9ba769c53e Fix merge and clear 2022-01-04 21:50:35 +01:00
J-Jamet
8ff57e3004 Better database loader implementation 2022-01-04 21:00:23 +01:00
J-Jamet
5c75c6c7d3 First pass to manage deleted objects 2022-01-04 16:06:39 +01:00
J-Jamet
56efb20ffa Fix delete methods 2022-01-04 15:12:58 +01:00
J-Jamet
699578bb59 Better recycle bin implementation 2022-01-04 13:31:18 +01:00
ssantos
8d7d01bf88 Translated using Weblate (Portuguese)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2022-01-03 21:55:51 +01:00
solokot
0bc37d2fc2 Translated using Weblate (Russian)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2022-01-03 21:55:50 +01:00
André Marcelo Alvarenga
aaa1655af1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-01-03 21:55:50 +01:00
Mr-Update
f1bd4e1bba Translated using Weblate (German)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2022-01-03 21:55:50 +01:00
J-Jamet
f74147070a Add TODO for merge code 2022-01-03 19:53:19 +01:00
J-Jamet
20f4ea93e4 Merge branch 'develop' into feature/Merge_Data 2022-01-03 19:52:23 +01:00
J-Jamet
15a28e7c83 Fix action in breadcrumb 2022-01-03 19:51:59 +01:00
J-Jamet
c550e1de54 First merge implementation 2022-01-03 19:25:48 +01:00
Serdar Sağlam
ab26e561fd Translated using Weblate (Turkish)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2022-01-01 13:56:33 +01:00
Eric
66968a28a3 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2022-01-01 13:56:32 +01:00
Ihor Hordiichuk
37d1f91224 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2022-01-01 13:56:32 +01:00
Gabriel Cardoso
9e69068d42 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2022-01-01 13:56:32 +01:00
Matthaiks
8e2a9fcd01 Translated using Weblate (Polish)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2022-01-01 13:56:31 +01:00
Retrial
1753887916 Translated using Weblate (Greek)
Currently translated at 100.0% (571 of 571 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2022-01-01 13:56:31 +01:00
Hosted Weblate
21bcffcc87 Merge branch 'origin/develop' into Weblate. 2021-12-31 17:27:28 +01:00
I. Musthafa
1caed49c75 Translated using Weblate (Indonesian)
Currently translated at 84.7% (482 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2021-12-31 09:20:33 +01:00
Vitor Henrique
619ea35168 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-12-31 09:20:32 +01:00
Giai Ngo
877f913e8f Translated using Weblate (Vietnamese)
Currently translated at 25.8% (147 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2021-12-23 03:50:28 +01:00
I. Musthafa
25c47390c0 Translated using Weblate (Indonesian)
Currently translated at 81.1% (462 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2021-12-23 03:50:26 +01:00
J-Jamet
b3c46348a1 Allow to change root group 2021-12-22 19:01:51 +01:00
J-Jamet
6f154194f1 Upgrade bouncy castle #833 2021-12-22 17:40:18 +01:00
J-Jamet
c3ab08ce17 Upgrade to SDK 31 2021-12-22 17:28:29 +01:00
J-Jamet
004fffa992 Add exact alarm message 2021-12-22 17:23:57 +01:00
J-Jamet
d6bd80c9c0 Fix UI in Android 8 #509 2021-12-22 14:12:30 +01:00
J-Jamet
318bcdd011 Remove WRITE_EXTERNAL_STORAGE permission 2021-12-22 13:57:05 +01:00
J-Jamet
3076f2af68 Add backup rules 2021-12-21 17:14:30 +01:00
Jérémy JAMET
3dd9ef5564 Update bug_report.md 2021-12-21 10:01:34 +01:00
I. Musthafa
367e5fa84e Translated using Weblate (Indonesian)
Currently translated at 81.0% (461 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2021-12-20 15:50:26 +01:00
J-Jamet
97cd61fd13 First pass to update API 31 2021-12-17 17:57:09 +01:00
Y. Sakamoto
869bf7a345 Translated using Weblate (Japanese)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2021-12-17 12:53:25 +01:00
J-Jamet
9e15ac242d Fix small element 2021-12-16 21:36:55 +01:00
J-Jamet
84943e58f1 Fix small elements 2021-12-16 21:30:40 +01:00
J-Jamet
2289bf0a27 Fix show UUID in V1 format 2021-12-16 21:15:23 +01:00
J-Jamet
7fda40c983 Show UUID in group 2021-12-16 20:52:49 +01:00
J-Jamet
7eeed8f670 Edit group on long click 2021-12-16 20:20:46 +01:00
J-Jamet
4d3f4ed5c2 Add group info dialog #1177 2021-12-16 19:12:31 +01:00
J-Jamet
145a4f5c20 Merge branch 'feature/Breadcrumb' into develop 2021-12-16 17:44:20 +01:00
J-Jamet
9afe3d26e9 Arrow as breadcrumb delimiter 2021-12-16 17:37:17 +01:00
J-Jamet
b73a7f1ed8 Upgrade version to 3.1.0 and changelog 2021-12-16 17:29:17 +01:00
J-Jamet
91a2bc3862 Fix virtual content 2021-12-16 17:25:41 +01:00
J-Jamet
78a8a840b0 Add path in search result 2021-12-16 17:20:33 +01:00
J-Jamet
f4d54b6ca3 Fix margin 2021-12-16 16:54:53 +01:00
J-Jamet
bc7a1c332c Breadcrunb toolbar animation and remove back button 2021-12-16 16:49:56 +01:00
J-Jamet
0e75cb9095 Change parallax 2021-12-16 16:23:09 +01:00
J-Jamet
41b6fb6dcd Add selectable background 2021-12-16 13:23:18 +01:00
J-Jamet
2ca3cbc88f Fix database title 2021-12-16 13:12:08 +01:00
J-Jamet
d05641a3d6 Change toolbar parallax 2021-12-16 13:02:04 +01:00
J-Jamet
28bf84e05c Fix search 2021-12-16 12:56:14 +01:00
J-Jamet
ff51b53660 Back group in breadcrumb 2021-12-16 12:25:25 +01:00
J-Jamet
8b8e034b18 Refresh breadcrumb 2021-12-16 12:06:42 +01:00
J-Jamet
39927b06e3 Change breadcrumb UI 2021-12-16 12:01:26 +01:00
J-Jamet
66db2e7d16 Better breadcrumb implementation 2021-12-16 11:26:17 +01:00
Kunzisoft
a927c33ef1 Translated using Weblate (French)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2021-12-15 12:50:48 +01:00
J-Jamet
17bc18b881 Add breadcrumb for group 2021-12-13 14:24:12 +01:00
Oymate
aa643c4a82 Translated using Weblate (Bengali (Bangladesh))
Currently translated at 7.7% (44 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/bn_BD/
2021-12-12 07:52:01 +01:00
J-Jamet
836fbea676 Merge tag '3.0.4' into develop
3.0.4
2021-12-09 20:11:08 +01:00
J-Jamet
045049243c Merge branch 'release/3.0.4' 2021-12-09 20:10:57 +01:00
J-Jamet
b9813a3494 Upgrade version code 2021-12-09 19:54:12 +01:00
J-Jamet
9b42a93ce1 Change lock button 2021-12-09 19:49:38 +01:00
J-Jamet
8502bceef1 Fix search 2021-12-09 18:38:38 +01:00
J-Jamet
663387476f Change select entry min height 2021-12-09 14:33:07 +01:00
J-Jamet
daafd83df9 Better extra key implementation 2021-12-09 14:29:41 +01:00
J-Jamet
f780f2725b Fix compat inline suggestions request 2021-12-09 14:15:40 +01:00
J-Jamet
483aca871a Upgrade to version 3.0.4 and fix inline autofill suggestion #1165 2021-12-09 13:38:42 +01:00
J-Jamet
352e709c3b Merge branch 'master' into develop 2021-12-09 11:53:40 +01:00
J-Jamet
629057b2c1 Fix autofill exception #1173 2021-12-09 11:46:39 +01:00
J-Jamet
0e5f53596d Merge tag '3.0.3' into develop
3.0.3
2021-12-08 17:58:49 +01:00
J-Jamet
0d91f07646 Merge branch 'release/3.0.3' 2021-12-08 17:58:37 +01:00
J-Jamet
db882a26ab Upgrade constraint layout lib 2021-12-08 11:37:02 +01:00
Ihor Hordiichuk
35c8ea22b1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2021-12-08 03:51:55 +01:00
J-Jamet
7f01619358 Fix notification in older android versions 2021-12-07 18:14:36 +01:00
J-Jamet
ee109b4ceb Merge branch 'feature/StartActivityResult' into develop 2021-12-07 16:36:52 +01:00
J-Jamet
7a398e5453 Fix activity result for advanced unlocking 2021-12-07 16:20:57 +01:00
Óscar Fernández Díaz
23a548f9b4 Translated using Weblate (Spanish)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2021-12-02 19:54:32 +01:00
J-Jamet
d4655d7034 Fix search in activity 2021-12-02 13:31:41 +01:00
J-Jamet
9feb96b541 Fix start autofill service 2021-12-02 13:30:02 +01:00
J-Jamet
e939278193 Suppress deprecation with setTargetFragment 2021-12-02 13:21:25 +01:00
J-Jamet
d4ef1a2617 Fix small warnings 2021-12-02 11:39:42 +01:00
J-Jamet
5f8746ced3 Fix result with entry edit 2021-12-01 17:16:19 +01:00
J-Jamet
40a063e94f Fix result exit lock 2021-11-30 11:50:07 +01:00
J-Jamet
8f5439b958 Icon selection with activity result launcher 2021-11-30 11:20:09 +01:00
J-Jamet
e347f57d8b Refactor FileHelper and fix key file selection 2021-11-30 10:47:31 +01:00
Milo Ivir
7169b15fd8 Translated using Weblate (Croatian)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2021-11-29 16:54:00 +01:00
abidin toumi
f9def8c96f Translated using Weblate (Arabic)
Currently translated at 78.7% (448 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2021-11-29 16:53:59 +01:00
Mr-Update
ef43837af1 Translated using Weblate (German)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2021-11-25 10:50:58 +01:00
J-Jamet
2efb8e8b8c Merge branch 'develop' into feature/StartActivityResult 2021-11-23 18:28:08 +01:00
J-Jamet
e5bb69ea5f Fix startActivityResult for Autofill 2021-11-23 18:28:01 +01:00
random r
0979ca607d Translated using Weblate (Italian)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2021-11-23 15:40:37 +01:00
J-Jamet
6ae186b2af Fix exported and pending intent 2021-11-23 12:10:57 +01:00
Beytullah AKYÜZ
98fb27f77d Translated using Weblate (Turkish)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2021-11-22 14:52:03 +01:00
JY3
d68510bbaa Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2021-11-22 14:52:03 +01:00
J-Jamet
71fdd2d92d Fix lowercase and uppercase 2021-11-22 13:22:18 +01:00
J-Jamet
3656689ff3 Fix kotlin code warning 2021-11-22 13:10:42 +01:00
J-Jamet
7d78406db6 Fix pending intent 2021-11-22 12:24:22 +01:00
J-Jamet
ac47748e41 Fix pending intent 2021-11-22 11:51:30 +01:00
J-Jamet
80f9b46479 New lock icon in notification 2021-11-20 13:30:26 +01:00
J-Jamet
999f1bf47a New lock icon in notification 2021-11-20 13:10:23 +01:00
J-Jamet
9e114eb2b8 Add lock button in database notification 2021-11-20 12:30:58 +01:00
SC
4177d34b00 Translated using Weblate (Portuguese)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2021-11-19 19:52:59 +01:00
Serdar Sağlam
3ec5c04bf6 Translated using Weblate (Turkish)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2021-11-19 19:52:59 +01:00
Eric
a877c068b6 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2021-11-19 19:52:58 +01:00
Ihor Hordiichuk
6a3db90c1e Translated using Weblate (Ukrainian)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2021-11-19 19:52:58 +01:00
solokot
a079e0d864 Translated using Weblate (Russian)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2021-11-19 19:52:58 +01:00
Matthaiks
719776d66e Translated using Weblate (Polish)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2021-11-19 19:52:58 +01:00
Stephan Paternotte
c5af1241e9 Translated using Weblate (Dutch)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2021-11-19 19:52:57 +01:00
Retrial
27e4d7b563 Translated using Weblate (Greek)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2021-11-19 19:52:57 +01:00
VfBFan
450ab34721 Translated using Weblate (German)
Currently translated at 100.0% (569 of 569 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2021-11-19 19:52:57 +01:00
Hosted Weblate
3e2d4eae2c Merge branch 'origin/develop' into Weblate. 2021-11-17 20:33:06 +01:00
J-Jamet
d89b6529ef Upgrade kotlin and fragment versions 2021-11-16 16:51:06 +01:00
J-Jamet
5caf11556a Remove unused translation 2021-11-16 16:15:08 +01:00
J-Jamet
78cc6f0f40 Merge branch 'translations' into develop 2021-11-16 16:10:58 +01:00
J-Jamet
0007cd4668 Merge branch 'develop' of https://hosted.weblate.org/git/keepass-dx/strings into translations 2021-11-16 16:09:26 +01:00
J-Jamet
05195e41de Upgrade appcompat and material libs 2021-11-16 14:53:54 +01:00
J-Jamet
66f44ef87d Encapsulate lib version through modules 2021-11-16 12:48:38 +01:00
J-Jamet
a0585d9b11 Upgrade repo and libs 2021-11-16 12:07:48 +01:00
J-Jamet
5067946b13 Change backup configuration #1144 2021-11-16 11:12:07 +01:00
J-Jamet
f52241d5a8 Change backup configuration #1144 2021-11-16 11:09:14 +01:00
J-Jamet
04ccb25fa3 Catch key file out of memory exception 2021-11-15 12:25:27 +01:00
J-Jamet
5a3f4b60b8 Catch style exception 2021-11-15 12:19:36 +01:00
J-Jamet
4408b2e488 Catch exception in run action 2021-11-15 12:04:46 +01:00
J-Jamet
9a26acee35 Change version to 3.0.3 and add issue tag 2021-11-15 11:35:08 +01:00
Rsec
6ac377348b Translated using Weblate (Romanian)
Currently translated at 63.2% (359 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ro/
2021-11-10 18:49:56 +01:00
I. Musthafa
daeb88d4f4 Translated using Weblate (Indonesian)
Currently translated at 79.0% (449 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2021-11-08 07:50:09 +01:00
J-Jamet
47bf199f52 Merge branch 'feature/Biometric_Refactor' into develop 2021-11-03 14:46:55 +01:00
J-Jamet
91540b022d Use strong box to store in security chip #1145 2021-11-02 17:55:30 +01:00
J-Jamet
505a51b6b5 Update CHANGELOG 2021-11-02 17:31:09 +01:00
J-Jamet
28400488aa Fix advanced unlock menu button 2021-11-02 17:22:23 +01:00
J-Jamet
45ae600289 Change biometric views 2021-11-02 17:10:06 +01:00
J-Jamet
8be6874651 Auto remove all biometric keys when invalidated 2021-11-02 16:27:29 +01:00
Milo Ivir
f694a500e0 Translated using Weblate (Croatian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2021-10-30 00:37:53 +02:00
J-Jamet
c415fa01fc Update Autofill compatibility list #725 2021-10-29 17:40:16 +02:00
J-Jamet
5225a9459c Fix template chars limit 2021-10-27 20:01:47 +02:00
J-Jamet
2974b150af Fix template spinner 2021-10-27 19:55:14 +02:00
J-Jamet
cf353c8067 Fix template icons 2021-10-27 19:27:21 +02:00
Serdar Sağlam
3aacb5d8b3 Translated using Weblate (Turkish)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2021-10-27 01:38:42 +02:00
abidin toumi
114fbdbe01 Translated using Weblate (Arabic)
Currently translated at 77.4% (440 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2021-10-27 01:38:42 +02:00
abidin toumi
f1f83cbec4 Translated using Weblate (Arabic)
Currently translated at 76.5% (435 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2021-10-25 20:38:00 +02:00
J-Jamet
335c28c2c9 Fix save default username 2021-10-25 15:57:01 +02:00
J-Jamet
daf12cbcce Change Wifi to Wi-Fi 2021-10-25 15:44:18 +02:00
J-Jamet
bf56eca003 Fix templates #1128 2021-10-25 15:41:20 +02:00
SUPERYAO
c3542224ae Merge branch 'develop' into feature/Keep_Screen_On 2021-10-25 18:03:04 +08:00
J-Jamet
a12b7fd58a Merge branch 'SUPERYAO541-feature/Complete_zh-rTW' into develop 2021-10-25 11:30:33 +02:00
J-Jamet
98d004edbf Merge branch 'feature/Complete_zh-rTW' of git://github.com/SUPERYAO541/KeePassDX into SUPERYAO541-feature/Complete_zh-rTW 2021-10-25 11:30:18 +02:00
random r
67586a98b3 Translated using Weblate (Italian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2021-10-23 11:41:24 +02:00
J-Jamet
429faf44db Allow to delete tags 2021-10-22 15:23:44 +02:00
Milo Ivir
c6d8911883 Translated using Weblate (Croatian)
Currently translated at 99.8% (567 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2021-10-21 21:36:24 +02:00
J-Jamet
69ad7979ae Manually add token tags 2021-10-17 13:40:49 +02:00
Neko Nekowazarashi
12e398ce9b Translated using Weblate (Indonesian)
Currently translated at 78.1% (444 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2021-10-16 13:40:45 +02:00
abidin toumi
5c4a202616 Translated using Weblate (Arabic)
Currently translated at 76.4% (434 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2021-10-14 23:34:38 +02:00
solokot
adc1ec8444 Translated using Weblate (Russian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2021-10-14 23:34:36 +02:00
Darin Avdeyeva
0227d2fcb4 Translated using Weblate (Russian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2021-10-13 19:02:33 +02:00
J-Jamet
e87caac723 Put tag if not empty 2021-10-13 16:45:41 +02:00
abidin toumi
95abe3b5ac Translated using Weblate (Arabic)
Currently translated at 67.6% (384 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2021-10-10 18:02:20 +02:00
abidin toumi
133a902c54 Translated using Weblate (Arabic)
Currently translated at 61.4% (349 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2021-10-09 17:05:15 +02:00
J-Jamet
494544a4c2 Fix tags view position 2021-10-08 17:44:47 +02:00
Stephan Paternotte
aacb03d9ef Translated using Weblate (Dutch)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2021-10-07 20:03:28 +02:00
J-Jamet
fbeaa1781f Add no internet connection required in description 2021-10-06 18:45:14 +02:00
J-Jamet
ca73aad538 Add dynamic templates in description 2021-10-06 18:09:54 +02:00
J-Jamet
94b6118bf7 Fix theme and add autocomplete view 2021-10-05 14:30:49 +02:00
André Marcelo Alvarenga
4a4bfefd17 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-10-05 10:08:58 +02:00
J-Jamet
7d6d86c6ff Merge branch 'develop' into feature/Tags 2021-10-04 16:49:38 +02:00
J-Jamet
6796b0cd2a Upgrade gradle 2021-10-04 16:49:15 +02:00
abidin toumi
29e1f824b0 Translated using Weblate (Arabic)
Currently translated at 61.2% (348 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ar/
2021-10-03 17:19:42 +02:00
hokonch
51263a2911 Translated using Weblate (Japanese)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2021-09-30 06:36:59 +02:00
Kunzisoft
dd7f857475 Translated using Weblate (French)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2021-09-30 06:36:59 +02:00
J-Jamet
bedc327e65 Manage Tags #633 2021-09-28 19:12:34 +02:00
J-Jamet
f0fdd4a537 Add & edit custom icon name #976 2021-09-28 18:12:49 +02:00
J-Jamet
9b847a0561 Change default Argon2 parameters #1098
and upgrade to 3.1.0
2021-09-28 12:57:14 +02:00
Hosted Weblate
469e76b80a Merge branch 'origin/develop' into Weblate. 2021-09-28 09:56:49 +02:00
SC
9c6994b476 Translated using Weblate (Portuguese)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2021-09-27 19:36:47 +02:00
Oğuz Ersen
52ba487617 Translated using Weblate (Turkish)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2021-09-27 19:36:47 +02:00
Eric
21c57c9484 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2021-09-27 19:36:47 +02:00
Ihor Hordiichuk
9b1ea6a07a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2021-09-27 19:36:47 +02:00
solokot
f7d7bb0ea3 Translated using Weblate (Russian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2021-09-27 19:36:46 +02:00
SC
dd96b9ef53 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2021-09-27 19:36:46 +02:00
Matthaiks
b6b01893ba Translated using Weblate (Polish)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2021-09-27 19:36:46 +02:00
Óscar Fernández Díaz
ad531d793d Translated using Weblate (Spanish)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2021-09-27 19:36:45 +02:00
Retrial
a9dd11e24a Translated using Weblate (Greek)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2021-09-27 19:36:45 +02:00
VfBFan
115983830b Translated using Weblate (German)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2021-09-27 19:36:45 +02:00
zeritti
442cece081 Translated using Weblate (Czech)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2021-09-27 19:36:45 +02:00
SUPERYAO
14e08457b9 Complete and improve zh-rTW 2021-09-25 21:59:59 +08:00
J-Jamet
fabcc08cd5 Merge tag '3.0.2' into develop
3.0.2
2021-09-24 19:35:07 +02:00
J-Jamet
7750843b04 Merge branch 'release/3.0.2' 2021-09-24 19:34:58 +02:00
SUPERYAO
40a893a8c9 There is no need to clear the flag when the option is not enabled 2021-09-24 22:30:21 +08:00
SUPERYAO
37ebd30a4d Keep the screen on when watching the entry 2021-09-24 20:33:57 +08:00
Hosted Weblate
c03188e976 Merge branch 'origin/develop' into Weblate. 2021-09-24 13:54:09 +02:00
J-Jamet
d7da1ce333 Upgrade to 3.0.2 and update CHANGELOG 2021-09-24 12:55:08 +02:00
J-Jamet
dd9ee8c3f8 Merge branch 'chenxiaolong-samsung_dex' into develop 2021-09-24 12:50:40 +02:00
Braja Yudhistira
34bbd8f439 Translated using Weblate (Indonesian)
Currently translated at 77.8% (442 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/id/
2021-09-23 21:34:44 +02:00
Milo Ivir
053f57cff5 Translated using Weblate (Croatian)
Currently translated at 99.8% (567 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hr/
2021-09-23 21:34:44 +02:00
Balázs Meskó
365d2e2844 Translated using Weblate (Hungarian)
Currently translated at 82.5% (469 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/hu/
2021-09-23 21:34:43 +02:00
Andrew Gunnerson
c0ac01a34a Add workaround to support Samsung DeX
This commit changes the Magikeyboard service behavior so that KeePassDX
is able to run in Samsung DeX mode. Currently, the app cannot run in
DeX mode because apps which have services using `BIND_INPUT_METHOD` are
blocked.

A new broadcast receiver has been added to listen for DeX's enter/leave
events [1] and disable/enable the `Magikeyboard` service appropriately.
The enabled state of a service lives in the Android framework's
`PackageManager` and survives app crashes and device reboots (though it
does get reset when app data is cleared).

Additionally, an extra check is added to `FileDatabaseSelectActivity` to
ensure the service's enabled state is correct. This is necessary if the
app crashes or is force quit within DeX mode and then the user exits DeX
mode. Otherwise, the service would stay disabled until the user entered
and exited DeX again.

With the new behavior, KeePassDX will generally just work with DeX,
though there's one caveat: after the initial installation, the user must
open the app once outside of DeX. Otherwise, Android will not trigger
the broadcast receiver. This could be fixed by making the service
intially disabled in the manifest with `android:enabled="false"`, but
Android's Settings app in SDK 15 through 25 does not correctly refresh
the keyboard list when changing the service from disabled to enabled.
I opted *not* to introduce different behavior based on the API version.

[1] https://developer.samsung.com/sdp/blog/en-us/2017/07/27/samsung-dex-how-to-detect-the-samsung-dex-mode

Fixes: #245
Signed-off-by: Andrew Gunnerson <chillermillerlong@hotmail.com>
2021-09-18 23:30:37 -04:00
Stephan Paternotte
22c0bc0adb Translated using Weblate (Dutch)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nl/
2021-09-17 18:36:29 +02:00
J-Jamet
1b88f2ddf0 Merge tag '3.0.1' into develop
3.0.1
2021-09-15 13:25:03 +02:00
J-Jamet
b4f2a1eb89 Merge branch 'release/3.0.1' 2021-09-15 13:24:53 +02:00
J-Jamet
e9fc9cbc2a Capture cast exception 2021-09-15 12:21:44 +02:00
J-Jamet
b809180a1b Small changes 2021-09-15 11:25:15 +02:00
J-Jamet
ecc75df3a1 Fix search actions #1091 #1092 2021-09-15 11:16:32 +02:00
J-Jamet
d1b6863143 Update CHANGELOG 2021-09-15 10:36:41 +02:00
J-Jamet
faf27143aa Fix timeout reset #1107 2021-09-15 10:33:37 +02:00
J-Jamet
aee58a4475 Fix exception after group name change and save #1112 2021-09-15 09:48:48 +02:00
VfBFan
c4cbf07d78 Translated using Weblate (German)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2021-09-15 07:34:50 +02:00
J-Jamet
c5e07f643f Fix Magikeyboard URL auto action #1100 2021-09-14 20:40:22 +02:00
J-Jamet
818f5820d5 Update CHANGELOG 2021-09-14 20:13:35 +02:00
J-Jamet
77c6e28876 Fix max lines #1073 2021-09-14 20:06:49 +02:00
J-Jamet
fb7f66012d Upgrade to 3.0.1 2021-09-14 19:35:30 +02:00
J-Jamet
0f7f7bbe6c Min height to 48dp 2021-09-14 19:30:50 +02:00
J-Jamet
8dedb8deb4 Fix text dimension 2021-09-14 19:10:48 +02:00
Long Nguyễn Khánh
dbb2c10bba Translated using Weblate (Vietnamese)
Currently translated at 16.1% (92 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/vi/
2021-09-13 12:46:09 +02:00
Ihor Hordiichuk
67a5eef7d6 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2021-09-12 00:23:20 +02:00
HARADA Hiroyuki
979f651251 Translated using Weblate (Japanese)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2021-09-12 00:23:19 +02:00
SC
3b93cbb009 Translated using Weblate (Portuguese)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2021-09-11 04:18:42 +02:00
SC
30c63bfc4b Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_PT/
2021-09-11 04:18:42 +02:00
SC
bed40324a1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-11 04:18:37 +02:00
Wilker Santana da Silva
bc035de377 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-11 04:18:37 +02:00
SC
4db3cb6936 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.8% (567 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-11 01:07:20 +02:00
Wilker Santana da Silva
ed4b91f4bd Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.8% (567 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-11 01:07:20 +02:00
SC
24c7151276 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.6% (566 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-11 01:00:00 +02:00
Wilker Santana da Silva
804a9c07b8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.6% (566 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-11 00:59:58 +02:00
SC
528ea56821 Translated using Weblate (Portuguese)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt/
2021-09-11 00:01:53 +02:00
SC
7ba9c69ff8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 88.7% (504 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-10 20:50:55 +02:00
Wilker Santana da Silva
0fc34da08a Translated using Weblate (Portuguese (Brazil))
Currently translated at 88.7% (504 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-10 20:50:54 +02:00
SC
3fbf8cdbc8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 83.0% (472 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-10 20:36:00 +02:00
Wilker Santana da Silva
e21f20d818 Translated using Weblate (Portuguese (Brazil))
Currently translated at 83.0% (472 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pt_BR/
2021-09-10 20:35:59 +02:00
Sina bagheri
9fd9a60ca3 Translated using Weblate (Persian)
Currently translated at 56.6% (322 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fa/
2021-09-09 17:32:51 +02:00
Hosted Weblate
78b683d724 Merge branch 'origin/develop' into Weblate. 2021-09-08 07:26:45 +02:00
vachan-maker
ad2f5036e1 Translated using Weblate (Malayalam)
Currently translated at 70.2% (399 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ml/
2021-09-08 07:26:45 +02:00
random r
4afbad8faa Translated using Weblate (Italian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2021-09-08 07:26:44 +02:00
J-Jamet
d284db4d3c Merge tag '3.0.0' into develop
3.0.0
2021-09-07 18:43:40 +02:00
J-Jamet
82450c0ae8 Merge branch 'release/3.0.0' 2021-09-07 18:43:31 +02:00
J-Jamet
8dd6c33901 Fix add entry education hint with default templates 2021-09-07 14:00:02 +02:00
J-Jamet
f920d40db5 Fix autofill popup window application id #1046 2021-09-07 13:45:35 +02:00
J-Jamet
19be6c1acc Upgrade to 3.0.0 2021-09-07 13:17:34 +02:00
J-Jamet
7d9d8ad0e4 Manage magikeyboard in landscape 2021-09-07 13:09:24 +02:00
J-Jamet
85f8237d5f Merge branch 'fullscreen' of git://github.com/chenxiaolong/KeePassDX into chenxiaolong-fullscreen 2021-09-07 12:41:24 +02:00
J-Jamet
c542894734 Small change in progress dialog 2021-09-07 12:18:21 +02:00
J-Jamet
d348987077 Remove unused code 2021-09-07 11:21:28 +02:00
J-Jamet
3718610595 Copy OTP Token from list to provide suitable alternative to #553 2021-09-07 10:44:34 +02:00
J-Jamet
9c36ec0623 Fix datetime font size 2021-09-07 10:29:08 +02:00
J-Jamet
c6917b5d74 Update CHANGELOG 2021-09-07 10:16:38 +02:00
Oliver Cervera
ae8b1c0c29 Translated using Weblate (Italian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2021-09-06 21:34:18 +02:00
Óscar Fernández Díaz
27978c459c Translated using Weblate (Spanish)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2021-09-06 21:34:17 +02:00
Martin
1dc7f5c666 Translated using Weblate (Czech)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2021-09-06 21:34:17 +02:00
zeritti
12ac870d3a Translated using Weblate (Czech)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2021-09-06 21:34:17 +02:00
Aman Kirely
dd1baa0224 Translated using Weblate (Czech)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2021-09-06 21:34:17 +02:00
Andrew Gunnerson
4eaa179789 magikeyboard: Don't force full screen EditTexts on large screen devices
Per [1], Android defaults to showing EditTexts in full screen mode when
the device is in landscape orientation. This makes sense for phones,
but not so much for larger screen devices, like tablets.

This commit updates MagiKeyboard to not use full screen mode on large
screen devices. The condition for disabling full screen mode is the same
as in the AOSP keyboard and should match what other OEM keyboards do as
well.

[1] https://developer.android.com/reference/android/inputmethodservice/InputMethodService#fullscreen-mode
2021-09-06 13:01:56 -04:00
J-Jamet
9008cd4549 Remove max lines in TextFieldView #1073 #1076 2021-09-06 12:18:17 +02:00
Oğuz Ersen
bb27ef41cc Translated using Weblate (Turkish)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2021-09-04 17:34:43 +02:00
Allan Nordhøy
2d35ac1df8 Translated using Weblate (Norwegian Bokmål)
Currently translated at 74.8% (425 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/nb_NO/
2021-09-04 17:34:43 +02:00
Eric
589ffc0c06 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2021-09-04 17:34:42 +02:00
Ihor Hordiichuk
1f7f38c7d3 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2021-09-04 17:34:41 +02:00
solokot
83817a2dc0 Translated using Weblate (Russian)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2021-09-04 17:34:41 +02:00
Matthaiks
11af9da66f Translated using Weblate (Polish)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2021-09-04 17:34:40 +02:00
Retrial
af3926acf3 Translated using Weblate (Greek)
Currently translated at 100.0% (568 of 568 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2021-09-04 17:34:40 +02:00
Hosted Weblate
ab40c2b3fd Merge branch 'origin/develop' into Weblate. 2021-09-03 16:07:31 +02:00
Oliver Cervera
fd05670dbc Translated using Weblate (Italian)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2021-09-03 00:32:28 +02:00
Óscar Fernández Díaz
1ac094bfae Translated using Weblate (Spanish)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/es/
2021-09-03 00:32:27 +02:00
Oğuz Ersen
fdf052cddb Translated using Weblate (Turkish)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/tr/
2021-09-01 10:34:02 +02:00
Eric
9a8d50ba6f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/zh_Hans/
2021-09-01 10:34:02 +02:00
Ihor Hordiichuk
136c97c312 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/uk/
2021-09-01 10:34:02 +02:00
solokot
bf00b88ef3 Translated using Weblate (Russian)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/
2021-09-01 10:34:02 +02:00
Matthaiks
bafd1ea549 Translated using Weblate (Polish)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/pl/
2021-09-01 10:34:01 +02:00
Hisikawa Mizuki
982618511b Translated using Weblate (Japanese)
Currently translated at 99.2% (561 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ja/
2021-09-01 10:34:01 +02:00
Oliver Cervera
a4ad7ca3b1 Translated using Weblate (Italian)
Currently translated at 99.4% (562 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/it/
2021-09-01 10:34:01 +02:00
Éfrit
99d71b57a4 Translated using Weblate (French)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/fr/
2021-09-01 10:34:00 +02:00
Retrial
1b2d8502e0 Translated using Weblate (Greek)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/el/
2021-09-01 10:34:00 +02:00
VfBFan
53e4ea9334 Translated using Weblate (German)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/de/
2021-09-01 10:34:00 +02:00
zeritti
3ce704155c Translated using Weblate (Czech)
Currently translated at 100.0% (565 of 565 strings)

Translation: KeePassDX/Strings
Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/cs/
2021-09-01 10:33:59 +02:00
1151 changed files with 42813 additions and 29944 deletions

13
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
# These are supported funding model platforms
#github: [J-Jamet] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: Kunzisoft # Replace with a single Liberapay username
issuehunt: Kunzisoft/KeePassDX # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: ['https://www.keepassdx.com/#donation'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -8,9 +8,11 @@ assignees: ''
--- ---
**Describe the bug** **Describe the bug**
A clear and concise description of what the bug is. A clear and concise description of what the bug is.
**To Reproduce** **To Reproduce**
Steps to reproduce the behavior: Steps to reproduce the behavior:
1. Go to '...' 1. Go to '...'
2. Click on '....' 2. Click on '....'
@@ -18,24 +20,30 @@ Steps to reproduce the behavior:
4. See error 4. See error
**Expected behavior** **Expected behavior**
A clear and concise description of what you expected to happen. A clear and concise description of what you expected to happen.
**KeePass Database** **KeePass Database**
- Created with: [e.g Windows KeePass 2.42] - Created with: [e.g Windows KeePass 2.42]
- Version: [e.g. 2] - Version: [e.g. 2]
- Location: [e.g. Remote file retrieved with GDrive app] - Location: [e.g. Remote file retrieved with GDrive app]
- File provider (`content://` URI): [e.g. `content://com.google.android.apps.docs.storage/5`]
- Size: [e.g. 150Mo] - Size: [e.g. 150Mo]
- Contains attachment: [e.g. Yes] - Contains attachment: [e.g. Yes]
**KeePassDX (please complete the following information):** **KeePassDX:**
- Version: [e.g. 2.5.0.0beta23] - Version: [e.g. 2.5.0.0beta23]
- Build: [e.g. Free] - Build: [e.g. Free]
- Language: [e.g. French] - Language: [e.g. French]
**Android (please complete the following information):** **Android:**
- Device: [e.g. GalaxyS8] - Device: [e.g. GalaxyS8]
- Version: [e.g. 8.1] - Version: [e.g. 8.1]
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.
- Browser for Autofill: [e.g. Chrome version X] - Browser for Autofill: [e.g. Chrome version X]

3
.gitignore vendored
View File

@@ -80,6 +80,9 @@ art/screen*.png
art/logo_512.png art/logo_512.png
art/store_screens/ art/store_screens/
# Release
releases/*
# Dir linux # Dir linux
.directory .directory
*/.directory */.directory

168
CHANGELOG
View File

@@ -1,3 +1,169 @@
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 #874 #1327
* Fix bugs #1589 #1584 #1545 #1563 #1371 #1609
KeePassDX(3.5.1)
* Fix action dialog with YubiKey challenge-response #1506
KeePassDX(3.5.0)
* Support YubiKey challenge-response #8 #137
* Better exception management during database save #1346
* Add "Screenshot mode" setting #459 #1377 #1354 (Thx @GianpaMX)
* Hide clipboard sensitive text when copy entry field #1386
* Fix attachment download button #1401
* Add monochrome icon #1403 #1404 (Thx @Sandelinos)
* Fix lock with back button #1412 #1414 (Thx @ryg-git)
* Vanadium compatibility #1447 (Thx @flawedworld)
KeePassDX(3.4.5)
* Fix custom data in group (fix KeeShare) #1335
* Fix device credential unlocking #1344
* New clipboard manager #1343
* Keep screen on by default when viewing an entry
* Change the order of the search filters
* Fix searchable selection
KeePassDX(3.4.4)
* Fix crash in New Android 13 #1321
* Better backstack management for selection mode
* Prevent Tapjacking #1318
* Small changes #1298
KeePassDX(3.4.3)
* Remove "Select share info" setting for Magikeyboard #1304
* Fix quick search and better loadGroup implementation #1302
* Fix small bugs
KeePassDX(3.4.2)
* Fix service parameter and workflow to remove notification when service is killed
* Fix color
KeePassDX(3.4.1)
* Fix search mode with Magikeyboard #1292
* Fix select another entry with Magikeyboard #1293
* Fix unexpected lock with Magikeyboard #1294
* Small UI changes
KeePassDX(3.4.0)
* Passphrase implementation #218
* Show visual password strength indicator with entropy #631 #869 #454 #1270
* Dynamically save password generator configuration #618 #696
* Add advanced password filters #1052 #448 #983 #271 #539
* Better search implementation #175 #1254 #1267
* Manage package name from Magikeyboard #1010 #1261
* Ask confirmation to lock if changes without save #970
* Fix small bugs #1282
KeePassDX(3.3.3)
* Fix shared otpauth link if database not open #1274
* Ellipsize attachment name #1253
* Add a warning to inform about KeyStore usage #1269
* Fingerprint unlock no more by default #1273
* Tabs to show main and advanced content separately
* Fix URL color
KeePassDX(3.3.2)
* Merge KeePassDX & KeePassDX Pro #1257
* Create new Contributor Pro app
KeePassDX(3.3.1)
* Fix Japanese keyboard in search #1248
* Better OOM management #256
* Fix filters #1249
* Fix temp advanced unlocking #1245
* Best autofill recognition #1250
* Workaround to fill OTP token in multiple fields with Magikeyboard (long press) #1158
KeePassDX(3.3.0)
* Quick search and dynamic filters #163 #462 #521
* Keep search context #1141
* Add searchable groups #905 #1006
* Search with regular expression #175
* Merge from file and save as copy #1221 #1204 #840
* Fix custom data #1236
* Fix education hints #1192
* Fix save and app instance in selection mode
* New UI and fix styles
* Add "Simple" and "Reply" themes
KeePassDX(3.2.0)
* Manage data merge #840 #977
* Manage Tags #633
* Inherit colors and icon from template #1213 #1130
* Entry colors setting #1207
* Setting to keep the screen on when watching the entry #1119
* Add path in quick search
* Small fixes
KeePassDX(3.1.0)
* Add breadcrumb
* Add path in search results #1148
* Add group info dialog #1177
* Manage colors #64 #913
* Fix UI in Android 8 #509
* Upgrade libs and SDK to 31 #833
* Fix parser of database v1 #1201
* Stop asking WRITE_EXTERNAL_STORAGE permission
KeePassDX(3.0.4)
* Fix autofill inline bugs #1173 #1165
* Small UI change
KeePassDX(3.0.3)
* Change default Argon2 parameters #1098
* Add & edit custom icon name #976
* Fix templates #1128 #1133 #1138
* Update Autofill compatibility list #725 #1154
* Improve fingerprint usage #1137 #1145
* Change backup configuration #1144
* Add lock button in database notification
KeePassDX(3.0.2)
* Samsung DeX mode #1114 #245 (Thx @chenxiaolong)
KeePassDX(3.0.1)
* Fix text size and smallest margin #1085
* Fix number of lines during an edition #1073
* Fix Magikeyboard URL auto action #1100
* Fix exception after group name change and save #1112
* Fix timeout reset #1107
* Fix search actions #1091 #1092
* Small changes #1106 #1085
KeePassDX(3.0.0) KeePassDX(3.0.0)
* Add / Manage dynamic templates #191 * Add / Manage dynamic templates #191
* Manually select RecycleBin group and Templates group #191 * Manually select RecycleBin group and Templates group #191
@@ -5,7 +171,7 @@ KeePassDX(3.0.0)
* Fix timeout in dialogs #716 * Fix timeout in dialogs #716
* Check URI permissions #626 * Check URI permissions #626
* Better autofill implementation #943 #946 #984 #1070 (Thx @uduerholz) * Better autofill implementation #943 #946 #984 #1070 (Thx @uduerholz)
* Improvements #680 #1035 #1043 #942 #1021 #1027 * Improvements #680 #1035 #1043 #942 #1021 #1027 #1046 #1082 #1083 (Thx @chenxiaolong)
KeePassDX(2.10.5) KeePassDX(2.10.5)
* Increase the saving speed of database #1028 * Increase the saving speed of database #1028

10
Gemfile Normal file
View File

@@ -0,0 +1,10 @@
# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!
source "https://rubygems.org"
gem 'fastlane'
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

220
Gemfile.lock Normal file
View File

@@ -0,0 +1,220 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.6)
rexml
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
artifactory (3.0.15)
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)
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)
aws-sigv4 (~> 1.6)
aws-sigv4 (1.6.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
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)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.100.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
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 (~> 1.0)
fastimage (2.2.7)
fastlane (2.214.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
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
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)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
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.1)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.46.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
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-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)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.19.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.7.0)
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)
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)
multi_json (1.15.0)
multipart-post (2.3.0)
nanaimo (0.3.0)
naturally (2.2.1)
optparse (0.1.1)
os (1.1.4)
plist (3.7.0)
public_suffix (5.0.3)
rake (13.0.6)
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)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.17.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
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)
word_wrap (1.0.0)
xcodeproj (1.22.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)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
ruby
DEPENDENCIES
fastlane
fastlane-plugin-versioning_android
BUNDLED WITH
2.1.4

View File

@@ -1,6 +1,6 @@
# Android KeePassDX # Android KeePassDX
<img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/icon.png"> KeePassDX is a **multi-format KeePass manager for Android devices**. The app allows creating keys and passwords in a secure way by integrating with the Android design standards. <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 src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen.jpg" width="220"> <img src="https://raw.githubusercontent.com/Kunzisoft/KeePassDX/master/art/screen.jpg" width="220">
@@ -8,13 +8,14 @@
- Create database files / entries and groups. - Create database files / entries and groups.
- Support for **.kdb** and **.kdbx** files (version 1 to 4) with AES - Twofish - ChaCha20 - Argon2 algorithm. - Support for **.kdb** and **.kdbx** files (version 1 to 4) with AES - Twofish - ChaCha20 - Argon2 algorithm.
- **Compatible** with the majority of alternative programs (KeePass, KeePassX, KeePassXC, …). - **Compatible** with the majority of alternative programs (KeePass, KeePassXC, KeeWeb, …).
- Allows opening and **copying URI / URL fields quickly**. - Allows opening and **copying URI / URL fields quickly**.
- **Biometric recognition** for fast unlocking *(fingerprint / face unlock / …)*. - **Biometric recognition** for fast unlocking *(fingerprint / face unlock / …)*.
- **One-Time Password** management *(HOTP / TOTP)* for Two-factor authentication (2FA). - **One-Time Password** management *(HOTP / TOTP)* for Two-factor authentication (2FA).
- Material design with **themes**. - Material design with **themes**.
- **Auto-Fill** and Integration. - **Auto-Fill** and Integration.
- Field filling **keyboard**. - Field filling **keyboard**.
- Dynamic **templates**
- **History** of each entry. - **History** of each entry.
- Precise management of **settings**. - Precise management of **settings**.
- Code written in **native languages** *(Kotlin / Java / JNI / C)*. - Code written in **native languages** *(Kotlin / Java / JNI / C)*.
@@ -42,21 +43,39 @@ Optional visual styles are accessible after a contribution (and a congratulatory
* Add features by making a **[pull request](https://help.github.com/articles/about-pull-requests/)**. * Add features by making a **[pull request](https://help.github.com/articles/about-pull-requests/)**.
* Help to **[translate](https://hosted.weblate.org/projects/keepass-dx/strings/)** KeePassDX to your language (on [Weblate](https://hosted.weblate.org/projects/keepass-dx/) or by sending a [pull request](https://help.github.com/articles/about-pull-requests/)). * Help to **[translate](https://hosted.weblate.org/projects/keepass-dx/strings/)** KeePassDX to your language (on [Weblate](https://hosted.weblate.org/projects/keepass-dx/) or by sending a [pull request](https://help.github.com/articles/about-pull-requests/)).
* **[Donate](https://www.kunzisoft.com/donation)** 人◕ ‿‿ ◕人Y for a better service and a quick development of your features. * **[Donate](https://www.keepassdx.com/#donation)** 人◕ ‿‿ ◕人Y for a better service and a quick development of your features.
* Buy the **[Pro version](https://play.google.com/store/apps/details?id=com.kunzisoft.keepass.pro)** of KeePassDX. * Buy the **[Pro version](https://play.google.com/store/apps/details?id=com.kunzisoft.keepass.pro)** of KeePassDX.
## Download ## 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 that all the libraries and app code is libre software.*
[<img src="https://f-droid.org/badge/get-it-on.png" [<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid" alt="Get it on F-Droid"
height="80">](https://f-droid.org/en/packages/com.kunzisoft.keepass.libre/) height="80">](https://f-droid.org/packages/com.kunzisoft.keepass.libre/)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" [<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Get it on Google Play" alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=com.kunzisoft.keepass.free) 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)
## Verify the authenticity of the downloaded app from GitHub
1- Download the latest app from [GitHub releases](https://github.com/Kunzisoft/KeePassDX/releases/latest). <br>
2- Open the directory where you saved the downloaded file in the Terminal on Linux/MacOS. <br>
3- You must have `keytool` command installed. <br>
4- Depending on the flavor you downloaded, run:
```
keytool -printcert -jarfile KeePassDX-*-libre.apk | grep '7D:55:B8:AF:21:03:81:AA:BF:96:0F:07:E1:7C:F7:85:7B:6D:2A:64:2C:A2:DA:6B:F0:BD:F1:B2:00:36:2F:04'
```
Or:
```
keytool -printcert -jarfile KeePassDX-*-free.apk | grep '7D:55:B8:AF:21:03:81:AA:BF:96:0F:07:E1:7C:F7:85:7B:6D:2A:64:2C:A2:DA:6B:F0:BD:F1:B2:00:36:2F:04'
```
You should get this output:
```
SHA256: 7D:55:B8:AF:21:03:81:AA:BF:96:0F:07:E1:7C:F7:85:7B:6D:2A:64:2C:A2:DA:6B:F0:BD:F1:B2:00:36:2F:04
```
## Frequently Asked Questions ## Frequently Asked Questions
Other questions? You can read the [FAQ](https://github.com/Kunzisoft/KeePassDX/wiki/FAQ) Other questions? You can read the [FAQ](https://github.com/Kunzisoft/KeePassDX/wiki/FAQ)
@@ -71,7 +90,7 @@ Other questions? You can read the [FAQ](https://github.com/Kunzisoft/KeePassDX/w
## License ## License
Copyright © 2020 Jeremy Jamet / [Kunzisoft](https://www.kunzisoft.com). Copyright © 2023 Jeremy Jamet / [Kunzisoft](https://www.kunzisoft.com).
This file is part of KeePassDX. This file is part of KeePassDX.

View File

@@ -1,18 +1,19 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
android { android {
compileSdkVersion 30 namespace 'com.kunzisoft.keepass'
buildToolsVersion "30.0.3" compileSdkVersion 33
ndkVersion "21.4.7075529" buildToolsVersion "33.0.2"
defaultConfig { defaultConfig {
applicationId "com.kunzisoft.keepass" applicationId "com.kunzisoft.keepass"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 30 targetSdkVersion 33
versionCode = 86 versionCode = 129
versionName = "3.0.0_beta03" versionName = "4.0.6"
multiDexEnabled true multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests" testApplicationId = "com.kunzisoft.keepass.tests"
@@ -32,7 +33,6 @@ android {
buildTypes { buildTypes {
release { release {
minifyEnabled = false minifyEnabled = false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
@@ -42,38 +42,34 @@ android {
dimension "version" dimension "version"
applicationIdSuffix = ".libre" applicationIdSuffix = ".libre"
buildConfigField "String", "BUILD_VERSION", "\"libre\"" buildConfigField "String", "BUILD_VERSION", "\"libre\""
buildConfigField "boolean", "FULL_VERSION", "true"
buildConfigField "boolean", "CLOSED_STORE", "false" buildConfigField "boolean", "CLOSED_STORE", "false"
buildConfigField "String[]", "STYLES_DISABLED", buildConfigField "String[]", "STYLES_DISABLED",
"{\"KeepassDXStyle_Red\"," + "{\"KeepassDXStyle_Red\"," +
"\"KeepassDXStyle_Red_Night\"," + "\"KeepassDXStyle_Red_Night\"," +
"\"KeepassDXStyle_Reply\"," +
"\"KeepassDXStyle_Reply_Night\"," +
"\"KeepassDXStyle_Purple\"," + "\"KeepassDXStyle_Purple\"," +
"\"KeepassDXStyle_Purple_Dark\"}" "\"KeepassDXStyle_Purple_Dark\"," +
"\"KeepassDXStyle_Dynamic_Light\"," +
"\"KeepassDXStyle_Dynamic_Night\"}"
buildConfigField "String[]", "ICON_PACKS_DISABLED", "{}" buildConfigField "String[]", "ICON_PACKS_DISABLED", "{}"
} }
pro {
dimension "version"
applicationIdSuffix = ".pro"
buildConfigField "String", "BUILD_VERSION", "\"pro\""
buildConfigField "boolean", "FULL_VERSION", "true"
buildConfigField "boolean", "CLOSED_STORE", "true"
buildConfigField "String[]", "STYLES_DISABLED", "{}"
buildConfigField "String[]", "ICON_PACKS_DISABLED", "{}"
manifestPlaceholders = [ googleAndroidBackupAPIKey:"AEdPqrEAAAAIZiXvrQCzSV9LNI6-p7cjTKENZLHIrz_zaqZuQQ" ]
}
free { free {
dimension "version" dimension "version"
applicationIdSuffix = ".free" applicationIdSuffix = ".free"
buildConfigField "String", "BUILD_VERSION", "\"free\"" buildConfigField "String", "BUILD_VERSION", "\"free\""
buildConfigField "boolean", "FULL_VERSION", "false"
buildConfigField "boolean", "CLOSED_STORE", "true" buildConfigField "boolean", "CLOSED_STORE", "true"
buildConfigField "String[]", "STYLES_DISABLED", buildConfigField "String[]", "STYLES_DISABLED",
"{\"KeepassDXStyle_Blue\"," + "{\"KeepassDXStyle_Blue\"," +
"\"KeepassDXStyle_Blue_Night\"," + "\"KeepassDXStyle_Blue_Night\"," +
"\"KeepassDXStyle_Red\"," + "\"KeepassDXStyle_Red\"," +
"\"KeepassDXStyle_Red_Night\"," + "\"KeepassDXStyle_Red_Night\"," +
"\"KeepassDXStyle_Reply\"," +
"\"KeepassDXStyle_Reply_Night\"," +
"\"KeepassDXStyle_Purple\"," + "\"KeepassDXStyle_Purple\"," +
"\"KeepassDXStyle_Purple_Dark\"}" "\"KeepassDXStyle_Purple_Dark\"," +
"\"KeepassDXStyle_Dynamic_Light\"," +
"\"KeepassDXStyle_Dynamic_Night\"}"
buildConfigField "String[]", "ICON_PACKS_DISABLED", "{}" buildConfigField "String[]", "ICON_PACKS_DISABLED", "{}"
manifestPlaceholders = [ googleAndroidBackupAPIKey:"AEdPqrEAAAAIbRfbV8fHLItXo8OcHwrO0sSNblqhPwkc0DPTqg" ] manifestPlaceholders = [ googleAndroidBackupAPIKey:"AEdPqrEAAAAIbRfbV8fHLItXo8OcHwrO0sSNblqhPwkc0DPTqg" ]
} }
@@ -81,7 +77,6 @@ android {
sourceSets { sourceSets {
libre.res.srcDir 'src/libre/res' libre.res.srcDir 'src/libre/res'
pro.res.srcDir 'src/pro/res'
free.res.srcDir 'src/free/res' free.res.srcDir 'src/free/res'
} }
@@ -99,43 +94,48 @@ android {
} }
} }
def room_version = "2.2.6" def room_version = "2.5.1"
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.2.0' implementation "com.android.support:multidex:1.0.3"
implementation 'androidx.preference:preference-ktx:1.1.1' implementation "androidx.appcompat:appcompat:$android_appcompat_version"
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01' implementation 'androidx.viewpager2:viewpager2:1.1.0-beta02'
implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'androidx.biometric:biometric:1.1.0' implementation 'androidx.biometric:biometric:1.1.0'
implementation 'androidx.media:media:1.6.0'
// Lifecycle - LiveData - ViewModel - Coroutines // Lifecycle - LiveData - ViewModel - Coroutines
implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.core:core-ktx:$android_core_version"
implementation 'androidx.fragment:fragment-ktx:1.2.5' implementation 'androidx.fragment:fragment-ktx:1.6.0'
// WARNING: Don't upgrade because slowdown https://github.com/Kunzisoft/KeePassDX/issues/923 implementation "com.google.android.material:material:$android_material_version"
implementation 'com.google.android.material:material:1.1.0' // Token auto complete
// From sources until https://github.com/splitwise/TokenAutoComplete/pull/422 fixed
implementation "com.splitwise:tokenautocomplete:4.0.0-beta05"
// Database // Database
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version" kapt "androidx.room:room-compiler:$room_version"
// Autofill // Autofill
implementation "androidx.autofill:autofill:1.1.0" implementation "androidx.autofill:autofill:1.1.0"
// Time // Time
implementation 'joda-time:joda-time:2.10.6' implementation 'joda-time:joda-time:2.10.13'
// Color // Color
implementation 'com.github.Kunzisoft:AndroidClearChroma:2.4' implementation 'com.github.Kunzisoft:AndroidClearChroma:2.6'
// Education // Education
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.0' implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.3'
// Apache Commons // Apache Commons
implementation 'commons-io:commons-io:2.8.0' implementation 'commons-io:commons-io:2.8.0'
implementation 'commons-codec:commons-codec:1.15' implementation 'commons-codec:commons-codec:1.15'
// Encrypt lib // Password generator
implementation project(path: ':crypto') implementation 'me.gosimple:nbvcxz:1.5.0'
// Icon pack
implementation project(path: ':icon-pack-classic') // Modules import
implementation project(path: ':icon-pack-material') implementation project(path: ':database')
implementation project(path: ':icon-pack')
// Tests // Tests
androidTestImplementation 'androidx.test:runner:1.3.0' androidTestImplementation "androidx.test:runner:$android_test_version"
androidTestImplementation 'androidx.test:rules:1.3.0' androidTestImplementation "androidx.test:rules:$android_test_version"
} }

View File

@@ -0,0 +1,90 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "f8fb4aed546de19ae7ca0797f49b26a4",
"entities": [
{
"tableName": "file_database_history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`database_uri` TEXT NOT NULL, `database_alias` TEXT NOT NULL, `keyfile_uri` TEXT, `hardware_key` TEXT, `updated` INTEGER NOT NULL, PRIMARY KEY(`database_uri`))",
"fields": [
{
"fieldPath": "databaseUri",
"columnName": "database_uri",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "databaseAlias",
"columnName": "database_alias",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "keyFileUri",
"columnName": "keyfile_uri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "hardwareKey",
"columnName": "hardware_key",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "updated",
"columnName": "updated",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"database_uri"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "cipher_database",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`database_uri` TEXT NOT NULL, `encrypted_value` TEXT NOT NULL, `specs_parameters` TEXT NOT NULL, PRIMARY KEY(`database_uri`))",
"fields": [
{
"fieldPath": "databaseUri",
"columnName": "database_uri",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encryptedValue",
"columnName": "encrypted_value",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "specParameters",
"columnName": "specs_parameters",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"database_uri"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f8fb4aed546de19ae7ca0797f49b26a4')"
]
}
}

View File

@@ -1,61 +1,31 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="108"
android:viewportHeight="108"
android:width="108dp" android:width="108dp"
android:height="108dp"> android:height="108dp"
android:viewportWidth="120"
android:viewportHeight="120">
<group <group
android:translateY="-332"> android:translateX="6"
<group android:translateY="8">
android:translateY="332"> <path
<path android:fillColor="#24000000"
android:pathData="M65.728516 32.791016L58.052734 35.904297 56.173828 48.380859 35.306641 69.267578 35.238281 73.759766 69.478516 108 108 108 108 70.810547 73.09375 35.904297 65.728516 32.791016Z" android:strokeWidth="1.99999297"
android:strokeLineJoin="round" android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
android:strokeLineCap="round" <path
android:strokeMiterLimit="4" > android:fillColor="#24000000"
<aapt:attr name="android:fillColor"> android:strokeWidth="1.99999297"
<gradient android:pathData="M63.9961,34.0059 C61.5643,34.096,59.2564,35.102,57.5352,36.8223 C53.7682,40.589,53.7682,46.6982,57.5352,50.4649 C61.3017,54.232,67.4073,54.232,71.1739,50.4649 C74.9409,46.6982,74.9409,40.589,71.1739,36.8223 C69.2766,34.9258,66.6768,33.9054,63.9962,34.0059 Z M68.1992,40.6954 C69.8278,40.6958,71.148,42.016,71.1484,43.6446 C71.148,45.2732,69.8278,46.5934,68.1992,46.5938 C66.5706,46.5934,65.2504,45.2732,65.25,43.6446 C65.2504,42.016,66.5706,40.6958,68.1992,40.6954 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
android:endColor="#0000" </group>
android:endX="80" <group
android:endY="80" android:translateX="6"
android:startColor="#4e000000" android:translateY="6">
android:startX="0" <path
android:startY="0" android:fillColor="#ffa726"
android:type="linear"/> android:strokeWidth="1.99999297"
</aapt:attr> android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
</path> <path
</group> android:fillColor="#ffffff"
<group android:strokeWidth="1.99999297"
android:scaleX="0.3939503" android:pathData="M63.9961,34.0059 C61.5643,34.096,59.2564,35.102,57.5352,36.8223 C53.7682,40.589,53.7682,46.6982,57.5352,50.4649 C61.3017,54.232,67.4073,54.232,71.1739,50.4649 C74.9409,46.6982,74.9409,40.589,71.1739,36.8223 C69.2766,34.9258,66.6768,33.9054,63.9962,34.0059 Z M68.1992,40.6954 C69.8278,40.6958,71.148,42.016,71.1484,43.6446 C71.148,45.2732,69.8278,46.5934,68.1992,46.5938 C66.5706,46.5934,65.2504,45.2732,65.25,43.6446 C65.2504,42.016,66.5706,40.6958,68.1992,40.6954 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
android:scaleY="0.3939503"
android:translateX="33.66343"
android:translateY="233.998">
<path
android:pathData="M88.76953 339.91602L4.1718754 424.59766 4.0000004 436 15.400391 435.82813 27.240234 424 40 424l0 -12 12 0 0 -12.73438 34.01172 -33.97656A8 8 0 0 1 84 360a8 8 0 0 1 8 -8 8 8 0 0 1 5.296882 2.01367l2.787098 -2.7832 -11.31445 -11.31445z"
android:fillColor="#eaeaea"
android:strokeWidth="1"
android:strokeColor="#58000000" />
</group>
<group
android:scaleX="0.3939503"
android:scaleY="0.3939503"
android:translateX="33.66343"
android:translateY="233.998">
<path
android:pathData="M4.0000004 340L4.1718754 351.40137 88.59863 435.82812 100 436 99.828122 424.59863 15.401367 340.17188Z"
android:fillColor="#81c784" />
</group>
<group
android:scaleX="0.3939503"
android:scaleY="0.3939503"
android:translateX="33.66343"
android:translateY="233.998">
<path
android:pathData="M81.39454 332.00195a27 27 0 0 0 -19.48634 7.90625 27 27 0 0 0 0 38.1836 27 27 0 0 0 38.1836 0 27 27 0 0 0 0 -38.1836 27 27 0 0 0 -18.69726 -7.90625zM92 352a8 8 0 0 1 8 8 8 8 0 0 1 -8 8 8 8 0 0 1 -8 -8 8 8 0 0 1 8 -8z"
android:fillColor="#eaeaea"
android:strokeWidth="1"
android:strokeColor="#58000000" />
</group>
</group> </group>
</vector> </vector>

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="108dp"
android:height="108dp"
android:viewportWidth="120"
android:viewportHeight="120">
<group
android:translateX="6"
android:translateY="6">
<path
android:fillColor="#ffffff"
android:strokeWidth="1.99999297"
android:pathData="M63.9961,34.0059 C61.5643,34.096,59.2564,35.102,57.5352,36.8223 C53.7682,40.589,53.7682,46.6982,57.5352,50.4649 C61.3017,54.232,67.4073,54.232,71.1739,50.4649 C74.9409,46.6982,74.9409,40.589,71.1739,36.8223 C69.2766,34.9258,66.6768,33.9054,63.9962,34.0059 Z M68.1992,40.6954 C69.8278,40.6958,71.148,42.016,71.1484,43.6446 C71.148,45.2732,69.8278,46.5934,68.1992,46.5938 C66.5706,46.5934,65.2504,45.2732,65.25,43.6446 C65.2504,42.016,66.5706,40.6958,68.1992,40.6954 Z M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
</group>
</vector>

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="M63.9961,34.0059 C61.5643,34.096,59.2564,35.102,57.5352,36.8223 C53.7682,40.589,53.7682,46.6982,57.5352,50.4649 C61.3017,54.232,67.4073,54.232,71.1739,50.4649 C74.9409,46.6982,74.9409,40.589,71.1739,36.8223 C69.2766,34.9258,66.6768,33.9054,63.9962,34.0059 Z M68.1992,40.6954 C69.8278,40.6958,71.148,42.016,71.1484,43.6446 C71.148,45.2732,69.8278,46.5934,68.1992,46.5938 C66.5706,46.5934,65.2504,45.2732,65.25,43.6446 C65.2504,42.016,66.5706,40.6958,68.1992,40.6954 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
</group>
</vector>

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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,61 +1,31 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="108"
android:viewportHeight="108"
android:width="108dp" android:width="108dp"
android:height="108dp"> android:height="108dp"
android:viewportWidth="120"
android:viewportHeight="120">
<group <group
android:translateY="-332"> android:translateX="6"
<group android:translateY="8">
android:translateY="332"> <path
<path android:fillColor="#24000000"
android:pathData="M65.728516 32.791016L58.052734 35.904297 56.173828 48.380859 35.306641 69.267578 35.238281 73.759766 69.478516 108 108 108 108 70.810547 73.09375 35.904297 65.728516 32.791016Z" android:strokeWidth="1.99999297"
android:strokeLineJoin="round" android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
android:strokeLineCap="round" <path
android:strokeMiterLimit="4" > android:fillColor="#24000000"
<aapt:attr name="android:fillColor"> android:strokeWidth="1.99999297"
<gradient android:pathData="M64.501,35.0576 C63.7095,35.0576,62.918,35.3613,62.3115,35.9678 L55.0127,43.2666 C53.7998,44.4795,53.7998,46.4306,55.0127,47.6436 L62.3115,54.9424 C63.5244,56.1553,65.4775,56.1553,66.6904,54.9424 L73.9873,47.6436 C75.2002,46.4307,75.2002,44.4796,73.9873,43.2666 L66.6904,35.9678 C66.0839,35.3613,65.2924,35.0576,64.5009,35.0576 Z M67.6729,42.6006 C69.3298,42.6006,70.6729,43.9437,70.6729,45.6006 C70.6729,47.2575,69.3298,48.6006,67.6729,48.6006 C66.016,48.6006,64.6729,47.2575,64.6729,45.6006 C64.6729,43.9437,66.016,42.6006,67.6729,42.6006 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
android:endColor="#0000" </group>
android:endX="80" <group
android:endY="80" android:translateX="6"
android:startColor="#4e000000" android:translateY="6">
android:startX="0" <path
android:startY="0" android:fillColor="#ffa726"
android:type="linear"/> android:strokeWidth="1.99999297"
</aapt:attr> android:pathData="M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z" />
</path> <path
</group> android:fillColor="#ffffff"
<group android:strokeWidth="1.99999297"
android:scaleX="0.3939503" android:pathData="M64.501,35.0576 C63.7095,35.0576,62.918,35.3613,62.3115,35.9678 L55.0127,43.2666 C53.7998,44.4795,53.7998,46.4306,55.0127,47.6436 L62.3115,54.9424 C63.5244,56.1553,65.4775,56.1553,66.6904,54.9424 L73.9873,47.6436 C75.2002,46.4307,75.2002,44.4796,73.9873,43.2666 L66.6904,35.9678 C66.0839,35.3613,65.2924,35.0576,64.5009,35.0576 Z M67.6729,42.6006 C69.3298,42.6006,70.6729,43.9437,70.6729,45.6006 C70.6729,47.2575,69.3298,48.6006,67.6729,48.6006 C66.016,48.6006,64.6729,47.2575,64.6729,45.6006 C64.6729,43.9437,66.016,42.6006,67.6729,42.6006 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
android:scaleY="0.3939503"
android:translateX="33.66343"
android:translateY="233.998">
<path
android:pathData="M88.76953 339.91602L4.1718754 424.59766 4.0000004 436 15.400391 435.82813 27.240234 424 40 424l0 -12 12 0 0 -12.73438 34.01172 -33.97656A8 8 0 0 1 84 360a8 8 0 0 1 8 -8 8 8 0 0 1 5.296882 2.01367l2.787098 -2.7832 -11.31445 -11.31445z"
android:fillColor="#eaeaea"
android:strokeWidth="1"
android:strokeColor="#58000000"/>
</group>
<group
android:scaleX="0.3939503"
android:scaleY="0.3939503"
android:translateX="33.66343"
android:translateY="233.998">
<path
android:pathData="M4.0000004 340L4.1718754 351.40137 88.59863 435.82812 100 436 99.828122 424.59863 15.401367 340.17188Z"
android:fillColor="#64b5f6" />
</group>
<group
android:scaleX="0.3939503"
android:scaleY="0.3939503"
android:translateX="33.66343"
android:translateY="233.998">
<path
android:pathData="M81.39454 332.00195a27 27 0 0 0 -19.48634 7.90625 27 27 0 0 0 0 38.1836 27 27 0 0 0 38.1836 0 27 27 0 0 0 0 -38.1836 27 27 0 0 0 -18.69726 -7.90625zM92 352a8 8 0 0 1 8 8 8 8 0 0 1 -8 8 8 8 0 0 1 -8 -8 8 8 0 0 1 8 -8z"
android:fillColor="#eaeaea"
android:strokeWidth="1"
android:strokeColor="#58000000" />
</group>
</group> </group>
</vector> </vector>

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="108dp"
android:height="108dp"
android:viewportWidth="120"
android:viewportHeight="120">
<group
android:translateX="6"
android:translateY="6">
<path
android:fillColor="#ffffff"
android:strokeWidth="1.99999297"
android:pathData="M64.501,35.0576 C63.7095,35.0576,62.918,35.3613,62.3115,35.9678 L55.0127,43.2666 C53.7998,44.4795,53.7998,46.4306,55.0127,47.6436 L62.3115,54.9424 C63.5244,56.1553,65.4775,56.1553,66.6904,54.9424 L73.9873,47.6436 C75.2002,46.4307,75.2002,44.4796,73.9873,43.2666 L66.6904,35.9678 C66.0839,35.3613,65.2924,35.0576,64.5009,35.0576 Z M67.6729,42.6006 C69.3298,42.6006,70.6729,43.9437,70.6729,45.6006 C70.6729,47.2575,69.3298,48.6006,67.6729,48.6006 C66.016,48.6006,64.6729,47.2575,64.6729,45.6006 C64.6729,43.9437,66.016,42.6006,67.6729,42.6006 Z M36,36 L36,40.2422 L67.7578,72 L72,72 L72,67.7578 L40.2422,36 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
</group>
</vector>

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="M64.501,35.0576 C63.7095,35.0576,62.918,35.3613,62.3115,35.9678 L55.0127,43.2666 C53.7998,44.4795,53.7998,46.4306,55.0127,47.6436 L62.3115,54.9424 C63.5244,56.1553,65.4775,56.1553,66.6904,54.9424 L73.9873,47.6436 C75.2002,46.4307,75.2002,44.4796,73.9873,43.2666 L66.6904,35.9678 C66.0839,35.3613,65.2924,35.0576,64.5009,35.0576 Z M67.6729,42.6006 C69.3298,42.6006,70.6729,43.9437,70.6729,45.6006 C70.6729,47.2575,69.3298,48.6006,67.6729,48.6006 C66.016,48.6006,64.6729,47.2575,64.6729,45.6006 C64.6729,43.9437,66.016,42.6006,67.6729,42.6006 Z M48.3438,55.4141 L36,67.7578 L36,72 L40.2422,72 L44.7578,67.4844 L44.7578,67.5 L49,67.5 L49,63.2578 L48.9844,63.2578 L49,63.2422 L49,63.2578 L53.2578,63.2578 L53.2578,60.3281 Z" />
</group>
</vector>

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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/green" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/green" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.kunzisoft.keepass"
android:installLocation="auto"> android:installLocation="auto">
<supports-screens <supports-screens
android:smallScreens="true" android:smallScreens="true"
@@ -10,19 +9,24 @@
android:anyDensity="true" /> android:anyDensity="true" />
<uses-permission <uses-permission
android:name="android.permission.FOREGROUND_SERVICE" /> android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission
android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission
android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission <uses-permission
android:name="android.permission.USE_BIOMETRIC" /> android:name="android.permission.USE_BIOMETRIC" />
<uses-permission <uses-permission
android:name="android.permission.VIBRATE"/> android:name="android.permission.VIBRATE"/>
<!-- Write permission until Android 10 -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
<!-- Open apps from links --> <!-- Open apps from links -->
<uses-permission <uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES" android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" /> tools:ignore="QueryAllPackagesPermission" />
<queries>
<intent>
<action android:name="android.intent.action.CREATE_DOCUMENT" />
<data android:mimeType="application/octet-stream" />
</intent>
</queries>
<application <application
android:label="@string/app_name" android:label="@string/app_name"
@@ -30,20 +34,20 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:name="com.kunzisoft.keepass.app.App" android:name="com.kunzisoft.keepass.app.App"
android:allowBackup="true" android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/old_backup_rules"
android:dataExtractionRules="@xml/backup_rules"
android:backupAgent="com.kunzisoft.keepass.backup.SettingsBackupAgent" android:backupAgent="com.kunzisoft.keepass.backup.SettingsBackupAgent"
android:largeHeap="true" android:largeHeap="true"
android:resizeableActivity="true" android:resizeableActivity="true"
android:theme="@style/KeepassDXStyle.Night" android:theme="@style/KeepassDXStyle.Night"
tools:targetApi="n"> tools:targetApi="s">
<meta-data <meta-data
android:name="com.google.android.backup.api_key" android:name="com.google.android.backup.api_key"
android:value="${googleAndroidBackupAPIKey}" /> android:value="${googleAndroidBackupAPIKey}" />
<activity <activity
android:name="com.kunzisoft.keepass.activities.FileDatabaseSelectActivity" android:name="com.kunzisoft.keepass.activities.FileDatabaseSelectActivity"
android:theme="@style/KeepassDXStyle.SplashScreen"
android:label="@string/app_name"
android:launchMode="singleTop" android:launchMode="singleTop"
android:exported="true"
android:configChanges="keyboardHidden" android:configChanges="keyboardHidden"
android:windowSoftInputMode="stateHidden|stateAlwaysHidden" > android:windowSoftInputMode="stateHidden|stateAlwaysHidden" >
<intent-filter> <intent-filter>
@@ -52,7 +56,8 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name="com.kunzisoft.keepass.activities.PasswordActivity" android:name="com.kunzisoft.keepass.activities.MainCredentialActivity"
android:exported="true"
android:configChanges="keyboardHidden" android:configChanges="keyboardHidden"
android:windowSoftInputMode="adjustResize|stateUnchanged"> android:windowSoftInputMode="adjustResize|stateUnchanged">
<intent-filter> <intent-filter>
@@ -111,6 +116,7 @@
<!-- Main Activity --> <!-- Main Activity -->
<activity <activity
android:name="com.kunzisoft.keepass.activities.GroupActivity" android:name="com.kunzisoft.keepass.activities.GroupActivity"
android:exported="false"
android:configChanges="keyboardHidden" android:configChanges="keyboardHidden"
android:windowSoftInputMode="adjustPan"> android:windowSoftInputMode="adjustPan">
<meta-data <meta-data
@@ -131,12 +137,15 @@
<activity <activity
android:name="com.kunzisoft.keepass.activities.IconPickerActivity" android:name="com.kunzisoft.keepass.activities.IconPickerActivity"
android:configChanges="keyboardHidden" /> android:configChanges="keyboardHidden" />
<activity
android:name="com.kunzisoft.keepass.activities.KeyGeneratorActivity"
android:configChanges="keyboardHidden" />
<activity <activity
android:name="com.kunzisoft.keepass.activities.ImageViewerActivity" android:name="com.kunzisoft.keepass.activities.ImageViewerActivity"
android:configChanges="keyboardHidden" /> android:configChanges="keyboardHidden" />
<activity <activity
android:name="com.kunzisoft.keepass.activities.EntryEditActivity" android:name="com.kunzisoft.keepass.activities.EntryEditActivity"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustPan" />
<!-- About and Settings --> <!-- About and Settings -->
<activity <activity
android:name="com.kunzisoft.keepass.activities.AboutActivity" android:name="com.kunzisoft.keepass.activities.AboutActivity"
@@ -147,14 +156,22 @@
<activity <activity
android:name="com.kunzisoft.keepass.activities.AutofillLauncherActivity" android:name="com.kunzisoft.keepass.activities.AutofillLauncherActivity"
android:theme="@style/Theme.Transparent" android:theme="@style/Theme.Transparent"
android:configChanges="keyboardHidden" /> android:configChanges="keyboardHidden"
android:excludeFromRecents="true"/>
<activity <activity
android:name="com.kunzisoft.keepass.settings.SettingsAdvancedUnlockActivity" /> android:name="com.kunzisoft.keepass.settings.AdvancedUnlockSettingsActivity" />
<activity <activity
android:name="com.kunzisoft.keepass.settings.AutofillSettingsActivity" /> android:name="com.kunzisoft.keepass.settings.AutofillSettingsActivity" />
<activity
android:name="com.kunzisoft.keepass.settings.AppearanceSettingsActivity" />
<activity
android:name="com.kunzisoft.keepass.hardware.HardwareKeyActivity"
android:theme="@style/Theme.Transparent" />
<activity <activity
android:name="com.kunzisoft.keepass.activities.EntrySelectionLauncherActivity" android:name="com.kunzisoft.keepass.activities.EntrySelectionLauncherActivity"
android:theme="@style/Theme.Transparent"> android:theme="@style/Theme.Transparent"
android:launchMode="singleInstance"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
@@ -164,16 +181,15 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="otpauth" android:host="totp" /> <data android:scheme="otpauth"/>
<data android:scheme="otpauth" android:host="hotp" /> <data android:host="totp"/>
<data android:host="hotp"/>
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name="com.kunzisoft.keepass.activities.MagikeyboardLauncherActivity"
android:theme="@style/Theme.Transparent" />
<activity <activity
android:name="com.kunzisoft.keepass.settings.MagikeyboardSettingsActivity" android:name="com.kunzisoft.keepass.settings.MagikeyboardSettingsActivity"
android:label="@string/keyboard_setting_label"> android:label="@string/keyboard_setting_label"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
</intent-filter> </intent-filter>
@@ -199,6 +215,7 @@
<service <service
android:name="com.kunzisoft.keepass.autofill.KeeAutofillService" android:name="com.kunzisoft.keepass.autofill.KeeAutofillService"
android:label="@string/autofill_service_name" android:label="@string/autofill_service_name"
android:exported="true"
android:permission="android.permission.BIND_AUTOFILL_SERVICE"> android:permission="android.permission.BIND_AUTOFILL_SERVICE">
<meta-data <meta-data
android:name="android.autofill" android:name="android.autofill"
@@ -210,6 +227,7 @@
<service <service
android:name="com.kunzisoft.keepass.magikeyboard.MagikeyboardService" android:name="com.kunzisoft.keepass.magikeyboard.MagikeyboardService"
android:label="@string/keyboard_label" android:label="@string/keyboard_label"
android:exported="true"
android:permission="android.permission.BIND_INPUT_METHOD" > android:permission="android.permission.BIND_INPUT_METHOD" >
<meta-data android:name="android.view.im" <meta-data android:name="android.view.im"
android:resource="@xml/keyboard_method"/> android:resource="@xml/keyboard_method"/>
@@ -221,6 +239,14 @@
android:name="com.kunzisoft.keepass.services.KeyboardEntryNotificationService" android:name="com.kunzisoft.keepass.services.KeyboardEntryNotificationService"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<receiver
android:name="com.kunzisoft.keepass.receivers.DexModeReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.app.action.ENTER_KNOX_DESKTOP_MODE" />
<action android:name="android.app.action.EXIT_KNOX_DESKTOP_MODE" />
</intent-filter>
</receiver>
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" /> <meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
</application> </application>

View File

@@ -172,16 +172,16 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
private val onScaleGestureListener: ScaleGestureDetector.OnScaleGestureListener = private val onScaleGestureListener: ScaleGestureDetector.OnScaleGestureListener =
object : ScaleGestureDetector.OnScaleGestureListener { object : ScaleGestureDetector.OnScaleGestureListener {
override fun onScale(detector: ScaleGestureDetector?): Boolean { override fun onScale(detector: ScaleGestureDetector): Boolean {
if (isDragging() || isBitmapTranslateAnimationRunning || isBitmapScaleAnimationRunninng) { if (isDragging() || isBitmapTranslateAnimationRunning || isBitmapScaleAnimationRunninng) {
return false return false
} }
val scaleFactor = detector?.scaleFactor ?: 1.0f val scaleFactor = detector.scaleFactor
val focalX = detector?.focusX ?: bitmapBounds.centerX() val focalX = detector.focusX
val focalY = detector?.focusY ?: bitmapBounds.centerY() val focalY = detector.focusY
if (detector?.scaleFactor == 1.0f) { if (detector.scaleFactor == 1.0f) {
// scale is not changing // scale is not changing
return true return true
} }
@@ -191,22 +191,23 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
return true return true
} }
override fun onScaleBegin(p0: ScaleGestureDetector?): Boolean = true override fun onScaleBegin(p0: ScaleGestureDetector): Boolean = true
override fun onScaleEnd(p0: ScaleGestureDetector) {}
override fun onScaleEnd(p0: ScaleGestureDetector?) {}
} }
private val onGestureListener: GestureDetector.OnGestureListener = private val onGestureListener: GestureDetector.OnGestureListener =
object : GestureDetector.SimpleOnGestureListener() { object : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent?): Boolean = true override fun onDown(e: MotionEvent): Boolean = true
override fun onScroll( override fun onScroll(
e1: MotionEvent?, e1: MotionEvent,
e2: MotionEvent?, e2: MotionEvent,
distanceX: Float, distanceX: Float,
distanceY: Float distanceY: Float
): Boolean { ): Boolean {
if (e2?.pointerCount != 1) { if (e2.pointerCount != 1) {
return true return true
} }
@@ -219,13 +220,11 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
} }
override fun onFling( override fun onFling(
e1: MotionEvent?, e1: MotionEvent,
e2: MotionEvent?, e2: MotionEvent,
velocityX: Float, velocityX: Float,
velocityY: Float velocityY: Float
): Boolean { ): Boolean {
e1 ?: return true
if (scale > minScale) { if (scale > minScale) {
processFlingBitmap(velocityX, velocityY) processFlingBitmap(velocityX, velocityY)
} else { } else {
@@ -234,9 +233,7 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
return true return true
} }
override fun onDoubleTap(e: MotionEvent?): Boolean { override fun onDoubleTap(e: MotionEvent): Boolean {
e ?: return false
if (isBitmapScaleAnimationRunninng) { if (isBitmapScaleAnimationRunninng) {
return true return true
} }
@@ -376,21 +373,21 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
onViewTranslateListener?.onViewTranslate(imageView, amount) onViewTranslateListener?.onViewTranslate(imageView, amount)
} }
.setListener(object : Animator.AnimatorListener { .setListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
onViewTranslateListener?.onDismiss(imageView) onViewTranslateListener?.onDismiss(imageView)
cleanup() cleanup()
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
@@ -409,21 +406,21 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
onViewTranslateListener?.onViewTranslate(imageView, amount) onViewTranslateListener?.onViewTranslate(imageView, amount)
} }
addListener(object : Animator.AnimatorListener { addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
// no op // no op
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
onViewTranslateListener?.onDismiss(imageView) onViewTranslateListener?.onDismiss(imageView)
cleanup() cleanup()
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
@@ -480,20 +477,20 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
setTransform() setTransform()
} }
addListener(object : Animator.AnimatorListener { addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
isBitmapTranslateAnimationRunning = true isBitmapTranslateAnimationRunning = true
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
isBitmapTranslateAnimationRunning = false isBitmapTranslateAnimationRunning = false
constrainBitmapBounds() constrainBitmapBounds()
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
isBitmapTranslateAnimationRunning = false isBitmapTranslateAnimationRunning = false
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
@@ -531,11 +528,11 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
setTransform() setTransform()
} }
addListener(object : Animator.AnimatorListener { addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
isBitmapScaleAnimationRunninng = true isBitmapScaleAnimationRunninng = true
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
isBitmapScaleAnimationRunninng = false isBitmapScaleAnimationRunninng = false
if (endScale == minScale) { if (endScale == minScale) {
zoomToTargetScale(minScale, focalX, focalY) zoomToTargetScale(minScale, focalX, focalY)
@@ -543,11 +540,11 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
} }
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
isBitmapScaleAnimationRunninng = false isBitmapScaleAnimationRunninng = false
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
@@ -585,11 +582,11 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
setTransform() setTransform()
} }
addListener(object : Animator.AnimatorListener { addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
isBitmapScaleAnimationRunninng = true isBitmapScaleAnimationRunninng = true
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
isBitmapScaleAnimationRunninng = false isBitmapScaleAnimationRunninng = false
if (endScale == minScale) { if (endScale == minScale) {
scale = minScale scale = minScale
@@ -599,11 +596,11 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
} }
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
isBitmapScaleAnimationRunninng = false isBitmapScaleAnimationRunninng = false
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
@@ -669,19 +666,19 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
onViewTranslateListener?.onViewTranslate(this, amount) onViewTranslateListener?.onViewTranslate(this, amount)
} }
.setListener(object : Animator.AnimatorListener { .setListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
// no op // no op
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
onViewTranslateListener?.onRestore(imageView) onViewTranslateListener?.onRestore(imageView)
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
// no op // no op
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
@@ -696,19 +693,19 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
onViewTranslateListener?.onViewTranslate(imageView, amount) onViewTranslateListener?.onViewTranslate(imageView, amount)
} }
addListener(object : Animator.AnimatorListener { addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
// no op // no op
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
onViewTranslateListener?.onRestore(imageView) onViewTranslateListener?.onRestore(imageView)
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
// no op // no op
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
@@ -737,27 +734,27 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
onViewTranslateListener?.onViewTranslate(this, amount) onViewTranslateListener?.onViewTranslate(this, amount)
} }
.setListener(object : Animator.AnimatorListener { .setListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
isViewTranslateAnimationRunning = true isViewTranslateAnimationRunning = true
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
onViewTranslateListener?.onDismiss(imageView) onViewTranslateListener?.onDismiss(imageView)
cleanup() cleanup()
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })
} }
} else { } else {
ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, imageView.translationY.toFloat()).apply { ObjectAnimator.ofFloat(imageView, View.TRANSLATION_Y, imageView.translationY).apply {
duration = dismissAnimationDuration duration = dismissAnimationDuration
interpolator = AccelerateDecelerateInterpolator() interpolator = AccelerateDecelerateInterpolator()
addUpdateListener { addUpdateListener {
@@ -766,21 +763,21 @@ class Loupe(imageView: ImageView, container: ViewGroup) : View.OnTouchListener,
onViewTranslateListener?.onViewTranslate(imageView, amount) onViewTranslateListener?.onViewTranslate(imageView, amount)
} }
addListener(object : Animator.AnimatorListener { addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(p0: Animator?) { override fun onAnimationStart(p0: Animator) {
isViewTranslateAnimationRunning = true isViewTranslateAnimationRunning = true
} }
override fun onAnimationEnd(p0: Animator?) { override fun onAnimationEnd(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
onViewTranslateListener?.onDismiss(imageView) onViewTranslateListener?.onDismiss(imageView)
cleanup() cleanup()
} }
override fun onAnimationCancel(p0: Animator?) { override fun onAnimationCancel(p0: Animator) {
isViewTranslateAnimationRunning = false isViewTranslateAnimationRunning = false
} }
override fun onAnimationRepeat(p0: Animator?) { override fun onAnimationRepeat(p0: Animator) {
// no op // no op
} }
}) })

View File

@@ -30,6 +30,8 @@ import androidx.core.text.HtmlCompat
import com.kunzisoft.keepass.BuildConfig import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.StylishActivity import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.getPackageInfoCompat
import org.joda.time.DateTime import org.joda.time.DateTime
class AboutActivity : StylishActivity() { class AboutActivity : StylishActivity() {
@@ -45,10 +47,16 @@ class AboutActivity : StylishActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
val appName = if (this.isContributingUser())
getString(R.string.app_name) + " " + getString(R.string.app_name_part3)
else
getString(R.string.app_name)
findViewById<TextView>(R.id.activity_about_app_name).text = appName
var version: String var version: String
var build: String var build: String
try { try {
version = packageManager.getPackageInfo(packageName, 0).versionName version = packageManager.getPackageInfoCompat(packageName).versionName
build = BuildConfig.BUILD_VERSION build = BuildConfig.BUILD_VERSION
} catch (e: NameNotFoundException) { } catch (e: NameNotFoundException) {
Log.w(javaClass.simpleName, "Unable to get the app or the build version", e) Log.w(javaClass.simpleName, "Unable to get the app or the build version", e)
@@ -70,6 +78,12 @@ class AboutActivity : StylishActivity() {
HtmlCompat.FROM_HTML_MODE_LEGACY) HtmlCompat.FROM_HTML_MODE_LEGACY)
} }
findViewById<TextView>(R.id.activity_about_privacy_text).apply {
movementMethod = LinkMovementMethod.getInstance()
text = HtmlCompat.fromHtml(getString(R.string.html_about_privacy),
HtmlCompat.FROM_HTML_MODE_LEGACY)
}
findViewById<TextView>(R.id.activity_about_contribution_text).apply { findViewById<TextView>(R.id.activity_about_contribution_text).apply {
movementMethod = LinkMovementMethod.getInstance() movementMethod = LinkMovementMethod.getInstance()
text = HtmlCompat.fromHtml(getString(R.string.html_about_contribution), text = HtmlCompat.fromHtml(getString(R.string.html_about_contribution),

View File

@@ -23,28 +23,38 @@ import android.app.Activity
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentSender
import android.os.Build import android.os.Build
import android.view.inputmethod.InlineSuggestionsRequest import android.os.Bundle
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.autofill.AutofillHelper.EXTRA_INLINE_SUGGESTIONS_REQUEST import com.kunzisoft.keepass.autofill.CompatInlineSuggestionsRequest
import com.kunzisoft.keepass.autofill.KeeAutofillService import com.kunzisoft.keepass.autofill.KeeAutofillService
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.search.SearchHelper import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.model.RegisterInfo import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.LOCK_ACTION 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) @RequiresApi(api = Build.VERSION_CODES.O)
class AutofillLauncherActivity : DatabaseModeActivity() { class AutofillLauncherActivity : DatabaseModeActivity() {
private var mAutofillActivityResultLauncher: ActivityResultLauncher<Intent>? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
AutofillHelper.buildActivityResultLauncher(this, true)
else null
override fun applyCustomStyle(): Boolean { override fun applyCustomStyle(): Boolean {
return false return false
} }
@@ -53,30 +63,50 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
return true return true
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
// Retrieve selection mode // Retrieve selection mode
EntrySelectionHelper.retrieveSpecialModeFromIntent(intent).let { specialMode -> EntrySelectionHelper.retrieveSpecialModeFromIntent(intent).let { specialMode ->
when (specialMode) { when (specialMode) {
SpecialMode.SELECTION -> { SpecialMode.SELECTION -> {
// Build search param intent.getBundleExtra(KEY_SELECTION_BUNDLE)?.let { bundle ->
val searchInfo = SearchInfo().apply { // To pass extra inline request
applicationId = intent.getStringExtra(KEY_SEARCH_APPLICATION_ID) var compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest? = null
webDomain = intent.getStringExtra(KEY_SEARCH_DOMAIN) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
webScheme = intent.getStringExtra(KEY_SEARCH_SCHEME) compatInlineSuggestionsRequest = bundle.getParcelableCompat(KEY_INLINE_SUGGESTION)
manualSelection = intent.getBooleanExtra(KEY_MANUAL_SELECTION, false) }
} // Build search param
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain -> bundle.getParcelableCompat<SearchInfo>(KEY_SEARCH_INFO)?.let { searchInfo ->
searchInfo.webDomain = concreteWebDomain WebDomain.getConcreteWebDomain(
launchSelection(database, searchInfo) this,
searchInfo.webDomain
) { concreteWebDomain ->
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
val assistStructure = AutofillHelper
.retrieveAutofillComponent(intent)
?.assistStructure
val newAutofillComponent = if (assistStructure != null) {
AutofillComponent(
assistStructure,
compatInlineSuggestionsRequest
)
} else {
null
}
searchInfo.webDomain = concreteWebDomain
launchSelection(database, newAutofillComponent, searchInfo)
}
}
} }
// Remove bundle
intent.removeExtra(KEY_SELECTION_BUNDLE)
} }
SpecialMode.REGISTRATION -> { SpecialMode.REGISTRATION -> {
// To register info // To register info
val registerInfo = intent.getParcelableExtra<RegisterInfo>(KEY_REGISTER_INFO) val registerInfo = intent.getParcelableExtraCompat<RegisterInfo>(KEY_REGISTER_INFO)
val searchInfo = SearchInfo(registerInfo?.searchInfo) val searchInfo = SearchInfo(registerInfo?.searchInfo)
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain -> WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
searchInfo.webDomain = concreteWebDomain searchInfo.webDomain = concreteWebDomain
launchRegistration(database, searchInfo, registerInfo) launchRegistration(database, searchInfo, registerInfo)
} }
@@ -90,11 +120,9 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
} }
} }
private fun launchSelection(database: Database?, private fun launchSelection(database: ContextualDatabase?,
autofillComponent: AutofillComponent?,
searchInfo: SearchInfo) { searchInfo: SearchInfo) {
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
val autofillComponent = AutofillHelper.retrieveAutofillComponent(intent)
if (autofillComponent == null) { if (autofillComponent == null) {
setResult(Activity.RESULT_CANCELED) setResult(Activity.RESULT_CANCELED)
finish() finish()
@@ -119,6 +147,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
// Show the database UI to select the entry // Show the database UI to select the entry
GroupActivity.launchForAutofillResult(this, GroupActivity.launchForAutofillResult(this,
openedDatabase, openedDatabase,
mAutofillActivityResultLauncher,
autofillComponent, autofillComponent,
searchInfo, searchInfo,
false) false)
@@ -126,6 +155,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
{ {
// If database not open // If database not open
FileDatabaseSelectActivity.launchForAutofillResult(this, FileDatabaseSelectActivity.launchForAutofillResult(this,
mAutofillActivityResultLauncher,
autofillComponent, autofillComponent,
searchInfo) searchInfo)
} }
@@ -133,7 +163,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
} }
} }
private fun launchRegistration(database: Database?, private fun launchRegistration(database: ContextualDatabase?,
searchInfo: SearchInfo, searchInfo: SearchInfo,
registerInfo: RegisterInfo?) { registerInfo: RegisterInfo?) {
if (!KeeAutofillService.autofillAllowedFor(searchInfo.applicationId, if (!KeeAutofillService.autofillAllowedFor(searchInfo.applicationId,
@@ -186,55 +216,63 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
Toast.makeText(this.applicationContext, R.string.autofill_read_only_save, Toast.LENGTH_LONG).show() Toast.makeText(this.applicationContext, R.string.autofill_read_only_save, Toast.LENGTH_LONG).show()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data)
if (PreferencesUtil.isAutofillCloseDatabaseEnable(this)) {
// Close the database
sendBroadcast(Intent(LOCK_ACTION))
}
super.onActivityResult(requestCode, resultCode, data)
}
companion object { companion object {
private const val KEY_MANUAL_SELECTION = "KEY_MANUAL_SELECTION" private val TAG = AutofillLauncherActivity::class.java.name
private const val KEY_SEARCH_APPLICATION_ID = "KEY_SEARCH_APPLICATION_ID"
private const val KEY_SEARCH_DOMAIN = "KEY_SEARCH_DOMAIN" private const val KEY_SELECTION_BUNDLE = "KEY_SELECTION_BUNDLE"
private const val KEY_SEARCH_SCHEME = "KEY_SEARCH_SCHEME" private const val KEY_SEARCH_INFO = "KEY_SEARCH_INFO"
private const val KEY_INLINE_SUGGESTION = "KEY_INLINE_SUGGESTION"
private const val KEY_REGISTER_INFO = "KEY_REGISTER_INFO" private const val KEY_REGISTER_INFO = "KEY_REGISTER_INFO"
fun getPendingIntentForSelection(context: Context, fun getPendingIntentForSelection(context: Context,
searchInfo: SearchInfo? = null, searchInfo: SearchInfo? = null,
inlineSuggestionsRequest: InlineSuggestionsRequest? = null): PendingIntent { compatInlineSuggestionsRequest: CompatInlineSuggestionsRequest? = null): PendingIntent? {
return PendingIntent.getActivity(context, 0, try {
// Doesn't work with Parcelable (don't know why?) 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 { Intent(context, AutofillLauncherActivity::class.java).apply {
searchInfo?.let { putExtra(KEY_SELECTION_BUNDLE, Bundle().apply {
putExtra(KEY_SEARCH_APPLICATION_ID, it.applicationId) putParcelable(KEY_SEARCH_INFO, searchInfo)
putExtra(KEY_SEARCH_DOMAIN, it.webDomain) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
putExtra(KEY_SEARCH_SCHEME, it.webScheme) putParcelable(KEY_INLINE_SUGGESTION, compatInlineSuggestionsRequest)
putExtra(KEY_MANUAL_SELECTION, it.manualSelection)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
inlineSuggestionsRequest?.let {
putExtra(EXTRA_INLINE_SUGGESTIONS_REQUEST, it)
} }
} })
}, },
PendingIntent.FLAG_CANCEL_CURRENT) 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, fun getPendingIntentForRegistration(context: Context,
registerInfo: RegisterInfo): PendingIntent { registerInfo: RegisterInfo): PendingIntent? {
return PendingIntent.getActivity(context, 0, try {
return PendingIntent.getActivity(
context, 0,
Intent(context, AutofillLauncherActivity::class.java).apply { Intent(context, AutofillLauncherActivity::class.java).apply {
EntrySelectionHelper.addSpecialModeInIntent(this, SpecialMode.REGISTRATION) EntrySelectionHelper.addSpecialModeInIntent(this, SpecialMode.REGISTRATION)
putExtra(KEY_REGISTER_INFO, registerInfo) putExtra(KEY_REGISTER_INFO, registerInfo)
}, },
PendingIntent.FLAG_CANCEL_CURRENT) 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, fun launchForRegistration(context: Context,

View File

@@ -23,6 +23,7 @@ import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@@ -30,19 +31,34 @@ import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.ProgressBar import android.widget.ProgressBar
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout 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
import com.google.android.material.appbar.CollapsingToolbarLayout import com.google.android.material.appbar.CollapsingToolbarLayout
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.tabs.TabLayout
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.fragments.EntryFragment import com.kunzisoft.keepass.activities.fragments.EntryFragment
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.adapters.TagsAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.icon.IconImage import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.education.EntryActivityEducation import com.kunzisoft.keepass.education.EntryActivityEducation
@@ -57,38 +73,59 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.TimeoutHelper import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.* 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.hideByFading
import com.kunzisoft.keepass.view.setTransparentNavigationBar
import com.kunzisoft.keepass.view.showActionErrorIfNeeded import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.viewmodels.EntryViewModel import com.kunzisoft.keepass.viewmodels.EntryViewModel
import java.util.* import java.util.UUID
import kotlin.collections.HashMap
class EntryActivity : DatabaseLockActivity() { class EntryActivity : DatabaseLockActivity() {
private var footer: ViewGroup? = null
private var coordinatorLayout: CoordinatorLayout? = null private var coordinatorLayout: CoordinatorLayout? = null
private var collapsingToolbarLayout: CollapsingToolbarLayout? = null private var collapsingToolbarLayout: CollapsingToolbarLayout? = null
private var appBarLayout: AppBarLayout? = null
private var titleIconView: ImageView? = null private var titleIconView: ImageView? = null
private var historyView: View? = null private var historyView: View? = null
private var entryProgress: ProgressBar? = null private var tagsListView: RecyclerView? = null
private var entryContentTab: TabLayout? = null
private var tagsAdapter: TagsAdapter? = null
private var entryProgress: LinearProgressIndicator? = null
private var lockView: View? = null private var lockView: View? = null
private var toolbar: Toolbar? = null private var toolbar: Toolbar? = null
private var loadingView: ProgressBar? = null private var loadingView: ProgressBar? = null
private val mEntryViewModel: EntryViewModel by viewModels() private val mEntryViewModel: EntryViewModel by viewModels()
private val mEntryActivityEducation = EntryActivityEducation(this)
private var mMainEntryId: NodeId<UUID>? = null private var mMainEntryId: NodeId<UUID>? = null
private var mHistoryPosition: Int = -1 private var mHistoryPosition: Int = -1
private var mEntryIsHistory: Boolean = false private var mEntryIsHistory: Boolean = false
private var mUrl: String? = null
private var mEntryLoaded = false private var mEntryLoaded = false
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
private var mAttachmentsToDownload: HashMap<Int, Attachment> = HashMap()
private var mExternalFileHelper: ExternalFileHelper? = null private var mExternalFileHelper: ExternalFileHelper? = null
private var mAttachmentSelected: Attachment? = null
private var mEntryActivityResultLauncher = EntryEditActivity.registerForEntryResult(this) {
// Reload the current id from database
mEntryViewModel.loadDatabase(mDatabase)
}
private var mIcon: IconImage? = null private var mIcon: IconImage? = null
private var mIconColor: Int = 0 private var mColorSecondary: Int = 0
private var mColorSurface: Int = 0
private var mColorOnSurface: Int = 0
private var mColorBackground: Int = 0
private var mBackgroundColor: Int? = null
private var mForegroundColor: Int? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -101,26 +138,67 @@ class EntryActivity : DatabaseLockActivity() {
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
// Get views // Get views
footer = findViewById(R.id.activity_entry_footer)
coordinatorLayout = findViewById(R.id.toolbar_coordinator) coordinatorLayout = findViewById(R.id.toolbar_coordinator)
collapsingToolbarLayout = findViewById(R.id.toolbar_layout) collapsingToolbarLayout = findViewById(R.id.toolbar_layout)
appBarLayout = findViewById(R.id.app_bar)
titleIconView = findViewById(R.id.entry_icon) titleIconView = findViewById(R.id.entry_icon)
historyView = findViewById(R.id.history_container) historyView = findViewById(R.id.history_container)
tagsListView = findViewById(R.id.entry_tags_list_view)
entryContentTab = findViewById(R.id.entry_content_tab)
entryProgress = findViewById(R.id.entry_progress) entryProgress = findViewById(R.id.entry_progress)
lockView = findViewById(R.id.lock_button) lockView = findViewById(R.id.lock_button)
loadingView = findViewById(R.id.loading) 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 // Empty title
collapsingToolbarLayout?.title = " " collapsingToolbarLayout?.title = " "
toolbar?.title = " " toolbar?.title = " "
// Retrieve the textColor to tint the icon // Retrieve the textColor to tint the toolbar
val taIconColor = theme.obtainStyledAttributes(intArrayOf(R.attr.colorAccent)) val taColorSecondary = theme.obtainStyledAttributes(intArrayOf(R.attr.colorSecondary))
mIconColor = taIconColor.getColor(0, Color.BLACK) val taColorSurface = theme.obtainStyledAttributes(intArrayOf(R.attr.colorSurface))
taIconColor.recycle() val taColorOnSurface = theme.obtainStyledAttributes(intArrayOf(R.attr.colorOnSurface))
val taColorBackground = theme.obtainStyledAttributes(intArrayOf(android.R.attr.windowBackground))
mColorSecondary = taColorSecondary.getColor(0, Color.BLACK)
mColorSurface = taColorSurface.getColor(0, Color.BLACK)
mColorOnSurface = taColorOnSurface.getColor(0, Color.BLACK)
mColorBackground = taColorBackground.getColor(0, Color.BLACK)
taColorSecondary.recycle()
taColorSurface.recycle()
taColorOnSurface.recycle()
taColorBackground.recycle()
// Init Tags adapter
tagsAdapter = TagsAdapter(this)
tagsListView?.apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = tagsAdapter
}
// Init content tab
entryContentTab?.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
mEntryViewModel.selectSection(EntryViewModel.EntrySection.
getEntrySectionByPosition(tab?.position ?: 0)
)
}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
override fun onTabReselected(tab: TabLayout.Tab?) {}
})
// Get Entry from UUID // Get Entry from UUID
try { try {
intent.getParcelableExtra<NodeId<UUID>?>(KEY_ENTRY)?.let { mainEntryId -> intent.getParcelableExtraCompat<NodeId<UUID>>(KEY_ENTRY)?.let { mainEntryId ->
intent.removeExtra(KEY_ENTRY) intent.removeExtra(KEY_ENTRY)
val historyPosition = intent.getIntExtra(KEY_ENTRY_HISTORY_POSITION, -1) val historyPosition = intent.getIntExtra(KEY_ENTRY_HISTORY_POSITION, -1)
intent.removeExtra(KEY_ENTRY_HISTORY_POSITION) intent.removeExtra(KEY_ENTRY_HISTORY_POSITION)
@@ -133,6 +211,15 @@ class EntryActivity : DatabaseLockActivity() {
// Init SAF manager // Init SAF manager
mExternalFileHelper = ExternalFileHelper(this) mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildCreateDocument { createdFileUri ->
mAttachmentSelected?.let { attachment ->
if (createdFileUri != null) {
mAttachmentFileBinderManager
?.startDownloadAttachment(createdFileUri, attachment)
}
mAttachmentSelected = null
}
}
// Init attachment service binder manager // Init attachment service binder manager
mAttachmentFileBinderManager = AttachmentFileBinderManager(this) mAttachmentFileBinderManager = AttachmentFileBinderManager(this)
@@ -140,6 +227,10 @@ class EntryActivity : DatabaseLockActivity() {
lockAndExit() lockAndExit()
} }
mEntryViewModel.sectionSelected.observe(this) { entrySection ->
entryContentTab?.getTabAt(entrySection.position)?.select()
}
mEntryViewModel.entryInfoHistory.observe(this) { entryInfoHistory -> mEntryViewModel.entryInfoHistory.observe(this) { entryInfoHistory ->
if (entryInfoHistory != null) { if (entryInfoHistory != null) {
this.mMainEntryId = entryInfoHistory.mainEntryId this.mMainEntryId = entryInfoHistory.mainEntryId
@@ -151,18 +242,16 @@ class EntryActivity : DatabaseLockActivity() {
this.mEntryIsHistory = entryIsHistory this.mEntryIsHistory = entryIsHistory
// Assign history dedicated view // Assign history dedicated view
historyView?.visibility = if (entryIsHistory) View.VISIBLE else View.GONE historyView?.visibility = if (entryIsHistory) View.VISIBLE else View.GONE
// TODO History badge
/*
if (entryIsHistory) { if (entryIsHistory) {
val taColorAccent = theme.obtainStyledAttributes(intArrayOf(R.attr.colorAccent)) }*/
collapsingToolbarLayout?.contentScrim =
ColorDrawable(taColorAccent.getColor(0, Color.BLACK))
taColorAccent.recycle()
}
val entryInfo = entryInfoHistory.entryInfo val entryInfo = entryInfoHistory.entryInfo
// Manage entry copy to start notification if allowed (at the first start) // Manage entry copy to start notification if allowed (at the first start)
if (savedInstanceState == null) { if (savedInstanceState == null) {
// Manage entry to launch copying notification if allowed // Manage entry to launch copying notification if allowed
ClipboardEntryNotificationService.launchNotificationIfAllowed(this, entryInfo) ClipboardEntryNotificationService.checkAndLaunchNotification(this, entryInfo)
// Manage entry to populate Magikeyboard and launch keyboard notification if allowed // Manage entry to populate Magikeyboard and launch keyboard notification if allowed
if (PreferencesUtil.isKeyboardEntrySelectionEnable(this)) { if (PreferencesUtil.isKeyboardEntrySelectionEnable(this)) {
MagikeyboardService.addEntryAndLaunchNotificationIfAllowed(this, entryInfo) MagikeyboardService.addEntryAndLaunchNotificationIfAllowed(this, entryInfo)
@@ -170,15 +259,19 @@ class EntryActivity : DatabaseLockActivity() {
} }
// Assign title icon // Assign title icon
mIcon = entryInfo.icon mIcon = entryInfo.icon
titleIconView?.let { iconView ->
mIconDrawableFactory?.assignDatabaseIcon(iconView, entryInfo.icon, mIconColor)
}
// Assign title text // Assign title text
val entryTitle = val entryTitle =
if (entryInfo.title.isNotEmpty()) entryInfo.title else entryInfo.id.toString() if (entryInfo.title.isNotEmpty()) entryInfo.title else UuidUtil.toHexString(entryInfo.id)
collapsingToolbarLayout?.title = entryTitle collapsingToolbarLayout?.title = entryTitle
toolbar?.title = entryTitle toolbar?.title = entryTitle
mUrl = entryInfo.url // Assign tags
val tags = entryInfo.tags
tagsListView?.visibility = if (tags.isEmpty()) View.GONE else View.VISIBLE
tagsAdapter?.setTags(tags)
// Assign colors
val showEntryColors = PreferencesUtil.showEntryColors(this)
mBackgroundColor = if (showEntryColors) entryInfo.backgroundColor else null
mForegroundColor = if (showEntryColors) entryInfo.foregroundColor else null
loadingView?.hideByFading() loadingView?.hideByFading()
mEntryLoaded = true mEntryLoaded = true
@@ -190,9 +283,9 @@ class EntryActivity : DatabaseLockActivity() {
} }
mEntryViewModel.onOtpElementUpdated.observe(this) { otpElement -> mEntryViewModel.onOtpElementUpdated.observe(this) { otpElement ->
if (otpElement == null) if (otpElement == null) {
entryProgress?.visibility = View.GONE entryProgress?.visibility = View.GONE
when (otpElement?.type) { } else when (otpElement.type) {
// Only add token if HOTP // Only add token if HOTP
OtpType.HOTP -> { OtpType.HOTP -> {
entryProgress?.visibility = View.GONE entryProgress?.visibility = View.GONE
@@ -201,7 +294,7 @@ class EntryActivity : DatabaseLockActivity() {
OtpType.TOTP -> { OtpType.TOTP -> {
entryProgress?.apply { entryProgress?.apply {
max = otpElement.period max = otpElement.period
progress = otpElement.secondsRemaining setProgressCompat(otpElement.secondsRemaining, true)
visibility = View.VISIBLE visibility = View.VISIBLE
} }
} }
@@ -209,9 +302,8 @@ class EntryActivity : DatabaseLockActivity() {
} }
mEntryViewModel.attachmentSelected.observe(this) { attachmentSelected -> mEntryViewModel.attachmentSelected.observe(this) { attachmentSelected ->
mExternalFileHelper?.createDocument(attachmentSelected.name)?.let { requestCode -> mAttachmentSelected = attachmentSelected
mAttachmentsToDownload[requestCode] = attachmentSelected mExternalFileHelper?.createDocument(attachmentSelected.name)
}
} }
mEntryViewModel.historySelected.observe(this) { historySelected -> mEntryViewModel.historySelected.observe(this) { historySelected ->
@@ -220,7 +312,8 @@ class EntryActivity : DatabaseLockActivity() {
this, this,
database, database,
historySelected.nodeId, historySelected.nodeId,
historySelected.historyPosition historySelected.historyPosition,
mEntryActivityResultLauncher
) )
} }
} }
@@ -234,21 +327,14 @@ class EntryActivity : DatabaseLockActivity() {
return coordinatorLayout return coordinatorLayout
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
mEntryViewModel.loadDatabase(database) mEntryViewModel.loadDatabase(database)
// Assign title icon
mIcon?.let { icon ->
titleIconView?.let { iconView ->
mIconDrawableFactory?.assignDatabaseIcon(iconView, icon, mIconColor)
}
}
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {
@@ -282,6 +368,11 @@ class EntryActivity : DatabaseLockActivity() {
} }
} }
} }
// Keep the screen on
if (PreferencesUtil.isKeepScreenOnEnabled(this)) {
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
} }
override fun onPause() { override fun onPause() {
@@ -290,31 +381,33 @@ class EntryActivity : DatabaseLockActivity() {
super.onPause() super.onPause()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { private fun applyToolbarColors() {
super.onActivityResult(requestCode, resultCode, data) collapsingToolbarLayout?.setBackgroundColor(mBackgroundColor ?: mColorSurface)
collapsingToolbarLayout?.contentScrim = ColorDrawable(mBackgroundColor ?: mColorSurface)
when (requestCode) { val backgroundDarker = if (mBackgroundColor != null) {
EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE -> { ColorUtils.blendARGB(mBackgroundColor!!, Color.WHITE, 0.1f)
// Reload the current id from database } else {
mEntryViewModel.loadDatabase(mDatabase) mColorBackground
} }
} titleIconView?.background?.colorFilter = BlendModeColorFilterCompat
.createBlendModeColorFilterCompat(backgroundDarker, BlendModeCompat.SRC_IN)
mExternalFileHelper?.onCreateDocumentResult(requestCode, resultCode, data) { createdFileUri -> mIcon?.let { icon ->
if (createdFileUri != null) { titleIconView?.let { iconView ->
mAttachmentsToDownload[requestCode]?.let { attachmentToDownload -> mDatabase?.iconDrawableFactory?.assignDatabaseIcon(
mAttachmentFileBinderManager iconView,
?.startDownloadAttachment(createdFileUri, attachmentToDownload) icon,
} mForegroundColor ?: mColorSecondary
)
} }
} }
toolbar?.changeControlColor(mForegroundColor ?: mColorOnSurface)
collapsingToolbarLayout?.changeTitleColor(mForegroundColor ?: mColorOnSurface)
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu) super.onCreateOptionsMenu(menu)
if (mEntryLoaded) { if (mEntryLoaded) {
val inflater = menuInflater val inflater = menuInflater
MenuUtil.contributionMenuInflater(inflater, menu)
inflater.inflate(R.menu.entry, menu) inflater.inflate(R.menu.entry, menu)
inflater.inflate(R.menu.database, menu) inflater.inflate(R.menu.database, menu)
@@ -325,55 +418,53 @@ class EntryActivity : DatabaseLockActivity() {
// Show education views // Show education views
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
performedNextEducation( performedNextEducation(menu)
EntryActivityEducation(
this
), menu
)
} }
} }
return true return true
} }
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
if (mUrl?.isEmpty() != false) {
menu?.findItem(R.id.menu_goto_url)?.isVisible = false
}
if (mEntryIsHistory || mDatabaseReadOnly) { if (mEntryIsHistory || mDatabaseReadOnly) {
menu?.findItem(R.id.menu_save_database)?.isVisible = false menu?.findItem(R.id.menu_save_database)?.isVisible = false
menu?.findItem(R.id.menu_merge_database)?.isVisible = false
menu?.findItem(R.id.menu_edit)?.isVisible = false menu?.findItem(R.id.menu_edit)?.isVisible = false
} }
if (!mMergeDataAllowed) {
menu?.findItem(R.id.menu_merge_database)?.isVisible = false
}
if (mSpecialMode != SpecialMode.DEFAULT) { if (mSpecialMode != SpecialMode.DEFAULT) {
menu?.findItem(R.id.menu_merge_database)?.isVisible = false
menu?.findItem(R.id.menu_reload_database)?.isVisible = false menu?.findItem(R.id.menu_reload_database)?.isVisible = false
} }
applyToolbarColors()
return super.onPrepareOptionsMenu(menu) return super.onPrepareOptionsMenu(menu)
} }
private fun performedNextEducation(entryActivityEducation: EntryActivityEducation, private fun performedNextEducation(menu: Menu) {
menu: Menu) {
val entryFragment = supportFragmentManager.findFragmentByTag(ENTRY_FRAGMENT_TAG) val entryFragment = supportFragmentManager.findFragmentByTag(ENTRY_FRAGMENT_TAG)
as? EntryFragment? as? EntryFragment?
val entryFieldCopyView: View? = entryFragment?.firstEntryFieldCopyView() val entryFieldCopyView: View? = entryFragment?.firstEntryFieldCopyView()
val entryCopyEducationPerformed = entryFieldCopyView != null val entryCopyEducationPerformed = entryFieldCopyView != null
&& entryActivityEducation.checkAndPerformedEntryCopyEducation( && mEntryActivityEducation.checkAndPerformedEntryCopyEducation(
entryFieldCopyView, entryFieldCopyView,
{ {
entryFragment.launchEntryCopyEducationAction() entryFragment.launchEntryCopyEducationAction()
}, },
{ {
performedNextEducation(entryActivityEducation, menu) performedNextEducation(menu)
}) })
if (!entryCopyEducationPerformed) { if (!entryCopyEducationPerformed) {
val menuEditView = toolbar?.findViewById<View>(R.id.menu_edit) val menuEditView = toolbar?.findViewById<View>(R.id.menu_edit)
// entryEditEducationPerformed // entryEditEducationPerformed
menuEditView != null && entryActivityEducation.checkAndPerformedEntryEditEducation( menuEditView != null && mEntryActivityEducation.checkAndPerformedEntryEditEducation(
menuEditView, menuEditView,
{ {
onOptionsItemSelected(menu.findItem(R.id.menu_edit)) onOptionsItemSelected(menu.findItem(R.id.menu_edit))
}, },
{ {
performedNextEducation(entryActivityEducation, menu) performedNextEducation(menu)
} }
) )
} }
@@ -381,28 +472,19 @@ class EntryActivity : DatabaseLockActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_contribute -> {
MenuUtil.onContributionItemSelected(this)
return true
}
R.id.menu_edit -> { R.id.menu_edit -> {
mDatabase?.let { database -> mDatabase?.let { database ->
mMainEntryId?.let { entryId -> mMainEntryId?.let { entryId ->
EntryEditActivity.launchToUpdate( EntryEditActivity.launchToUpdate(
this, this,
database, database,
entryId entryId,
mEntryActivityResultLauncher
) )
} }
} }
return true return true
} }
R.id.menu_goto_url -> {
mUrl?.let { url ->
UriUtil.gotoUrl(this, url)
}
return true
}
R.id.menu_restore_entry_history -> { R.id.menu_restore_entry_history -> {
mMainEntryId?.let { mainEntryId -> mMainEntryId?.let { mainEntryId ->
restoreEntryHistory( restoreEntryHistory(
@@ -420,6 +502,9 @@ class EntryActivity : DatabaseLockActivity() {
R.id.menu_save_database -> { R.id.menu_save_database -> {
saveDatabase() saveDatabase()
} }
R.id.menu_merge_database -> {
mergeDatabase()
}
R.id.menu_reload_database -> { R.id.menu_reload_database -> {
reloadDatabase() reloadDatabase()
} }
@@ -432,7 +517,7 @@ class EntryActivity : DatabaseLockActivity() {
// Transit data in previous Activity after an update // Transit data in previous Activity after an update
Intent().apply { Intent().apply {
putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mMainEntryId) putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mMainEntryId)
setResult(EntryEditActivity.ADD_OR_UPDATE_ENTRY_RESULT_CODE, this) setResult(Activity.RESULT_OK, this)
} }
super.finish() super.finish()
} }
@@ -449,16 +534,14 @@ class EntryActivity : DatabaseLockActivity() {
* Open standard Entry activity * Open standard Entry activity
*/ */
fun launch(activity: Activity, fun launch(activity: Activity,
database: Database, database: ContextualDatabase,
entryId: NodeId<UUID>) { entryId: NodeId<UUID>,
activityResultLauncher: ActivityResultLauncher<Intent>) {
if (database.loaded) { if (database.loaded) {
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) { if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
val intent = Intent(activity, EntryActivity::class.java) val intent = Intent(activity, EntryActivity::class.java)
intent.putExtra(KEY_ENTRY, entryId) intent.putExtra(KEY_ENTRY, entryId)
activity.startActivityForResult( activityResultLauncher.launch(intent)
intent,
EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE
)
} }
} }
} }
@@ -467,18 +550,16 @@ class EntryActivity : DatabaseLockActivity() {
* Open history Entry activity * Open history Entry activity
*/ */
fun launch(activity: Activity, fun launch(activity: Activity,
database: Database, database: ContextualDatabase,
entryId: NodeId<UUID>, entryId: NodeId<UUID>,
historyPosition: Int) { historyPosition: Int,
activityResultLauncher: ActivityResultLauncher<Intent>) {
if (database.loaded) { if (database.loaded) {
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) { if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
val intent = Intent(activity, EntryActivity::class.java) val intent = Intent(activity, EntryActivity::class.java)
intent.putExtra(KEY_ENTRY, entryId) intent.putExtra(KEY_ENTRY, entryId)
intent.putExtra(KEY_ENTRY_HISTORY_POSITION, historyPosition) intent.putExtra(KEY_ENTRY_HISTORY_POSITION, historyPosition)
activity.startActivityForResult( activityResultLauncher.launch(intent)
intent,
EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE
)
} }
} }
} }

View File

@@ -19,8 +19,6 @@
package com.kunzisoft.keepass.activities package com.kunzisoft.keepass.activities
import android.app.Activity import android.app.Activity
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
@@ -32,17 +30,31 @@ import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.* import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ProgressBar
import android.widget.Spinner
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.widget.NestedScrollView import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.timepicker.MaterialTimePicker
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.* import com.kunzisoft.keepass.activities.dialogs.ColorPickerDialogFragment
import com.kunzisoft.keepass.activities.dialogs.EntryCustomFieldDialogFragment
import com.kunzisoft.keepass.activities.dialogs.FileTooBigDialogFragment
import com.kunzisoft.keepass.activities.dialogs.FileTooBigDialogFragment.Companion.MAX_WARNING_BINARY_FILE import com.kunzisoft.keepass.activities.dialogs.FileTooBigDialogFragment.Companion.MAX_WARNING_BINARY_FILE
import com.kunzisoft.keepass.activities.dialogs.ReplaceFileDialogFragment
import com.kunzisoft.keepass.activities.dialogs.SetOTPDialogFragment
import com.kunzisoft.keepass.activities.fragments.EntryEditFragment import com.kunzisoft.keepass.activities.fragments.EntryEditFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
@@ -50,12 +62,20 @@ import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.adapters.TemplatesSelectorAdapter import com.kunzisoft.keepass.adapters.TemplatesSelectorAdapter
import com.kunzisoft.keepass.autofill.AutofillComponent import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.database.element.* import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.template.* import com.kunzisoft.keepass.database.element.template.Template
import com.kunzisoft.keepass.education.EntryEditActivityEducation import com.kunzisoft.keepass.education.EntryEditActivityEducation
import com.kunzisoft.keepass.model.* import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.otp.OtpElement import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.services.AttachmentFileNotificationService import com.kunzisoft.keepass.services.AttachmentFileNotificationService
import com.kunzisoft.keepass.services.ClipboardEntryNotificationService import com.kunzisoft.keepass.services.ClipboardEntryNotificationService
@@ -67,23 +87,29 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.TimeoutHelper import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.view.* 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
import com.kunzisoft.keepass.viewmodels.EntryEditViewModel import com.kunzisoft.keepass.viewmodels.EntryEditViewModel
import org.joda.time.DateTime import java.util.UUID
import java.util.*
import kotlin.collections.ArrayList
class EntryEditActivity : DatabaseLockActivity(), class EntryEditActivity : DatabaseLockActivity(),
EntryCustomFieldDialogFragment.EntryCustomFieldListener, EntryCustomFieldDialogFragment.EntryCustomFieldListener,
GeneratePasswordDialogFragment.GeneratePasswordListener,
SetOTPDialogFragment.CreateOtpListener, SetOTPDialogFragment.CreateOtpListener,
DatePickerDialog.OnDateSetListener,
TimePickerDialog.OnTimeSetListener,
FileTooBigDialogFragment.ActionChooseListener, FileTooBigDialogFragment.ActionChooseListener,
ReplaceFileDialogFragment.ActionChooseListener { ReplaceFileDialogFragment.ActionChooseListener {
// Views // Views
private var footer: ViewGroup? = null
private var container: ViewGroup? = null
private var coordinatorLayout: CoordinatorLayout? = null private var coordinatorLayout: CoordinatorLayout? = null
private var scrollView: NestedScrollView? = null private var scrollView: NestedScrollView? = null
private var templateSelectorSpinner: Spinner? = null private var templateSelectorSpinner: Spinner? = null
@@ -96,6 +122,9 @@ class EntryEditActivity : DatabaseLockActivity(),
private var mTemplate: Template? = null private var mTemplate: Template? = null
private var mIsTemplate: Boolean = false private var mIsTemplate: Boolean = false
private var mEntryLoaded: Boolean = false private var mEntryLoaded: Boolean = false
private var mTemplatesSelectorAdapter: TemplatesSelectorAdapter? = null
private val mColorPickerViewModel: ColorPickerViewModel by viewModels()
private var mAllowCustomFields = false private var mAllowCustomFields = false
private var mAllowOTP = false private var mAllowOTP = false
@@ -104,7 +133,25 @@ class EntryEditActivity : DatabaseLockActivity(),
private var mExternalFileHelper: ExternalFileHelper? = null private var mExternalFileHelper: ExternalFileHelper? = null
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
// Education // Education
private var entryEditActivityEducation: EntryEditActivityEducation? = null private var mEntryEditActivityEducation = EntryEditActivityEducation(this)
private var mIconSelectionActivityResultLauncher = IconPickerActivity.registerIconSelectionForResult(this) { icon ->
mEntryEditViewModel.selectIcon(icon)
}
private var mPasswordField: Field? = null
private var mKeyGeneratorResultLauncher = KeyGeneratorActivity.registerForGeneratedKeyResult(this) { keyGenerated ->
keyGenerated?.let {
mPasswordField?.let {
it.protectedValue.stringValue = keyGenerated
mEntryEditViewModel.selectPassword(it)
}
}
mPasswordField = null
Handler(Looper.getMainLooper()).post {
performedNextEducation()
}
}
// To ask data lost only one time // To ask data lost only one time
private var backPressedAlreadyApproved = false private var backPressedAlreadyApproved = false
@@ -115,10 +162,8 @@ class EntryEditActivity : DatabaseLockActivity(),
// Bottom Bar // Bottom Bar
entryEditAddToolBar = findViewById(R.id.entry_edit_bottom_bar) entryEditAddToolBar = findViewById(R.id.entry_edit_bottom_bar)
setSupportActionBar(entryEditAddToolBar) footer = findViewById(R.id.activity_entry_edit_footer)
supportActionBar?.setDisplayHomeAsUpEnabled(true) container = findViewById(R.id.activity_entry_edit_container)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
coordinatorLayout = findViewById(R.id.entry_edit_coordinator_layout) coordinatorLayout = findViewById(R.id.entry_edit_coordinator_layout)
scrollView = findViewById(R.id.entry_edit_scroll) scrollView = findViewById(R.id.entry_edit_scroll)
scrollView?.scrollBarStyle = View.SCROLLBARS_INSIDE_INSET scrollView?.scrollBarStyle = View.SCROLLBARS_INSIDE_INSET
@@ -127,19 +172,30 @@ class EntryEditActivity : DatabaseLockActivity(),
validateButton = findViewById(R.id.entry_edit_validate) validateButton = findViewById(R.id.entry_edit_validate)
loadingView = findViewById(R.id.loading) 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)
footer?.applyWindowInsets(WindowInsetPosition.BOTTOM)
}
stopService(Intent(this, ClipboardEntryNotificationService::class.java)) stopService(Intent(this, ClipboardEntryNotificationService::class.java))
stopService(Intent(this, KeyboardEntryNotificationService::class.java)) stopService(Intent(this, KeyboardEntryNotificationService::class.java))
// Entry is retrieve, it's an entry to update // Entry is retrieve, it's an entry to update
var entryId: NodeId<UUID>? = null var entryId: NodeId<UUID>? = null
intent.getParcelableExtra<NodeId<UUID>>(KEY_ENTRY)?.let { entryToUpdate -> intent.getParcelableExtraCompat<NodeId<UUID>>(KEY_ENTRY)?.let { entryToUpdate ->
intent.removeExtra(KEY_ENTRY) intent.removeExtra(KEY_ENTRY)
entryId = entryToUpdate entryId = entryToUpdate
} }
// Parent is retrieve, it's a new entry to create // Parent is retrieve, it's a new entry to create
var parentId: NodeId<*>? = null var parentId: NodeId<*>? = null
intent.getParcelableExtra<NodeId<*>>(KEY_PARENT)?.let { parent -> intent.getParcelableExtraCompat<NodeId<*>>(KEY_PARENT)?.let { parent ->
intent.removeExtra(KEY_PARENT) intent.removeExtra(KEY_PARENT)
parentId = parent parentId = parent
} }
@@ -154,14 +210,27 @@ class EntryEditActivity : DatabaseLockActivity(),
// To retrieve attachment // To retrieve attachment
mExternalFileHelper = ExternalFileHelper(this) mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildOpenDocument { uri ->
uri?.let { attachmentToUploadUri ->
attachmentToUploadUri.getDocumentFile(this)?.also { documentFile ->
documentFile.name?.let { fileName ->
if (documentFile.length() > MAX_WARNING_BINARY_FILE) {
FileTooBigDialogFragment.build(attachmentToUploadUri, fileName)
.show(supportFragmentManager, "fileTooBigFragment")
} else {
mEntryEditViewModel.buildNewAttachment(attachmentToUploadUri, fileName)
}
}
}
}
}
mAttachmentFileBinderManager = AttachmentFileBinderManager(this) mAttachmentFileBinderManager = AttachmentFileBinderManager(this)
// Verify the education views
entryEditActivityEducation = EntryEditActivityEducation(this)
// Lock button // Lock button
lockView?.setOnClickListener { lockAndExit() } lockView?.setOnClickListener { lockAndExit() }
// Save button // Save button
validateButton?.setOnClickListener { saveEntry() } validateButton?.setOnClickListener { validateEntry() }
mEntryEditViewModel.onTemplateChanged.observe(this) { template -> mEntryEditViewModel.onTemplateChanged.observe(this) { template ->
this.mTemplate = template this.mTemplate = template
@@ -175,11 +244,13 @@ class EntryEditActivity : DatabaseLockActivity(),
templateSelectorSpinner?.apply { templateSelectorSpinner?.apply {
// Build template selector // Build template selector
if (templates.isNotEmpty()) { if (templates.isNotEmpty()) {
adapter = TemplatesSelectorAdapter( mTemplatesSelectorAdapter = TemplatesSelectorAdapter(
this@EntryEditActivity, this@EntryEditActivity,
mIconDrawableFactory,
templates templates
) ).apply {
iconDrawableFactory = mDatabase?.iconDrawableFactory
}
adapter = mTemplatesSelectorAdapter
val selectedTemplate = if (mTemplate != null) val selectedTemplate = if (mTemplate != null)
mTemplate mTemplate
else else
@@ -213,27 +284,41 @@ class EntryEditActivity : DatabaseLockActivity(),
// View model listeners // View model listeners
mEntryEditViewModel.requestIconSelection.observe(this) { iconImage -> mEntryEditViewModel.requestIconSelection.observe(this) { iconImage ->
IconPickerActivity.launch(this@EntryEditActivity, iconImage) IconPickerActivity.launch(this@EntryEditActivity, iconImage, mIconSelectionActivityResultLauncher)
}
mEntryEditViewModel.requestColorSelection.observe(this) { color ->
ColorPickerDialogFragment.newInstance(color)
.show(supportFragmentManager, "ColorPickerFragment")
}
mColorPickerViewModel.colorPicked.observe(this) { color ->
mEntryEditViewModel.selectColor(color)
} }
mEntryEditViewModel.requestDateTimeSelection.observe(this) { dateInstant -> mEntryEditViewModel.requestDateTimeSelection.observe(this) { dateInstant ->
if (dateInstant.type == DateInstant.Type.TIME) { if (dateInstant.type == DateInstant.Type.TIME) {
// Launch the time picker // Launch the time picker
val dateTime = DateTime(dateInstant.date) MaterialTimePicker.Builder().build().apply {
TimePickerFragment.getInstance(dateTime.hourOfDay, dateTime.minuteOfHour) addOnPositiveButtonClickListener {
.show(supportFragmentManager, "TimePickerFragment") mEntryEditViewModel.selectTime(this.hour, this.minute)
}
show(supportFragmentManager, "TimePickerFragment")
}
} else { } else {
// Launch the date picker // Launch the date picker
val dateTime = DateTime(dateInstant.date) MaterialDatePicker.Builder.datePicker().build().apply {
DatePickerFragment.getInstance(dateTime.year, dateTime.monthOfYear - 1, dateTime.dayOfMonth) addOnPositiveButtonClickListener {
.show(supportFragmentManager, "DatePickerFragment") mEntryEditViewModel.selectDate(it)
}
show(supportFragmentManager, "DatePickerFragment")
}
} }
} }
mEntryEditViewModel.requestPasswordSelection.observe(this) { passwordField -> mEntryEditViewModel.requestPasswordSelection.observe(this) { passwordField ->
GeneratePasswordDialogFragment mPasswordField = passwordField
.getInstance(passwordField) KeyGeneratorActivity.launch(this, mKeyGeneratorResultLauncher)
.show(supportFragmentManager, "PasswordGeneratorFragment")
} }
mEntryEditViewModel.requestCustomFieldEdition.observe(this) { field -> mEntryEditViewModel.requestCustomFieldEdition.observe(this) { field ->
@@ -316,15 +401,19 @@ class EntryEditActivity : DatabaseLockActivity(),
return true return true
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
mAllowCustomFields = database?.allowEntryCustomFields() == true mAllowCustomFields = database?.allowEntryCustomFields() == true
mAllowOTP = database?.allowOTP == true mAllowOTP = database?.allowOTP == true
mEntryEditViewModel.loadDatabase(database) mEntryEditViewModel.loadDatabase(database)
mTemplatesSelectorAdapter?.apply {
iconDrawableFactory = mDatabase?.iconDrawableFactory
notifyDataSetChanged()
}
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {
@@ -377,17 +466,18 @@ class EntryEditActivity : DatabaseLockActivity(),
finishForEntryResult(entry) finishForEntryResult(entry)
} }
private fun entryValidatedForKeyboardSelection(database: Database, entry: Entry) { private fun entryValidatedForKeyboardSelection(database: ContextualDatabase, entry: Entry) {
// Populate Magikeyboard with entry // Populate Magikeyboard with entry
populateKeyboardAndMoveAppToBackground(this, MagikeyboardService.populateKeyboardAndMoveAppToBackground(
entry.getEntryInfo(database), this,
intent) entry.getEntryInfo(database)
)
onValidateSpecialMode() onValidateSpecialMode()
// Don't keep activity history for entry edition // Don't keep activity history for entry edition
finishForEntryResult(entry) finishForEntryResult(entry)
} }
private fun entryValidatedForAutofillSelection(database: Database, entry: Entry) { private fun entryValidatedForAutofillSelection(database: ContextualDatabase, entry: Entry) {
// Build Autofill response with the entry selected // Build Autofill response with the entry selected
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.buildResponseAndSetResult(this@EntryEditActivity, AutofillHelper.buildResponseAndSetResult(this@EntryEditActivity,
@@ -422,6 +512,11 @@ class EntryEditActivity : DatabaseLockActivity(),
} }
} }
} }
// Keep the screen on
if (PreferencesUtil.isKeepScreenOnEnabled(this)) {
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
} }
override fun onPause() { override fun onPause() {
@@ -472,29 +567,6 @@ class EntryEditActivity : DatabaseLockActivity(),
} }
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
IconPickerActivity.onActivityResult(requestCode, resultCode, data) { icon ->
mEntryEditViewModel.selectIcon(icon)
}
mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri ->
uri?.let { attachmentToUploadUri ->
UriUtil.getFileData(this, attachmentToUploadUri)?.also { documentFile ->
documentFile.name?.let { fileName ->
if (documentFile.length() > MAX_WARNING_BINARY_FILE) {
FileTooBigDialogFragment.build(attachmentToUploadUri, fileName)
.show(supportFragmentManager, "fileTooBigFragment")
} else {
mEntryEditViewModel.buildNewAttachment(attachmentToUploadUri, fileName)
}
}
}
}
}
}
/** /**
* Set up OTP (HOTP or TOTP) and add it as extra field * Set up OTP (HOTP or TOTP) and add it as extra field
*/ */
@@ -507,9 +579,9 @@ class EntryEditActivity : DatabaseLockActivity(),
} }
/** /**
* Saves the new entry or update an existing entry in the database * Validate the new entry or update an existing entry in the database
*/ */
private fun saveEntry() { private fun validateEntry() {
mAttachmentFileBinderManager?.stopUploadAllAttachments() mAttachmentFileBinderManager?.stopUploadAllAttachments()
mEntryEditViewModel.requestEntryInfoUpdate(mDatabase) mEntryEditViewModel.requestEntryInfoUpdate(mDatabase)
} }
@@ -518,10 +590,8 @@ class EntryEditActivity : DatabaseLockActivity(),
super.onCreateOptionsMenu(menu) super.onCreateOptionsMenu(menu)
if (mEntryLoaded) { if (mEntryLoaded) {
menuInflater.inflate(R.menu.entry_edit, menu) menuInflater.inflate(R.menu.entry_edit, menu)
entryEditActivityEducation?.let { Handler(Looper.getMainLooper()).post {
Handler(Looper.getMainLooper()).post { performedNextEducation()
performedNextEducation(it)
}
} }
} }
return true return true
@@ -548,19 +618,19 @@ class EntryEditActivity : DatabaseLockActivity(),
return super.onPrepareOptionsMenu(menu) return super.onPrepareOptionsMenu(menu)
} }
private fun performedNextEducation(entryEditActivityEducation: EntryEditActivityEducation) { private fun performedNextEducation() {
val entryEditFragment = supportFragmentManager.findFragmentById(R.id.entry_edit_content) val entryEditFragment = supportFragmentManager.findFragmentById(R.id.entry_edit_content)
as? EntryEditFragment? as? EntryEditFragment?
val generatePasswordView = entryEditFragment?.getActionImageView() val generatePasswordView = entryEditFragment?.getActionImageView()
val generatePasswordEductionPerformed = generatePasswordView != null val generatePasswordEductionPerformed = generatePasswordView != null
&& entryEditActivityEducation.checkAndPerformedGeneratePasswordEducation( && mEntryEditActivityEducation.checkAndPerformedGeneratePasswordEducation(
generatePasswordView, generatePasswordView,
{ {
entryEditFragment.launchGeneratePasswordEductionAction() entryEditFragment.launchGeneratePasswordEductionAction()
}, },
{ {
performedNextEducation(entryEditActivityEducation) performedNextEducation()
} }
) )
@@ -569,38 +639,53 @@ class EntryEditActivity : DatabaseLockActivity(),
val addNewFieldEducationPerformed = mAllowCustomFields val addNewFieldEducationPerformed = mAllowCustomFields
&& addNewFieldView != null && addNewFieldView != null
&& addNewFieldView.isVisible && addNewFieldView.isVisible
&& entryEditActivityEducation.checkAndPerformedEntryNewFieldEducation( && mEntryEditActivityEducation.checkAndPerformedEntryNewFieldEducation(
addNewFieldView, addNewFieldView,
{ {
addNewCustomField() addNewCustomField()
}, },
{ {
performedNextEducation(entryEditActivityEducation) performedNextEducation()
} }
) )
if (!addNewFieldEducationPerformed) { if (!addNewFieldEducationPerformed) {
val attachmentView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_attachment) val attachmentView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_attachment)
val addAttachmentEducationPerformed = attachmentView != null val addAttachmentEducationPerformed = attachmentView != null
&& attachmentView.isVisible && attachmentView.isVisible
&& entryEditActivityEducation.checkAndPerformedAttachmentEducation( && mEntryEditActivityEducation.checkAndPerformedAttachmentEducation(
attachmentView, attachmentView,
{ {
mExternalFileHelper?.openDocument() addNewAttachment()
}, },
{ {
performedNextEducation(entryEditActivityEducation) performedNextEducation()
} }
) )
if (!addAttachmentEducationPerformed) { if (!addAttachmentEducationPerformed) {
val setupOtpView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_otp) val setupOtpView: View? = entryEditAddToolBar?.findViewById(R.id.menu_add_otp)
setupOtpView != null val validateEntryEducationPerformed = setupOtpView != null
&& setupOtpView.isVisible && setupOtpView.isVisible
&& entryEditActivityEducation.checkAndPerformedSetUpOTPEducation( && mEntryEditActivityEducation.checkAndPerformedSetUpOTPEducation(
setupOtpView, setupOtpView,
{ {
setupOtp() setupOtp()
},
{
performedNextEducation()
} }
) )
if (!validateEntryEducationPerformed) {
val entryValidateView = validateButton
mAllowCustomFields
&& entryValidateView != null
&& entryValidateView.isVisible
&& mEntryEditActivityEducation.checkAndPerformedValidateEntryEducation(
entryValidateView,
{
validateEntry()
}
)
}
} }
} }
} }
@@ -621,39 +706,16 @@ class EntryEditActivity : DatabaseLockActivity(),
return true return true
} }
android.R.id.home -> { android.R.id.home -> {
onBackPressed() onDatabaseBackPressed()
} }
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
override fun onDateSet(datePicker: DatePicker?, year: Int, month: Int, day: Int) { override fun onDatabaseBackPressed() {
// To fix android 4.4 issue
// https://stackoverflow.com/questions/12436073/datepicker-ondatechangedlistener-called-twice
if (datePicker?.isShown == true) {
mEntryEditViewModel.selectDate(year, month, day)
}
}
override fun onTimeSet(timePicker: TimePicker?, hours: Int, minutes: Int) {
mEntryEditViewModel.selectTime(hours, minutes)
}
override fun acceptPassword(passwordField: Field) {
mEntryEditViewModel.selectPassword(passwordField)
entryEditActivityEducation?.let {
Handler(Looper.getMainLooper()).post { performedNextEducation(it) }
}
}
override fun cancelPassword(passwordField: Field) {
// Do nothing here
}
override fun onBackPressed() {
onApprovedBackPressed { onApprovedBackPressed {
super@EntryEditActivity.onBackPressed() super@EntryEditActivity.onDatabaseBackPressed()
} }
} }
@@ -686,7 +748,7 @@ class EntryEditActivity : DatabaseLockActivity(),
val intentEntry = Intent() val intentEntry = Intent()
bundle.putParcelable(ADD_OR_UPDATE_ENTRY_KEY, entry.nodeId) bundle.putParcelable(ADD_OR_UPDATE_ENTRY_KEY, entry.nodeId)
intentEntry.putExtras(bundle) intentEntry.putExtras(bundle)
setResult(ADD_OR_UPDATE_ENTRY_RESULT_CODE, intentEntry) setResult(Activity.RESULT_OK, intentEntry)
super.finish() super.finish()
} catch (e: Exception) { } catch (e: Exception) {
// Exception when parcelable can't be done // Exception when parcelable can't be done
@@ -701,23 +763,46 @@ class EntryEditActivity : DatabaseLockActivity(),
// Keys for current Activity // Keys for current Activity
const val KEY_ENTRY = "entry" const val KEY_ENTRY = "entry"
const val KEY_PARENT = "parent" const val KEY_PARENT = "parent"
// Keys for callback
const val ADD_OR_UPDATE_ENTRY_RESULT_CODE = 31
const val ADD_OR_UPDATE_ENTRY_REQUEST_CODE = 7129
const val ADD_OR_UPDATE_ENTRY_KEY = "ADD_OR_UPDATE_ENTRY_KEY" const val ADD_OR_UPDATE_ENTRY_KEY = "ADD_OR_UPDATE_ENTRY_KEY"
fun registerForEntryResult(fragment: Fragment,
entryAddedOrUpdatedListener: (NodeId<UUID>?) -> Unit): ActivityResultLauncher<Intent> {
return fragment.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
entryAddedOrUpdatedListener.invoke(
result.data?.getParcelableExtraCompat(ADD_OR_UPDATE_ENTRY_KEY)
)
} else {
entryAddedOrUpdatedListener.invoke(null)
}
}
}
fun registerForEntryResult(activity: FragmentActivity,
entryAddedOrUpdatedListener: (NodeId<UUID>?) -> Unit): ActivityResultLauncher<Intent> {
return activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
entryAddedOrUpdatedListener.invoke(
result.data?.getParcelableExtraCompat(ADD_OR_UPDATE_ENTRY_KEY)
)
} else {
entryAddedOrUpdatedListener.invoke(null)
}
}
}
/** /**
* Launch EntryEditActivity to update an existing entry by his [entryId] * Launch EntryEditActivity to update an existing entry by his [entryId]
*/ */
fun launchToUpdate(activity: Activity, fun launchToUpdate(activity: Activity,
database: Database, database: ContextualDatabase,
entryId: NodeId<UUID>) { entryId: NodeId<UUID>,
activityResultLauncher: ActivityResultLauncher<Intent>) {
if (database.loaded && !database.isReadOnly) { if (database.loaded && !database.isReadOnly) {
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) { if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
val intent = Intent(activity, EntryEditActivity::class.java) val intent = Intent(activity, EntryEditActivity::class.java)
intent.putExtra(KEY_ENTRY, entryId) intent.putExtra(KEY_ENTRY, entryId)
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE) activityResultLauncher.launch(intent)
} }
} }
} }
@@ -726,19 +811,20 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to add a new entry in an existent group * Launch EntryEditActivity to add a new entry in an existent group
*/ */
fun launchToCreate(activity: Activity, fun launchToCreate(activity: Activity,
database: Database, database: ContextualDatabase,
groupId: NodeId<*>) { groupId: NodeId<*>,
activityResultLauncher: ActivityResultLauncher<Intent>) {
if (database.loaded && !database.isReadOnly) { if (database.loaded && !database.isReadOnly) {
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) { if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
val intent = Intent(activity, EntryEditActivity::class.java) val intent = Intent(activity, EntryEditActivity::class.java)
intent.putExtra(KEY_PARENT, groupId) intent.putExtra(KEY_PARENT, groupId)
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE) activityResultLauncher.launch(intent)
} }
} }
} }
fun launchToUpdateForSave(context: Context, fun launchToUpdateForSave(context: Context,
database: Database, database: ContextualDatabase,
entryId: NodeId<UUID>, entryId: NodeId<UUID>,
searchInfo: SearchInfo) { searchInfo: SearchInfo) {
if (database.loaded && !database.isReadOnly) { if (database.loaded && !database.isReadOnly) {
@@ -755,7 +841,7 @@ class EntryEditActivity : DatabaseLockActivity(),
} }
fun launchToCreateForSave(context: Context, fun launchToCreateForSave(context: Context,
database: Database, database: ContextualDatabase,
groupId: NodeId<*>, groupId: NodeId<*>,
searchInfo: SearchInfo) { searchInfo: SearchInfo) {
if (database.loaded && !database.isReadOnly) { if (database.loaded && !database.isReadOnly) {
@@ -775,7 +861,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to add a new entry in keyboard selection * Launch EntryEditActivity to add a new entry in keyboard selection
*/ */
fun launchForKeyboardSelectionResult(context: Context, fun launchForKeyboardSelectionResult(context: Context,
database: Database, database: ContextualDatabase,
groupId: NodeId<*>, groupId: NodeId<*>,
searchInfo: SearchInfo? = null) { searchInfo: SearchInfo? = null) {
if (database.loaded && !database.isReadOnly) { if (database.loaded && !database.isReadOnly) {
@@ -795,8 +881,9 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to add a new entry in autofill selection * Launch EntryEditActivity to add a new entry in autofill selection
*/ */
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
fun launchForAutofillResult(activity: Activity, fun launchForAutofillResult(activity: AppCompatActivity,
database: Database, database: ContextualDatabase,
activityResultLauncher: ActivityResultLauncher<Intent>?,
autofillComponent: AutofillComponent, autofillComponent: AutofillComponent,
groupId: NodeId<*>, groupId: NodeId<*>,
searchInfo: SearchInfo? = null) { searchInfo: SearchInfo? = null) {
@@ -807,6 +894,7 @@ class EntryEditActivity : DatabaseLockActivity(),
AutofillHelper.startActivityForAutofillResult( AutofillHelper.startActivityForAutofillResult(
activity, activity,
intent, intent,
activityResultLauncher,
autofillComponent, autofillComponent,
searchInfo searchInfo
) )
@@ -818,7 +906,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to register an updated entry (from autofill) * Launch EntryEditActivity to register an updated entry (from autofill)
*/ */
fun launchToUpdateForRegistration(context: Context, fun launchToUpdateForRegistration(context: Context,
database: Database, database: ContextualDatabase,
entryId: NodeId<UUID>, entryId: NodeId<UUID>,
registerInfo: RegisterInfo? = null) { registerInfo: RegisterInfo? = null) {
if (database.loaded && !database.isReadOnly) { if (database.loaded && !database.isReadOnly) {
@@ -838,7 +926,7 @@ class EntryEditActivity : DatabaseLockActivity(),
* Launch EntryEditActivity to register a new entry (from autofill) * Launch EntryEditActivity to register a new entry (from autofill)
*/ */
fun launchToCreateForRegistration(context: Context, fun launchToCreateForRegistration(context: Context,
database: Database, database: ContextualDatabase,
groupId: NodeId<*>, groupId: NodeId<*>,
registerInfo: RegisterInfo? = null) { registerInfo: RegisterInfo? = null) {
if (database.loaded && !database.isReadOnly) { if (database.loaded && !database.isReadOnly) {

View File

@@ -19,20 +19,21 @@
*/ */
package com.kunzisoft.keepass.activities package com.kunzisoft.keepass.activities
import android.app.Activity import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.search.SearchHelper import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.magikeyboard.MagikeyboardService import com.kunzisoft.keepass.magikeyboard.MagikeyboardService
import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.SearchInfo import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.otp.OtpEntryFields import com.kunzisoft.keepass.otp.OtpEntryFields
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.utils.KeyboardUtil.isKeyboardActivatedInSettings
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.WebDomain
/** /**
* Activity to search or select entry in database, * Activity to search or select entry in database,
@@ -45,156 +46,181 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
} }
override fun finishActivityIfReloadRequested(): Boolean { override fun finishActivityIfReloadRequested(): Boolean {
return true return false
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
var sharedWebDomain: String? = null
var otpString: String? = null
when (intent?.action) { val keySelectionBundle = intent.getBundleExtra(KEY_SELECTION_BUNDLE)
Intent.ACTION_SEND -> { if (keySelectionBundle != null) {
if ("text/plain" == intent.type) { // To manage package name
// Retrieve web domain or OTP var searchInfo = SearchInfo()
intent.getStringExtra(Intent.EXTRA_TEXT)?.let { extra -> keySelectionBundle.getParcelableCompat<SearchInfo>(KEY_SEARCH_INFO)?.let { mSearchInfo ->
searchInfo = mSearchInfo
}
launch(database, searchInfo)
} else {
// To manage share
var sharedWebDomain: String? = null
var otpString: String? = null
when (intent?.action) {
Intent.ACTION_SEND -> {
if ("text/plain" == intent.type) {
// Retrieve web domain or OTP
intent.getStringExtra(Intent.EXTRA_TEXT)?.let { extra ->
if (OtpEntryFields.isOTPUri(extra))
otpString = extra
else
sharedWebDomain = Uri.parse(extra).host
}
}
launchSelection(database, sharedWebDomain, otpString)
}
Intent.ACTION_VIEW -> {
// Retrieve OTP
intent.dataString?.let { extra ->
if (OtpEntryFields.isOTPUri(extra)) if (OtpEntryFields.isOTPUri(extra))
otpString = extra otpString = extra
else }
sharedWebDomain = Uri.parse(extra).host launchSelection(database, sharedWebDomain, otpString)
}
else -> {
if (database != null) {
GroupActivity.launch(this, database)
} else {
FileDatabaseSelectActivity.launch(this)
} }
} }
} }
Intent.ACTION_VIEW -> {
// Retrieve OTP
intent.dataString?.let { extra ->
if (OtpEntryFields.isOTPUri(extra))
otpString = extra
}
}
else -> {}
} }
finish()
}
private fun launchSelection(database: ContextualDatabase?,
sharedWebDomain: String?,
otpString: String?) {
// Build domain search param // Build domain search param
val searchInfo = SearchInfo().apply { val searchInfo = SearchInfo().apply {
this.webDomain = sharedWebDomain this.webDomain = sharedWebDomain
this.otpString = otpString this.otpString = otpString
} }
SearchInfo.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain -> WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
searchInfo.webDomain = concreteWebDomain searchInfo.webDomain = concreteWebDomain
launch(database, searchInfo) launch(database, searchInfo)
} }
} }
private fun launch(database: Database?, private fun launch(database: ContextualDatabase?,
searchInfo: SearchInfo) { searchInfo: SearchInfo) {
if (!searchInfo.containsOnlyNullValues()) { // Setting to integrate Magikeyboard
// Setting to integrate Magikeyboard val searchShareForMagikeyboard = isKeyboardActivatedInSettings()
val searchShareForMagikeyboard = PreferencesUtil.isKeyboardSearchShareEnable(this)
// If database is open // If database is open
val readOnly = database?.isReadOnly != false val readOnly = database?.isReadOnly != false
SearchHelper.checkAutoSearchInfo(this, SearchHelper.checkAutoSearchInfo(this,
database, database,
searchInfo, searchInfo,
{ openedDatabase, items -> { openedDatabase, items ->
// Items found // Items found
if (searchInfo.otpString != null) { if (searchInfo.otpString != null) {
if (!readOnly) { if (!readOnly) {
GroupActivity.launchForSaveResult( GroupActivity.launchForSaveResult(
this, this,
openedDatabase,
searchInfo,
false)
} else {
Toast.makeText(applicationContext,
R.string.autofill_read_only_save,
Toast.LENGTH_LONG)
.show()
}
} else if (searchShareForMagikeyboard) {
if (items.size == 1) {
// Automatically populate keyboard
val entryPopulate = items[0]
populateKeyboardAndMoveAppToBackground(
this,
entryPopulate,
intent)
} else {
// Select the one we want
GroupActivity.launchForKeyboardSelectionResult(this,
openedDatabase,
searchInfo,
true)
}
} else {
GroupActivity.launchForSearchResult(this,
openedDatabase,
searchInfo,
true)
}
},
{ openedDatabase ->
// Show the database UI to select the entry
if (searchInfo.otpString != null) {
if (!readOnly) {
GroupActivity.launchForSaveResult(this,
openedDatabase,
searchInfo,
false)
} else {
Toast.makeText(applicationContext,
R.string.autofill_read_only_save,
Toast.LENGTH_LONG)
.show()
}
} else if (readOnly || searchShareForMagikeyboard) {
GroupActivity.launchForKeyboardSelectionResult(this,
openedDatabase, openedDatabase,
searchInfo, searchInfo,
false) false)
} else { } else {
Toast.makeText(applicationContext,
R.string.autofill_read_only_save,
Toast.LENGTH_LONG)
.show()
}
} else if (searchShareForMagikeyboard) {
MagikeyboardService.performSelection(
items,
{ entryInfo ->
// Automatically populate keyboard
MagikeyboardService.populateKeyboardAndMoveAppToBackground(
this,
entryInfo
)
},
{ autoSearch ->
GroupActivity.launchForKeyboardSelectionResult(this,
openedDatabase,
searchInfo,
autoSearch)
}
)
} else {
GroupActivity.launchForSearchResult(this,
openedDatabase,
searchInfo,
true)
}
},
{ openedDatabase ->
// Show the database UI to select the entry
if (searchInfo.otpString != null) {
if (!readOnly) {
GroupActivity.launchForSaveResult(this, GroupActivity.launchForSaveResult(this,
openedDatabase, openedDatabase,
searchInfo, searchInfo,
false) false)
}
},
{
// If database not open
if (searchInfo.otpString != null) {
if (!readOnly) {
FileDatabaseSelectActivity.launchForSaveResult(this,
searchInfo)
} else {
Toast.makeText(applicationContext,
R.string.autofill_read_only_save,
Toast.LENGTH_LONG)
.show()
}
} else if (searchShareForMagikeyboard) {
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this,
searchInfo)
} else { } else {
FileDatabaseSelectActivity.launchForSearchResult(this, Toast.makeText(applicationContext,
searchInfo) R.string.autofill_read_only_save,
Toast.LENGTH_LONG)
.show()
} }
} else if (searchShareForMagikeyboard) {
GroupActivity.launchForKeyboardSelectionResult(this,
openedDatabase,
searchInfo,
false)
} else {
GroupActivity.launchForSearchResult(this,
openedDatabase,
searchInfo,
false)
} }
) },
{
// If database not open
if (searchInfo.otpString != null) {
FileDatabaseSelectActivity.launchForSaveResult(this,
searchInfo)
} else if (searchShareForMagikeyboard) {
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this,
searchInfo)
} else {
FileDatabaseSelectActivity.launchForSearchResult(this,
searchInfo)
}
}
)
}
companion object {
private const val KEY_SELECTION_BUNDLE = "KEY_SELECTION_BUNDLE"
private const val KEY_SEARCH_INFO = "KEY_SEARCH_INFO"
fun launch(context: Context,
searchInfo: SearchInfo? = null) {
val intent = Intent(context, EntrySelectionLauncherActivity::class.java).apply {
putExtra(KEY_SELECTION_BUNDLE, Bundle().apply {
putParcelable(KEY_SEARCH_INFO, searchInfo)
})
}
// New task needed because don't launch from an Activity context
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK
context.startActivity(intent)
} }
finish()
} }
} }
fun populateKeyboardAndMoveAppToBackground(activity: Activity,
entry: EntryInfo,
intent: Intent,
toast: Boolean = true) {
// Populate Magikeyboard with entry
MagikeyboardService.addEntryAndLaunchNotificationIfAllowed(activity, entry, toast)
// Consume the selection mode
EntrySelectionHelper.removeModesFromIntent(intent)
activity.moveTaskToBack(true)
}

View File

@@ -31,16 +31,19 @@ import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
@@ -50,9 +53,10 @@ import com.kunzisoft.keepass.adapters.FileDatabaseHistoryAdapter
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.autofill.AutofillComponent import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
import com.kunzisoft.keepass.model.MainCredential import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.model.RegisterInfo import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
@@ -61,21 +65,32 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.* 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.view.asError import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
import com.kunzisoft.keepass.viewmodels.DatabaseFilesViewModel import com.kunzisoft.keepass.viewmodels.DatabaseFilesViewModel
import java.io.FileNotFoundException import java.io.FileNotFoundException
class FileDatabaseSelectActivity : DatabaseModeActivity(), class FileDatabaseSelectActivity : DatabaseModeActivity(),
AssignMasterKeyDialogFragment.AssignPasswordDialogListener { SetMainCredentialDialogFragment.AssignMainCredentialDialogListener {
// Views // Views
private lateinit var coordinatorLayout: CoordinatorLayout private lateinit var coordinatorLayout: CoordinatorLayout
private var specialTitle: View? = null
private var createDatabaseButtonView: View? = null private var createDatabaseButtonView: View? = null
private var openDatabaseButtonView: View? = null private var openDatabaseButtonView: View? = null
private val databaseFilesViewModel: DatabaseFilesViewModel by viewModels() private val databaseFilesViewModel: DatabaseFilesViewModel by viewModels()
private val mFileDatabaseSelectActivityEducation = FileDatabaseSelectActivityEducation(this)
// Adapter to manage database history list // Adapter to manage database history list
private var mAdapterDatabaseHistory: FileDatabaseHistoryAdapter? = null private var mAdapterDatabaseHistory: FileDatabaseHistoryAdapter? = null
@@ -85,9 +100,20 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
private var mExternalFileHelper: ExternalFileHelper? = null private var mExternalFileHelper: ExternalFileHelper? = null
private var mAutofillActivityResultLauncher: ActivityResultLauncher<Intent>? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
AutofillHelper.buildActivityResultLauncher(this)
else null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// Enabling/disabling MagikeyboardService is normally done by DexModeReceiver, but this
// additional check will allow the keyboard to be reenabled more easily if the app crashes
// or is force quit within DeX mode and then the user leaves DeX mode. Without this, the
// user would need to enter and exit DeX mode once to reenable the service.
MagikeyboardUtil.setEnabled(this, !DexUtil.isDexMode(resources.configuration))
mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(applicationContext) mFileDatabaseHistoryAction = FileDatabaseHistoryAction.getInstance(applicationContext)
setContentView(R.layout.activity_file_selection) setContentView(R.layout.activity_file_selection)
@@ -97,13 +123,32 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
toolbar.title = "" toolbar.title = ""
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
// Special title
specialTitle = findViewById(R.id.file_selection_title_part_3)
// Create database button // Create database button
createDatabaseButtonView = findViewById(R.id.create_database_button) createDatabaseButtonView = findViewById(R.id.create_database_button)
createDatabaseButtonView?.setOnClickListener { createNewFile() } createDatabaseButtonView?.setOnClickListener { createNewFile() }
// Open database button // Open database button
mExternalFileHelper = ExternalFileHelper(this) mExternalFileHelper = ExternalFileHelper(this)
openDatabaseButtonView = findViewById(R.id.open_keyfile_button) mExternalFileHelper?.buildOpenDocument { uri ->
uri?.let {
launchPasswordActivityWithPath(uri)
}
}
mExternalFileHelper?.buildCreateDocument("application/x-keepass") { databaseFileCreatedUri ->
mDatabaseFileUri = databaseFileCreatedUri
if (mDatabaseFileUri != null) {
SetMainCredentialDialogFragment.getInstance(true)
.show(supportFragmentManager, "passwordDialog")
} else {
val error = getString(R.string.error_create_database)
Snackbar.make(coordinatorLayout, error, Snackbar.LENGTH_LONG).asError().show()
Log.e(TAG, error)
}
}
openDatabaseButtonView = findViewById(R.id.open_database_button)
openDatabaseButtonView?.setOpenDocumentClickListener(mExternalFileHelper) openDatabaseButtonView?.setOpenDocumentClickListener(mExternalFileHelper)
// History list // History list
@@ -119,8 +164,9 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryOpenListener { fileDatabaseHistoryEntityToOpen -> mAdapterDatabaseHistory?.setOnFileDatabaseHistoryOpenListener { fileDatabaseHistoryEntityToOpen ->
fileDatabaseHistoryEntityToOpen.databaseUri?.let { databaseFileUri -> fileDatabaseHistoryEntityToOpen.databaseUri?.let { databaseFileUri ->
launchPasswordActivity( launchPasswordActivity(
databaseFileUri, databaseFileUri,
fileDatabaseHistoryEntityToOpen.keyFileUri fileDatabaseHistoryEntityToOpen.keyFileUri,
fileDatabaseHistoryEntityToOpen.hardwareKey
) )
} }
} }
@@ -140,7 +186,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
&& savedInstanceState.getBoolean(EXTRA_STAY, false))) { && savedInstanceState.getBoolean(EXTRA_STAY, false))) {
val databasePath = PreferencesUtil.getDefaultDatabasePath(this) val databasePath = PreferencesUtil.getDefaultDatabasePath(this)
UriUtil.parse(databasePath)?.let { databaseFileUri -> databasePath?.parseUri()?.let { databaseFileUri ->
launchPasswordActivityWithPath(databaseFileUri) launchPasswordActivityWithPath(databaseFileUri)
} ?: run { } ?: run {
Log.i(TAG, "No default database to prepare") Log.i(TAG, "No default database to prepare")
@@ -150,7 +196,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
// Retrieve the database URI provided by file manager after an orientation change // Retrieve the database URI provided by file manager after an orientation change
if (savedInstanceState != null if (savedInstanceState != null
&& savedInstanceState.containsKey(EXTRA_DATABASE_URI)) { && savedInstanceState.containsKey(EXTRA_DATABASE_URI)) {
mDatabaseFileUri = savedInstanceState.getParcelable(EXTRA_DATABASE_URI) mDatabaseFileUri = savedInstanceState.getParcelableCompat(EXTRA_DATABASE_URI)
} }
// Observe list of databases // Observe list of databases
@@ -189,7 +235,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
} }
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
if (database != null) { if (database != null) {
launchGroupActivityIfLoaded(database) launchGroupActivityIfLoaded(database)
@@ -197,7 +243,7 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {
@@ -208,13 +254,14 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
when (actionTask) { when (actionTask) {
ACTION_DATABASE_CREATE_TASK, ACTION_DATABASE_CREATE_TASK,
ACTION_DATABASE_LOAD_TASK -> { ACTION_DATABASE_LOAD_TASK -> {
result.data?.getParcelable<Uri?>(DATABASE_URI_KEY)?.let { databaseUri -> result.data?.getParcelableCompat<Uri>(DATABASE_URI_KEY)?.let { databaseUri ->
val mainCredential = val mainCredential =
result.data?.getParcelable(DatabaseTaskNotificationService.MAIN_CREDENTIAL_KEY) result.data?.getParcelableCompat(DatabaseTaskNotificationService.MAIN_CREDENTIAL_KEY)
?: MainCredential() ?: MainCredential()
databaseFilesViewModel.addDatabaseFile( databaseFilesViewModel.addDatabaseFile(
databaseUri, databaseUri,
mainCredential.keyFileUri mainCredential.keyFileUri,
mainCredential.hardwareKey
) )
} }
} }
@@ -232,26 +279,17 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
launchGroupActivityIfLoaded(database) launchGroupActivityIfLoaded(database)
} }
} }
} else {
var resultError = ""
val resultMessage = result.message
// Show error message
if (resultMessage != null && resultMessage.isNotEmpty()) {
resultError = "$resultError $resultMessage"
}
Log.e(TAG, resultError)
Snackbar.make(coordinatorLayout,
resultError,
Snackbar.LENGTH_LONG).asError().show()
} }
coordinatorLayout.showActionErrorIfNeeded(result)
} }
/** /**
* Create a new file by calling the content provider * Create a new file by calling the content provider
*/ */
private fun createNewFile() { private fun createNewFile() {
mExternalFileHelper?.createDocument( getString(R.string.database_file_name_default) + mExternalFileHelper?.createDocument(
getString(R.string.database_file_extension_default), "application/x-keepass") getString(R.string.database_file_name_default) +
getString(R.string.database_file_extension_default))
} }
private fun fileNoFoundAction(e: FileNotFoundException) { private fun fileNoFoundAction(e: FileNotFoundException) {
@@ -260,39 +298,32 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
Snackbar.make(coordinatorLayout, error, Snackbar.LENGTH_LONG).asError().show() Snackbar.make(coordinatorLayout, error, Snackbar.LENGTH_LONG).asError().show()
} }
private fun launchPasswordActivity(databaseUri: Uri, keyFile: Uri?) { private fun launchPasswordActivity(databaseUri: Uri, keyFile: Uri?, hardwareKey: HardwareKey?) {
PasswordActivity.launch(this, MainCredentialActivity.launch(this,
databaseUri, databaseUri,
keyFile, keyFile,
hardwareKey,
{ exception -> { exception ->
fileNoFoundAction(exception) fileNoFoundAction(exception)
}, },
{ onCancelSpecialMode() }, { onCancelSpecialMode() },
{ onLaunchActivitySpecialMode() }) { onLaunchActivitySpecialMode() },
mAutofillActivityResultLauncher)
} }
private fun launchGroupActivityIfLoaded(database: Database) { private fun launchGroupActivityIfLoaded(database: ContextualDatabase) {
if (database.loaded) { if (database.loaded) {
GroupActivity.launch(this, GroupActivity.launch(this,
database, database,
{ onValidateSpecialMode() }, { onValidateSpecialMode() },
{ onCancelSpecialMode() }, { onCancelSpecialMode() },
{ onLaunchActivitySpecialMode() }) { onLaunchActivitySpecialMode() },
mAutofillActivityResultLauncher)
} }
} }
override fun onValidateSpecialMode() {
super.onValidateSpecialMode()
finish()
}
override fun onCancelSpecialMode() {
super.onCancelSpecialMode()
finish()
}
private fun launchPasswordActivityWithPath(databaseUri: Uri) { private fun launchPasswordActivityWithPath(databaseUri: Uri) {
launchPasswordActivity(databaseUri, null) launchPasswordActivity(databaseUri, null, null)
// Delete flickering for kitkat <= // Delete flickering for kitkat <=
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
overridePendingTransition(0, 0) overridePendingTransition(0, 0)
@@ -301,10 +332,13 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
// Define special title
specialTitle?.isVisible = this.isContributingUser()
// Show open and create button or special mode // Show open and create button or special mode
when (mSpecialMode) { when (mSpecialMode) {
SpecialMode.DEFAULT -> { SpecialMode.DEFAULT -> {
if (ExternalFileHelper.allowCreateDocumentByStorageAccessFramework(packageManager)) { if (packageManager.allowCreateDocumentByStorageAccessFramework()) {
// There is an activity which can handle this intent. // There is an activity which can handle this intent.
createDatabaseButtonView?.visibility = View.VISIBLE createDatabaseButtonView?.visibility = View.VISIBLE
} else{ } else{
@@ -353,79 +387,53 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
override fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential) {} override fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential) {}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data)
}
mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri ->
if (uri != null) {
launchPasswordActivityWithPath(uri)
}
}
// Retrieve the created URI from the file manager
mExternalFileHelper?.onCreateDocumentResult(requestCode, resultCode, data) { databaseFileCreatedUri ->
mDatabaseFileUri = databaseFileCreatedUri
if (mDatabaseFileUri != null) {
AssignMasterKeyDialogFragment.getInstance(true)
.show(supportFragmentManager, "passwordDialog")
} else {
val error = getString(R.string.error_create_database)
Snackbar.make(coordinatorLayout, error, Snackbar.LENGTH_LONG).asError().show()
Log.e(TAG, error)
}
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu) super.onCreateOptionsMenu(menu)
if (mSpecialMode == SpecialMode.DEFAULT) { if (mSpecialMode == SpecialMode.DEFAULT) {
MenuUtil.defaultMenuInflater(menuInflater, menu) MenuUtil.defaultMenuInflater(this, menuInflater, menu)
} }
Handler(Looper.getMainLooper()).post { performedNextEducation(FileDatabaseSelectActivityEducation(this)) } Handler(Looper.getMainLooper()).post {
performedNextEducation()
}
return true return true
} }
private fun performedNextEducation(fileDatabaseSelectActivityEducation: FileDatabaseSelectActivityEducation) { private fun performedNextEducation() {
// If no recent files // If no recent files
val createDatabaseEducationPerformed = val createDatabaseEducationPerformed =
createDatabaseButtonView != null createDatabaseButtonView != null
&& createDatabaseButtonView!!.visibility == View.VISIBLE && createDatabaseButtonView!!.visibility == View.VISIBLE
&& mAdapterDatabaseHistory != null && mFileDatabaseSelectActivityEducation.checkAndPerformedCreateDatabaseEducation(
&& mAdapterDatabaseHistory!!.itemCount == 0
&& fileDatabaseSelectActivityEducation.checkAndPerformedCreateDatabaseEducation(
createDatabaseButtonView!!, createDatabaseButtonView!!,
{ {
createNewFile() createNewFile()
}, },
{ {
// But if the user cancel, it can also select a database // But if the user cancel, it can also select a database
performedNextEducation(fileDatabaseSelectActivityEducation) performedNextEducation()
}) })
if (!createDatabaseEducationPerformed) { if (!createDatabaseEducationPerformed) {
// selectDatabaseEducationPerformed // selectDatabaseEducationPerformed
openDatabaseButtonView != null openDatabaseButtonView != null
&& fileDatabaseSelectActivityEducation.checkAndPerformedSelectDatabaseEducation( && mFileDatabaseSelectActivityEducation.checkAndPerformedSelectDatabaseEducation(
openDatabaseButtonView!!, openDatabaseButtonView!!,
{ tapTargetView -> { tapTargetView ->
tapTargetView?.let { tapTargetView?.let {
mExternalFileHelper?.openDocument() mExternalFileHelper?.openDocument()
} }
}, },
{} {
)
})
} }
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
android.R.id.home -> UriUtil.gotoUrl(this, R.string.file_manager_explanation_url) android.R.id.home -> this.openUrl(R.string.file_manager_explanation_url)
} }
MenuUtil.onDefaultMenuOptionsItemSelected(this, item) MenuUtil.onDefaultMenuOptionsItemSelected(this, item)
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
@@ -493,11 +501,13 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(),
*/ */
@RequiresApi(api = Build.VERSION_CODES.O) @RequiresApi(api = Build.VERSION_CODES.O)
fun launchForAutofillResult(activity: Activity, fun launchForAutofillResult(activity: AppCompatActivity,
activityResultLauncher: ActivityResultLauncher<Intent>?,
autofillComponent: AutofillComponent, autofillComponent: AutofillComponent,
searchInfo: SearchInfo? = null) { searchInfo: SearchInfo? = null) {
AutofillHelper.startActivityForAutofillResult(activity, AutofillHelper.startActivityForAutofillResult(activity,
Intent(activity, FileDatabaseSelectActivity::class.java), Intent(activity, FileDatabaseSelectActivity::class.java),
activityResultLauncher,
autofillComponent, autofillComponent,
searchInfo) searchInfo)
} }

View File

@@ -27,26 +27,38 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.commit import androidx.fragment.app.commit
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.IconEditDialogFragment
import com.kunzisoft.keepass.activities.fragments.IconPickerFragment import com.kunzisoft.keepass.activities.fragments.IconPickerFragment
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImage import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageCustom import com.kunzisoft.keepass.database.element.icon.IconImageCustom
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.view.asError import com.kunzisoft.keepass.view.asError
import com.kunzisoft.keepass.view.updateLockPaddingLeft import com.kunzisoft.keepass.view.updateLockPaddingLeft
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class IconPickerActivity : DatabaseLockActivity() { class IconPickerActivity : DatabaseLockActivity() {
@@ -81,6 +93,9 @@ class IconPickerActivity : DatabaseLockActivity() {
coordinatorLayout = findViewById(R.id.icon_picker_coordinator) coordinatorLayout = findViewById(R.id.icon_picker_coordinator)
mExternalFileHelper = ExternalFileHelper(this) mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildOpenDocument { uri ->
addCustomIcon(uri)
}
uploadButton = findViewById(R.id.icon_picker_upload) uploadButton = findViewById(R.id.icon_picker_upload)
@@ -89,7 +104,7 @@ class IconPickerActivity : DatabaseLockActivity() {
lockAndExit() lockAndExit()
} }
intent?.getParcelableExtra<IconImage>(EXTRA_ICON)?.let { intent?.getParcelableExtraCompat<IconImage>(EXTRA_ICON)?.let {
mIconImage = it mIconImage = it
} }
@@ -105,7 +120,7 @@ class IconPickerActivity : DatabaseLockActivity() {
), ICON_PICKER_FRAGMENT_TAG) ), ICON_PICKER_FRAGMENT_TAG)
} }
} else { } else {
mIconImage = savedInstanceState.getParcelable(EXTRA_ICON) ?: mIconImage mIconImage = savedInstanceState.getParcelableCompat(EXTRA_ICON) ?: mIconImage
} }
iconPickerViewModel.standardIconPicked.observe(this) { iconStandard -> iconPickerViewModel.standardIconPicked.observe(this) { iconStandard ->
@@ -139,6 +154,16 @@ class IconPickerActivity : DatabaseLockActivity() {
} }
uploadButton.isEnabled = true uploadButton.isEnabled = true
} }
iconPickerViewModel.customIconUpdated.observe(this) { iconCustomUpdated ->
if (iconCustomUpdated.error && !iconCustomUpdated.errorConsumed) {
Snackbar.make(coordinatorLayout, iconCustomUpdated.errorStringId, Snackbar.LENGTH_LONG).asError().show()
iconCustomUpdated.errorConsumed = true
}
iconCustomUpdated.iconCustom?.let {
mDatabase?.updateCustomIcon(it)
}
iconPickerViewModel.deselectAllCustomIcons()
}
} }
override fun viewToInvalidateTimeout(): View? { override fun viewToInvalidateTimeout(): View? {
@@ -149,7 +174,7 @@ class IconPickerActivity : DatabaseLockActivity() {
return true return true
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
if (database?.allowCustomIcons == true) { if (database?.allowCustomIcons == true) {
@@ -197,6 +222,10 @@ class IconPickerActivity : DatabaseLockActivity() {
} }
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
menu?.findItem(R.id.menu_edit)?.apply {
isEnabled = mIconsSelected.size == 1
isVisible = isEnabled
}
menu?.findItem(R.id.menu_delete)?.apply { menu?.findItem(R.id.menu_delete)?.apply {
isEnabled = mCustomIconsSelectionMode isEnabled = mCustomIconsSelectionMode
isVisible = isEnabled isVisible = isEnabled
@@ -210,16 +239,19 @@ class IconPickerActivity : DatabaseLockActivity() {
if (mCustomIconsSelectionMode) { if (mCustomIconsSelectionMode) {
iconPickerViewModel.deselectAllCustomIcons() iconPickerViewModel.deselectAllCustomIcons()
} else { } else {
onBackPressed() onDatabaseBackPressed()
} }
} }
R.id.menu_edit -> {
updateCustomIcon(mIconsSelected[0])
}
R.id.menu_delete -> { R.id.menu_delete -> {
mIconsSelected.forEach { iconToRemove -> mIconsSelected.forEach { iconToRemove ->
removeCustomIcon(iconToRemove) removeCustomIcon(iconToRemove)
} }
} }
R.id.menu_external_icon -> { R.id.menu_external_icon -> {
UriUtil.gotoUrl(this, R.string.external_icon_url) this.openUrl(R.string.external_icon_url)
} }
} }
@@ -233,7 +265,7 @@ class IconPickerActivity : DatabaseLockActivity() {
// on Progress with thread // on Progress with thread
val asyncResult: Deferred<IconPickerViewModel.IconCustomState?> = async { val asyncResult: Deferred<IconPickerViewModel.IconCustomState?> = async {
val iconCustomState = IconPickerViewModel.IconCustomState(null, true, R.string.error_upload_file) val iconCustomState = IconPickerViewModel.IconCustomState(null, true, R.string.error_upload_file)
UriUtil.getFileData(this@IconPickerActivity, iconToUploadUri)?.also { documentFile -> iconToUploadUri?.getDocumentFile(this@IconPickerActivity)?.also { documentFile ->
if (documentFile.length() > MAX_ICON_SIZE) { if (documentFile.length() > MAX_ICON_SIZE) {
iconCustomState.errorStringId = R.string.error_file_to_big iconCustomState.errorStringId = R.string.error_file_to_big
} else { } else {
@@ -277,6 +309,11 @@ class IconPickerActivity : DatabaseLockActivity() {
} }
} }
private fun updateCustomIcon(iconImageCustom: IconImageCustom) {
IconEditDialogFragment.update(iconImageCustom)
.show(supportFragmentManager, IconEditDialogFragment.TAG_UPDATE_ICON)
}
private fun removeCustomIcon(iconImageCustom: IconImageCustom) { private fun removeCustomIcon(iconImageCustom: IconImageCustom) {
uploadButton.isEnabled = false uploadButton.isEnabled = false
iconPickerViewModel.deselectAllCustomIcons() iconPickerViewModel.deselectAllCustomIcons()
@@ -286,52 +323,42 @@ class IconPickerActivity : DatabaseLockActivity() {
) )
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri ->
addCustomIcon(uri)
}
}
private fun setResult() { private fun setResult() {
setResult(Activity.RESULT_OK, Intent().apply { setResult(Activity.RESULT_OK, Intent().apply {
putExtra(EXTRA_ICON, mIconImage) putExtra(EXTRA_ICON, mIconImage)
}) })
} }
override fun onBackPressed() { override fun onDatabaseBackPressed() {
setResult() setResult()
super.onBackPressed() super.onDatabaseBackPressed()
} }
companion object { companion object {
private const val ICON_PICKER_FRAGMENT_TAG = "ICON_PICKER_FRAGMENT_TAG" private const val ICON_PICKER_FRAGMENT_TAG = "ICON_PICKER_FRAGMENT_TAG"
private const val ICON_SELECTED_REQUEST = 15861
private const val EXTRA_ICON = "EXTRA_ICON" private const val EXTRA_ICON = "EXTRA_ICON"
private const val MAX_ICON_SIZE = 5242880 private const val MAX_ICON_SIZE = 5242880
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?, listener: (icon: IconImage) -> Unit) { fun registerIconSelectionForResult(context: FragmentActivity,
if (requestCode == ICON_SELECTED_REQUEST) { listener: (icon: IconImage) -> Unit): ActivityResultLauncher<Intent> {
if (resultCode == Activity.RESULT_OK) { return context.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
listener.invoke(data?.getParcelableExtra(EXTRA_ICON) ?: IconImage()) if (result.resultCode == Activity.RESULT_OK) {
listener.invoke(result.data?.getParcelableExtraCompat(EXTRA_ICON) ?: IconImage())
} }
} }
} }
fun launch(context: Activity, fun launch(context: FragmentActivity,
previousIcon: IconImage?) { previousIcon: IconImage?,
resultLauncher: ActivityResultLauncher<Intent>) {
// Create an instance to return the picker icon // Create an instance to return the picker icon
context.startActivityForResult( resultLauncher.launch(
Intent(context, Intent(context, IconPickerActivity::class.java).apply {
IconPickerActivity::class.java).apply {
if (previousIcon != null) if (previousIcon != null)
putExtra(EXTRA_ICON, previousIcon) putExtra(EXTRA_ICON, previousIcon)
}, }
ICON_SELECTED_REQUEST) )
} }
} }
} }

View File

@@ -33,9 +33,10 @@ import androidx.appcompat.widget.Toolbar
import com.igreenwood.loupe.Loupe import com.igreenwood.loupe.Loupe
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.tasks.BinaryDatabaseManager import com.kunzisoft.keepass.tasks.BinaryDatabaseManager
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import kotlin.math.max import kotlin.math.max
class ImageViewerActivity : DatabaseLockActivity() { class ImageViewerActivity : DatabaseLockActivity() {
@@ -100,12 +101,12 @@ class ImageViewerActivity : DatabaseLockActivity() {
return true return true
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
try { try {
progressView.visibility = View.VISIBLE progressView.visibility = View.VISIBLE
intent.getParcelableExtra<Attachment>(IMAGE_ATTACHMENT_TAG)?.let { attachment -> intent.getParcelableExtraCompat<Attachment>(IMAGE_ATTACHMENT_TAG)?.let { attachment ->
supportActionBar?.title = attachment.name supportActionBar?.title = attachment.name

View File

@@ -0,0 +1,139 @@
package com.kunzisoft.keepass.activities
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.commit
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.fragments.KeyGeneratorFragment
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.view.updateLockPaddingLeft
import com.kunzisoft.keepass.viewmodels.KeyGeneratorViewModel
class KeyGeneratorActivity : DatabaseLockActivity() {
private lateinit var toolbar: Toolbar
private lateinit var coordinatorLayout: CoordinatorLayout
private lateinit var validationButton: View
private var lockView: View? = null
private val keyGeneratorViewModel: KeyGeneratorViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_key_generator)
toolbar = findViewById(R.id.toolbar)
toolbar.title = " "
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
coordinatorLayout = findViewById(R.id.key_generator_coordinator)
lockView = findViewById(R.id.lock_button)
lockView?.setOnClickListener {
lockAndExit()
}
validationButton = findViewById(R.id.key_generator_validation)
validationButton.setOnClickListener {
keyGeneratorViewModel.validateKeyGenerated()
}
supportFragmentManager.commit {
replace(R.id.key_generator_fragment, KeyGeneratorFragment.getInstance(
// Default selection tab
KeyGeneratorFragment.KeyGeneratorTab.PASSWORD
), KEY_GENERATED_FRAGMENT_TAG
)
}
keyGeneratorViewModel.keyGenerated.observe(this) { keyGenerated ->
setResult(Activity.RESULT_OK, Intent().apply {
putExtra(KEY_GENERATED, keyGenerated)
})
finish()
}
}
override fun viewToInvalidateTimeout(): View? {
return findViewById<ViewGroup>(R.id.key_generator_container)
}
override fun onResume() {
super.onResume()
// Show the lock button
lockView?.visibility = if (PreferencesUtil.showLockDatabaseButton(this)) {
View.VISIBLE
} else {
View.GONE
}
// Padding if lock button visible
toolbar.updateLockPaddingLeft()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.key_generator, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
onDatabaseBackPressed()
}
R.id.menu_generate -> {
keyGeneratorViewModel.requireKeyGeneration()
}
}
return super.onOptionsItemSelected(item)
}
override fun onDatabaseBackPressed() {
setResult(Activity.RESULT_CANCELED, Intent())
super.onDatabaseBackPressed()
}
companion object {
private const val KEY_GENERATED = "KEY_GENERATED"
private const val KEY_GENERATED_FRAGMENT_TAG = "KEY_GENERATED_FRAGMENT_TAG"
fun registerForGeneratedKeyResult(activity: FragmentActivity,
keyGeneratedListener: (String?) -> Unit): ActivityResultLauncher<Intent> {
return activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
keyGeneratedListener.invoke(
result.data?.getStringExtra(KEY_GENERATED)
)
} else {
keyGeneratedListener.invoke(null)
}
}
}
fun launch(context: FragmentActivity,
resultLauncher: ActivityResultLauncher<Intent>) {
// Create an instance to return the picker icon
resultLauncher.launch(
Intent(context, KeyGeneratorActivity::class.java)
)
}
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2020 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.activities
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.search.SearchHelper
/**
* Activity to select entry in database and populate it in Magikeyboard
*/
class MagikeyboardLauncherActivity : DatabaseModeActivity() {
override fun applyCustomStyle(): Boolean {
return false
}
override fun finishActivityIfReloadRequested(): Boolean {
return true
}
override fun onDatabaseRetrieved(database: Database?) {
super.onDatabaseRetrieved(database)
SearchHelper.checkAutoSearchInfo(this,
database,
null,
{ _, _ ->
// Not called
// if items found directly returns before calling this activity
},
{ openedDatabase ->
// Select if not found
GroupActivity.launchForKeyboardSelectionResult(this, openedDatabase)
},
{
// Pass extra to get entry
FileDatabaseSelectActivity.launchForKeyboardSelectionResult(this)
}
)
finish()
}
}

View File

@@ -1,314 +0,0 @@
/*
* Copyright 2019 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.activities.dialogs
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.text.SpannableStringBuilder
import android.text.TextWatcher
import android.view.View
import android.widget.CompoundButton
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener
import com.kunzisoft.keepass.model.MainCredential
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.view.KeyFileSelectionView
class AssignMasterKeyDialogFragment : DatabaseDialogFragment() {
private var mMasterPassword: String? = null
private var mKeyFile: Uri? = null
private var rootView: View? = null
private var passwordCheckBox: CompoundButton? = null
private var passwordTextInputLayout: TextInputLayout? = null
private var passwordView: TextView? = null
private var passwordRepeatTextInputLayout: TextInputLayout? = null
private var passwordRepeatView: TextView? = null
private var keyFileCheckBox: CompoundButton? = null
private var keyFileSelectionView: KeyFileSelectionView? = null
private var mListener: AssignPasswordDialogListener? = null
private var mExternalFileHelper: ExternalFileHelper? = null
private var mEmptyPasswordConfirmationDialog: AlertDialog? = null
private var mNoKeyConfirmationDialog: AlertDialog? = null
private var mEmptyKeyFileConfirmationDialog: AlertDialog? = null
private val passwordTextWatcher = object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
passwordCheckBox?.isChecked = true
}
}
interface AssignPasswordDialogListener {
fun onAssignKeyDialogPositiveClick(mainCredential: MainCredential)
fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential)
}
override fun onAttach(activity: Context) {
super.onAttach(activity)
try {
mListener = activity as AssignPasswordDialogListener
} catch (e: ClassCastException) {
throw ClassCastException(activity.toString()
+ " must implement " + AssignPasswordDialogListener::class.java.name)
}
}
override fun onDetach() {
mListener = null
mEmptyPasswordConfirmationDialog?.dismiss()
mEmptyPasswordConfirmationDialog = null
mNoKeyConfirmationDialog?.dismiss()
mNoKeyConfirmationDialog = null
mEmptyKeyFileConfirmationDialog?.dismiss()
mEmptyKeyFileConfirmationDialog = null
super.onDetach()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
var allowNoMasterKey = false
arguments?.apply {
if (containsKey(ALLOW_NO_MASTER_KEY_ARG))
allowNoMasterKey = getBoolean(ALLOW_NO_MASTER_KEY_ARG, false)
}
val builder = AlertDialog.Builder(activity)
val inflater = activity.layoutInflater
rootView = inflater.inflate(R.layout.fragment_set_password, null)
builder.setView(rootView)
// Add action buttons
.setPositiveButton(android.R.string.ok) { _, _ -> }
.setNegativeButton(android.R.string.cancel) { _, _ -> }
rootView?.findViewById<View>(R.id.credentials_information)?.setOnClickListener {
UriUtil.gotoUrl(activity, R.string.credentials_explanation_url)
}
passwordCheckBox = rootView?.findViewById(R.id.password_checkbox)
passwordTextInputLayout = rootView?.findViewById(R.id.password_input_layout)
passwordView = rootView?.findViewById(R.id.pass_password)
passwordRepeatTextInputLayout = rootView?.findViewById(R.id.password_repeat_input_layout)
passwordRepeatView = rootView?.findViewById(R.id.pass_conf_password)
keyFileCheckBox = rootView?.findViewById(R.id.keyfile_checkox)
keyFileSelectionView = rootView?.findViewById(R.id.keyfile_selection)
mExternalFileHelper = ExternalFileHelper(this)
keyFileSelectionView?.setOpenDocumentClickListener(mExternalFileHelper)
val dialog = builder.create()
if (passwordCheckBox != null && keyFileCheckBox!= null) {
dialog.setOnShowListener { dialog1 ->
val positiveButton = (dialog1 as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE)
positiveButton.setOnClickListener {
mMasterPassword = ""
mKeyFile = null
var error = verifyPassword() || verifyKeyFile()
if (!passwordCheckBox!!.isChecked && !keyFileCheckBox!!.isChecked) {
error = true
if (allowNoMasterKey)
showNoKeyConfirmationDialog()
else {
passwordTextInputLayout?.error = getString(R.string.error_disallow_no_credentials)
}
}
if (!error) {
mListener?.onAssignKeyDialogPositiveClick(retrieveMainCredential())
dismiss()
}
}
val negativeButton = dialog1.getButton(DialogInterface.BUTTON_NEGATIVE)
negativeButton.setOnClickListener {
mListener?.onAssignKeyDialogNegativeClick(retrieveMainCredential())
dismiss()
}
}
}
return dialog
}
return super.onCreateDialog(savedInstanceState)
}
private fun retrieveMainCredential(): MainCredential {
val masterPassword = if (passwordCheckBox!!.isChecked) mMasterPassword else null
val keyFile = if (keyFileCheckBox!!.isChecked) mKeyFile else null
return MainCredential(masterPassword, keyFile)
}
override fun onResume() {
super.onResume()
// To check checkboxes if a text is present
passwordView?.addTextChangedListener(passwordTextWatcher)
}
override fun onPause() {
super.onPause()
passwordView?.removeTextChangedListener(passwordTextWatcher)
}
private fun verifyPassword(): Boolean {
var error = false
if (passwordCheckBox != null
&& passwordCheckBox!!.isChecked
&& passwordView != null
&& passwordRepeatView != null) {
mMasterPassword = passwordView!!.text.toString()
val confPassword = passwordRepeatView!!.text.toString()
// Verify that passwords match
if (mMasterPassword != confPassword) {
error = true
// Passwords do not match
passwordRepeatTextInputLayout?.error = getString(R.string.error_pass_match)
}
if (mMasterPassword == null || mMasterPassword!!.isEmpty()) {
error = true
showEmptyPasswordConfirmationDialog()
}
}
return error
}
private fun verifyKeyFile(): Boolean {
var error = false
if (keyFileCheckBox != null
&& keyFileCheckBox!!.isChecked) {
keyFileSelectionView?.uri?.let { uri ->
mKeyFile = uri
} ?: run {
error = true
keyFileSelectionView?.error = getString(R.string.error_nokeyfile)
}
}
return error
}
private fun showEmptyPasswordConfirmationDialog() {
activity?.let {
val builder = AlertDialog.Builder(it)
builder.setMessage(R.string.warning_empty_password)
.setPositiveButton(android.R.string.ok) { _, _ ->
if (!verifyKeyFile()) {
mListener?.onAssignKeyDialogPositiveClick(retrieveMainCredential())
this@AssignMasterKeyDialogFragment.dismiss()
}
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
mEmptyPasswordConfirmationDialog = builder.create()
mEmptyPasswordConfirmationDialog?.show()
}
}
private fun showNoKeyConfirmationDialog() {
activity?.let {
val builder = AlertDialog.Builder(it)
builder.setMessage(R.string.warning_no_encryption_key)
.setPositiveButton(android.R.string.ok) { _, _ ->
mListener?.onAssignKeyDialogPositiveClick(retrieveMainCredential())
this@AssignMasterKeyDialogFragment.dismiss()
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
mNoKeyConfirmationDialog = builder.create()
mNoKeyConfirmationDialog?.show()
}
}
private fun showEmptyKeyFileConfirmationDialog() {
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
}
mEmptyKeyFileConfirmationDialog = builder.create()
mEmptyKeyFileConfirmationDialog?.show()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
mExternalFileHelper?.onOpenDocumentResult(requestCode, resultCode, data) { uri ->
uri?.let { pathUri ->
UriUtil.getFileData(requireContext(), uri)?.length()?.let { lengthFile ->
keyFileSelectionView?.error = null
keyFileCheckBox?.isChecked = true
keyFileSelectionView?.uri = pathUri
if (lengthFile <= 0L) {
showEmptyKeyFileConfirmationDialog()
}
}
}
}
}
companion object {
private const val ALLOW_NO_MASTER_KEY_ARG = "ALLOW_NO_MASTER_KEY_ARG"
fun getInstance(allowNoMasterKey: Boolean): AssignMasterKeyDialogFragment {
val fragment = AssignMasterKeyDialogFragment()
val args = Bundle()
args.putBoolean(ALLOW_NO_MASTER_KEY_ARG, allowNoMasterKey)
fragment.arguments = args
return fragment
}
}
}

View File

@@ -0,0 +1,95 @@
package com.kunzisoft.keepass.activities.dialogs
import android.app.Dialog
import android.graphics.Color
import android.os.Bundle
import android.widget.CompoundButton
import androidx.annotation.ColorInt
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
import com.kunzisoft.androidclearchroma.view.ChromaColorView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.viewmodels.ColorPickerViewModel
class ColorPickerDialogFragment : DatabaseDialogFragment() {
private val mColorPickerViewModel: ColorPickerViewModel by activityViewModels()
private lateinit var enableSwitchView: CompoundButton
private lateinit var chromaColorView: ChromaColorView
private var mDefaultColor = Color.WHITE
private var mActivated = false
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
val root = activity.layoutInflater.inflate(R.layout.fragment_color_picker, null)
enableSwitchView = root.findViewById(R.id.switch_element)
chromaColorView = root.findViewById(R.id.chroma_color_view)
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(ARG_INITIAL_COLOR)) {
mDefaultColor = savedInstanceState.getInt(ARG_INITIAL_COLOR)
}
if (savedInstanceState.containsKey(ARG_ACTIVATED)) {
mActivated = savedInstanceState.getBoolean(ARG_ACTIVATED)
}
} else {
arguments?.apply {
if (containsKey(ARG_INITIAL_COLOR)) {
mDefaultColor = getInt(ARG_INITIAL_COLOR)
}
if (containsKey(ARG_ACTIVATED)) {
mActivated = getBoolean(ARG_ACTIVATED)
}
}
}
enableSwitchView.isChecked = mActivated
chromaColorView.currentColor = mDefaultColor
chromaColorView.setOnColorChangedListener {
if (!enableSwitchView.isChecked)
enableSwitchView.isChecked = true
}
val builder = AlertDialog.Builder(activity)
builder.setView(root)
.setPositiveButton(android.R.string.ok) { _, _ ->
val color: Int? = if (enableSwitchView.isChecked)
chromaColorView.currentColor
else
null
mColorPickerViewModel.pickColor(color)
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
// Do nothing
}
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(ARG_INITIAL_COLOR, chromaColorView.currentColor)
outState.putBoolean(ARG_ACTIVATED, mActivated)
}
companion object {
private const val ARG_INITIAL_COLOR = "ARG_INITIAL_COLOR"
private const val ARG_ACTIVATED = "ARG_ACTIVATED"
fun newInstance(
@ColorInt initialColor: Int?,
): ColorPickerDialogFragment {
return ColorPickerDialogFragment().apply {
arguments = Bundle().apply {
putInt(ARG_INITIAL_COLOR, initialColor ?: Color.WHITE)
putBoolean(ARG_ACTIVATED, initialColor != null)
}
}
}
}
}

View File

@@ -25,6 +25,7 @@ import android.text.SpannableStringBuilder
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
import com.kunzisoft.keepass.utils.getParcelableCompat
class DatabaseChangedDialogFragment : DatabaseDialogFragment() { class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
@@ -40,8 +41,8 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity -> activity?.let { activity ->
val oldSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelable(OLD_FILE_DATABASE_INFO) val oldSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelableCompat(OLD_FILE_DATABASE_INFO)
val newSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelable(NEW_FILE_DATABASE_INFO) val newSnapFileDatabaseInfo: SnapFileDatabaseInfo? = arguments?.getParcelableCompat(NEW_FILE_DATABASE_INFO)
if (oldSnapFileDatabaseInfo != null && newSnapFileDatabaseInfo != null) { if (oldSnapFileDatabaseInfo != null && newSnapFileDatabaseInfo != null) {
// Use the Builder class for convenient dialog construction // Use the Builder class for convenient dialog construction
@@ -78,7 +79,8 @@ class DatabaseChangedDialogFragment : DatabaseDialogFragment() {
private const val NEW_FILE_DATABASE_INFO = "NEW_FILE_DATABASE_INFO" private const val NEW_FILE_DATABASE_INFO = "NEW_FILE_DATABASE_INFO"
fun getInstance(oldSnapFileDatabaseInfo: SnapFileDatabaseInfo, fun getInstance(oldSnapFileDatabaseInfo: SnapFileDatabaseInfo,
newSnapFileDatabaseInfo: SnapFileDatabaseInfo) newSnapFileDatabaseInfo: SnapFileDatabaseInfo
)
: DatabaseChangedDialogFragment { : DatabaseChangedDialogFragment {
val fragment = DatabaseChangedDialogFragment() val fragment = DatabaseChangedDialogFragment()
fragment.arguments = Bundle().apply { fragment.arguments = Bundle().apply {

View File

@@ -5,7 +5,7 @@ import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.timeout.TimeoutHelper import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
@@ -13,7 +13,7 @@ import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval { abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels() private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
private var mDatabase: Database? = null private var mDatabase: ContextualDatabase? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -29,18 +29,19 @@ abstract class DatabaseDialogFragment : DialogFragment(), DatabaseRetrieval {
} }
} }
@Suppress("DEPRECATION")
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
resetAppTimeoutOnTouchOrFocus() resetAppTimeoutOnTouchOrFocus()
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Can be overridden by a subclass // Can be overridden by a subclass
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {

View File

@@ -1,67 +0,0 @@
package com.kunzisoft.keepass.activities.dialogs
import android.app.DatePickerDialog
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.DialogFragment
// Not as DatabaseDialogFragment because crash on KitKat
class DatePickerFragment : DialogFragment() {
private var mDefaultYear: Int = 2000
private var mDefaultMonth: Int = 1
private var mDefaultDay: Int = 1
private var mListener: DatePickerDialog.OnDateSetListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
try {
mListener = context as DatePickerDialog.OnDateSetListener
} catch (e: ClassCastException) {
throw ClassCastException(context.toString()
+ " must implement " + DatePickerDialog.OnDateSetListener::class.java.name)
}
}
override fun onDetach() {
mListener = null
super.onDetach()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Create a new instance of DatePickerDialog and return it
return context?.let {
arguments?.apply {
if (containsKey(DEFAULT_YEAR_BUNDLE_KEY))
mDefaultYear = getInt(DEFAULT_YEAR_BUNDLE_KEY)
if (containsKey(DEFAULT_MONTH_BUNDLE_KEY))
mDefaultMonth = getInt(DEFAULT_MONTH_BUNDLE_KEY)
if (containsKey(DEFAULT_DAY_BUNDLE_KEY))
mDefaultDay = getInt(DEFAULT_DAY_BUNDLE_KEY)
}
DatePickerDialog(it, mListener, mDefaultYear, mDefaultMonth, mDefaultDay)
} ?: super.onCreateDialog(savedInstanceState)
}
companion object {
private const val DEFAULT_YEAR_BUNDLE_KEY = "DEFAULT_YEAR_BUNDLE_KEY"
private const val DEFAULT_MONTH_BUNDLE_KEY = "DEFAULT_MONTH_BUNDLE_KEY"
private const val DEFAULT_DAY_BUNDLE_KEY = "DEFAULT_DAY_BUNDLE_KEY"
fun getInstance(defaultYear: Int,
defaultMonth: Int,
defaultDay: Int): DatePickerFragment {
return DatePickerFragment().apply {
arguments = Bundle().apply {
putInt(DEFAULT_YEAR_BUNDLE_KEY, defaultYear)
putInt(DEFAULT_MONTH_BUNDLE_KEY, defaultMonth)
putInt(DEFAULT_DAY_BUNDLE_KEY, defaultDay)
}
}
}
}
}

View File

@@ -35,6 +35,7 @@ import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Field import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.database.element.security.ProtectedString import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.utils.getParcelableCompat
class EntryCustomFieldDialogFragment: DatabaseDialogFragment() { class EntryCustomFieldDialogFragment: DatabaseDialogFragment() {
@@ -72,7 +73,7 @@ class EntryCustomFieldDialogFragment: DatabaseDialogFragment() {
customFieldDeleteButton = root?.findViewById(R.id.entry_custom_field_delete) customFieldDeleteButton = root?.findViewById(R.id.entry_custom_field_delete)
customFieldProtectionButton = root?.findViewById(R.id.entry_custom_field_protection) customFieldProtectionButton = root?.findViewById(R.id.entry_custom_field_protection)
oldField = arguments?.getParcelable(KEY_FIELD) oldField = arguments?.getParcelableCompat(KEY_FIELD)
oldField?.let { oldCustomField -> oldField?.let { oldCustomField ->
customFieldLabel?.text = oldCustomField.name customFieldLabel?.text = oldCustomField.name
customFieldProtectionButton?.isChecked = oldCustomField.protectedValue.isProtected customFieldProtectionButton?.isChecked = oldCustomField.protectedValue.isProtected

View File

@@ -21,12 +21,12 @@ package com.kunzisoft.keepass.activities.dialogs
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.appcompat.app.AlertDialog
import android.widget.Button import android.widget.Button
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil.openUrl
class FileManagerDialogFragment : DialogFragment() { class FileManagerDialogFragment : DialogFragment() {
@@ -42,7 +42,7 @@ class FileManagerDialogFragment : DialogFragment() {
textDescription.text = getString(R.string.file_manager_install_description) textDescription.text = getString(R.string.file_manager_install_description)
root.findViewById<Button>(R.id.file_manager_button).setOnClickListener { root.findViewById<Button>(R.id.file_manager_button).setOnClickListener {
UriUtil.gotoUrl(requireContext(), R.string.file_manager_explanation_url) context?.openUrl(R.string.file_manager_explanation_url)
dismiss() dismiss()
} }

View File

@@ -27,6 +27,7 @@ import android.text.SpannableStringBuilder
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.getParcelableCompat
/** /**
* Custom Dialog to confirm big file to upload * Custom Dialog to confirm big file to upload
@@ -62,7 +63,7 @@ class FileTooBigDialogFragment : DialogFragment() {
}) })
builder.setPositiveButton(android.R.string.ok) { _, _ -> builder.setPositiveButton(android.R.string.ok) { _, _ ->
mActionChooseListener?.onValidateUploadFileTooBig( mActionChooseListener?.onValidateUploadFileTooBig(
arguments?.getParcelable(KEY_FILE_URI), arguments?.getParcelableCompat(KEY_FILE_URI),
arguments?.getString(KEY_FILE_NAME)) arguments?.getString(KEY_FILE_NAME))
} }
builder.setNegativeButton(android.R.string.cancel) { _, _ -> builder.setNegativeButton(android.R.string.cancel) { _, _ ->

View File

@@ -1,224 +0,0 @@
/*
* Copyright 2019 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.activities.dialogs
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Field
import com.kunzisoft.keepass.password.PasswordGenerator
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.view.applyFontVisibility
class GeneratePasswordDialogFragment : DatabaseDialogFragment() {
private var mListener: GeneratePasswordListener? = null
private var root: View? = null
private var lengthTextView: EditText? = null
private var passwordInputLayoutView: TextInputLayout? = null
private var passwordView: EditText? = null
private var mPasswordField: Field? = null
private var uppercaseBox: CompoundButton? = null
private var lowercaseBox: CompoundButton? = null
private var digitsBox: CompoundButton? = null
private var minusBox: CompoundButton? = null
private var underlineBox: CompoundButton? = null
private var spaceBox: CompoundButton? = null
private var specialsBox: CompoundButton? = null
private var bracketsBox: CompoundButton? = null
private var extendedBox: CompoundButton? = null
override fun onAttach(context: Context) {
super.onAttach(context)
try {
mListener = context as GeneratePasswordListener
} catch (e: ClassCastException) {
throw ClassCastException(context.toString()
+ " must implement " + GeneratePasswordListener::class.java.name)
}
}
override fun onDetach() {
mListener = null
super.onDetach()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
val builder = AlertDialog.Builder(activity)
val inflater = activity.layoutInflater
root = inflater.inflate(R.layout.fragment_generate_password, null)
passwordInputLayoutView = root?.findViewById(R.id.password_input_layout)
passwordView = root?.findViewById(R.id.password)
passwordView?.applyFontVisibility()
val passwordCopyView: ImageView? = root?.findViewById(R.id.password_copy_button)
passwordCopyView?.visibility = if(PreferencesUtil.allowCopyProtectedFields(activity))
View.VISIBLE else View.GONE
val clipboardHelper = ClipboardHelper(activity)
passwordCopyView?.setOnClickListener {
clipboardHelper.timeoutCopyToClipboard(passwordView!!.text.toString(),
getString(R.string.copy_field,
getString(R.string.entry_password)))
}
lengthTextView = root?.findViewById(R.id.length)
uppercaseBox = root?.findViewById(R.id.cb_uppercase)
lowercaseBox = root?.findViewById(R.id.cb_lowercase)
digitsBox = root?.findViewById(R.id.cb_digits)
minusBox = root?.findViewById(R.id.cb_minus)
underlineBox = root?.findViewById(R.id.cb_underline)
spaceBox = root?.findViewById(R.id.cb_space)
specialsBox = root?.findViewById(R.id.cb_specials)
bracketsBox = root?.findViewById(R.id.cb_brackets)
extendedBox = root?.findViewById(R.id.cb_extended)
mPasswordField = arguments?.getParcelable(KEY_PASSWORD_FIELD)
assignDefaultCharacters()
val seekBar = root?.findViewById<SeekBar>(R.id.seekbar_length)
seekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
lengthTextView?.setText(progress.toString())
}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {}
})
context?.let { context ->
seekBar?.progress = PreferencesUtil.getDefaultPasswordLength(context)
}
root?.findViewById<Button>(R.id.generate_password_button)
?.setOnClickListener { fillPassword() }
builder.setView(root)
.setPositiveButton(R.string.accept) { _, _ ->
mPasswordField?.let { passwordField ->
passwordView?.text?.toString()?.let { passwordValue ->
passwordField.protectedValue.stringValue = passwordValue
}
mListener?.acceptPassword(passwordField)
}
dismiss()
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
mPasswordField?.let { passwordField ->
mListener?.cancelPassword(passwordField)
}
dismiss()
}
// Pre-populate a password to possibly save the user a few clicks
fillPassword()
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
private fun assignDefaultCharacters() {
uppercaseBox?.isChecked = false
lowercaseBox?.isChecked = false
digitsBox?.isChecked = false
minusBox?.isChecked = false
underlineBox?.isChecked = false
spaceBox?.isChecked = false
specialsBox?.isChecked = false
bracketsBox?.isChecked = false
extendedBox?.isChecked = false
context?.let { context ->
PreferencesUtil.getDefaultPasswordCharacters(context)?.let { charSet ->
for (passwordChar in charSet) {
when (passwordChar) {
getString(R.string.value_password_uppercase) -> uppercaseBox?.isChecked = true
getString(R.string.value_password_lowercase) -> lowercaseBox?.isChecked = true
getString(R.string.value_password_digits) -> digitsBox?.isChecked = true
getString(R.string.value_password_minus) -> minusBox?.isChecked = true
getString(R.string.value_password_underline) -> underlineBox?.isChecked = true
getString(R.string.value_password_space) -> spaceBox?.isChecked = true
getString(R.string.value_password_special) -> specialsBox?.isChecked = true
getString(R.string.value_password_brackets) -> bracketsBox?.isChecked = true
getString(R.string.value_password_extended) -> extendedBox?.isChecked = true
}
}
}
}
}
private fun fillPassword() {
root?.findViewById<EditText>(R.id.password)?.setText(generatePassword())
}
fun generatePassword(): String {
var password = ""
try {
val length = Integer.valueOf(root?.findViewById<EditText>(R.id.length)?.text.toString())
password = PasswordGenerator(resources).generatePassword(length,
uppercaseBox?.isChecked == true,
lowercaseBox?.isChecked == true,
digitsBox?.isChecked == true,
minusBox?.isChecked == true,
underlineBox?.isChecked == true,
spaceBox?.isChecked == true,
specialsBox?.isChecked == true,
bracketsBox?.isChecked == true,
extendedBox?.isChecked == true)
passwordInputLayoutView?.error = null
} catch (e: NumberFormatException) {
passwordInputLayoutView?.error = getString(R.string.error_wrong_length)
} catch (e: IllegalArgumentException) {
passwordInputLayoutView?.error = e.message
}
return password
}
interface GeneratePasswordListener {
fun acceptPassword(passwordField: Field)
fun cancelPassword(passwordField: Field)
}
companion object {
private const val KEY_PASSWORD_FIELD = "KEY_PASSWORD_FIELD"
fun getInstance(field: Field): GeneratePasswordDialogFragment {
return GeneratePasswordDialogFragment().apply {
arguments = Bundle().apply {
putParcelable(KEY_PASSWORD_FIELD, field)
}
}
}
}
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright 2021 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.activities.dialogs
import android.app.Dialog
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.TagsAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
import com.kunzisoft.keepass.utils.UuidUtil
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.view.DateTimeFieldView
class GroupDialogFragment : DatabaseDialogFragment() {
private var mPopulateIconMethod: ((ImageView, IconImage) -> Unit)? = null
private var mGroupInfo = GroupInfo()
private lateinit var iconView: ImageView
private var mIconColor: Int = 0
private lateinit var nameTextView: TextView
private lateinit var tagsListView: RecyclerView
private var tagsAdapter: TagsAdapter? = null
private lateinit var notesTextLabelView: TextView
private lateinit var notesTextView: TextView
private lateinit var expirationView: DateTimeFieldView
private lateinit var creationView: TextView
private lateinit var modificationView: TextView
private lateinit var searchableLabelView: TextView
private lateinit var searchableView: TextView
private lateinit var autoTypeLabelView: TextView
private lateinit var autoTypeView: TextView
private lateinit var uuidContainerView: ViewGroup
private lateinit var uuidReferenceView: TextView
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mPopulateIconMethod = { imageView, icon ->
database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor)
}
mPopulateIconMethod?.invoke(iconView, mGroupInfo.icon)
if (database?.allowCustomSearchableGroup() == true) {
searchableLabelView.visibility = View.VISIBLE
searchableView.visibility = View.VISIBLE
} else {
searchableLabelView.visibility = View.GONE
searchableView.visibility = View.GONE
}
// TODO Auto-Type
/*
if (database?.allowAutoType() == true) {
autoTypeLabelView.visibility = View.VISIBLE
autoTypeView.visibility = View.VISIBLE
} else {
autoTypeLabelView.visibility = View.GONE
autoTypeView.visibility = View.GONE
}
*/
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
val root = activity.layoutInflater.inflate(R.layout.fragment_group, null)
iconView = root.findViewById(R.id.group_icon)
nameTextView = root.findViewById(R.id.group_name)
tagsListView = root.findViewById(R.id.group_tags_list_view)
notesTextLabelView = root.findViewById(R.id.group_note_label)
notesTextView = root.findViewById(R.id.group_note)
expirationView = root.findViewById(R.id.group_expiration)
creationView = root.findViewById(R.id.group_created)
modificationView = root.findViewById(R.id.group_modified)
searchableLabelView = root.findViewById(R.id.group_searchable_label)
searchableView = root.findViewById(R.id.group_searchable)
autoTypeLabelView = root.findViewById(R.id.group_auto_type_label)
autoTypeView = root.findViewById(R.id.group_auto_type)
uuidContainerView = root.findViewById(R.id.group_UUID_container)
uuidReferenceView = root.findViewById(R.id.group_UUID_reference)
// Retrieve the textColor to tint the icon
val ta = activity.theme.obtainStyledAttributes(intArrayOf(R.attr.colorSecondary))
mIconColor = ta.getColor(0, Color.WHITE)
ta.recycle()
if (savedInstanceState != null
&& savedInstanceState.containsKey(KEY_GROUP_INFO)) {
mGroupInfo = savedInstanceState.getParcelableCompat(KEY_GROUP_INFO) ?: mGroupInfo
} else {
arguments?.apply {
if (containsKey(KEY_GROUP_INFO)) {
mGroupInfo = getParcelableCompat(KEY_GROUP_INFO) ?: mGroupInfo
}
}
}
// populate info in views
val title = mGroupInfo.title
if (title.isEmpty()) {
nameTextView.visibility = View.GONE
} else {
nameTextView.text = title
nameTextView.visibility = View.VISIBLE
}
tagsAdapter = TagsAdapter(activity)
tagsListView.apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = tagsAdapter
}
val tags = mGroupInfo.tags
tagsListView.visibility = if (tags.isEmpty()) View.GONE else View.VISIBLE
tagsAdapter?.setTags(tags)
val notes = mGroupInfo.notes
if (notes == null || notes.isEmpty()) {
notesTextLabelView.visibility = View.GONE
notesTextView.visibility = View.GONE
} else {
notesTextView.text = notes
notesTextLabelView.visibility = View.VISIBLE
notesTextView.visibility = View.VISIBLE
}
expirationView.activation = mGroupInfo.expires
expirationView.dateTime = mGroupInfo.expiryTime
creationView.text = mGroupInfo.creationTime.getDateTimeString(resources)
modificationView.text = mGroupInfo.lastModificationTime.getDateTimeString(resources)
searchableView.text = stringFromInheritableBoolean(mGroupInfo.searchable)
autoTypeView.text = stringFromInheritableBoolean(mGroupInfo.enableAutoType,
mGroupInfo.defaultAutoTypeSequence)
val uuid = UuidUtil.toHexString(mGroupInfo.id)
if (uuid == null || uuid.isEmpty()) {
uuidContainerView.visibility = View.GONE
} else {
uuidReferenceView.text = uuid
uuidContainerView.apply {
visibility = if (PreferencesUtil.showUUID(context)) View.VISIBLE else View.GONE
}
}
val builder = AlertDialog.Builder(activity)
builder.setView(root)
.setPositiveButton(android.R.string.ok){ _, _ ->
// Do nothing
}
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
private fun stringFromInheritableBoolean(enable: Boolean?, value: String? = null): String {
val valueString = if (value != null && value.isNotEmpty()) " [$value]" else ""
return when {
enable == null -> getString(R.string.inherited) + valueString
enable -> getString(R.string.enable) + valueString
else -> getString(R.string.disable)
}
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putParcelable(KEY_GROUP_INFO, mGroupInfo)
super.onSaveInstanceState(outState)
}
data class Error(val isError: Boolean, val messageId: Int?)
companion object {
const val TAG_SHOW_GROUP = "TAG_SHOW_GROUP"
private const val KEY_GROUP_INFO = "KEY_GROUP_INFO"
fun launch(groupInfo: GroupInfo): GroupDialogFragment {
val bundle = Bundle()
bundle.putParcelable(KEY_GROUP_INFO, groupInfo)
val fragment = GroupDialogFragment()
fragment.arguments = bundle
return fragment
}
}
}

View File

@@ -23,6 +23,7 @@ import android.app.Dialog
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
@@ -30,13 +31,20 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.* import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.CREATION
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.NONE
import com.kunzisoft.keepass.activities.dialogs.GroupEditDialogFragment.EditGroupDialogAction.UPDATE
import com.kunzisoft.keepass.adapters.TagsProposalAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.DateInstant import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.icon.IconImage import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.model.GroupInfo import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.view.DateTimeEditFieldView import com.kunzisoft.keepass.view.DateTimeEditFieldView
import com.kunzisoft.keepass.view.InheritedCompletionView
import com.kunzisoft.keepass.view.TagsCompletionView
import com.kunzisoft.keepass.viewmodels.GroupEditViewModel import com.kunzisoft.keepass.viewmodels.GroupEditViewModel
import com.tokenautocomplete.FilteredArrayAdapter
import org.joda.time.DateTime import org.joda.time.DateTime
class GroupEditDialogFragment : DatabaseDialogFragment() { class GroupEditDialogFragment : DatabaseDialogFragment() {
@@ -55,6 +63,14 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
private lateinit var notesTextLayoutView: TextInputLayout private lateinit var notesTextLayoutView: TextInputLayout
private lateinit var notesTextView: TextView private lateinit var notesTextView: TextView
private lateinit var expirationView: DateTimeEditFieldView private lateinit var expirationView: DateTimeEditFieldView
private lateinit var searchableContainerView: TextInputLayout
private lateinit var searchableView: InheritedCompletionView
private lateinit var autoTypeContainerView: ViewGroup
private lateinit var autoTypeInheritedView: InheritedCompletionView
private lateinit var autoTypeSequenceView: TextView
private lateinit var tagsContainerView: TextInputLayout
private lateinit var tagsCompletionView: TagsCompletionView
private var tagsAdapter: FilteredArrayAdapter<String>? = null
enum class EditGroupDialogAction { enum class EditGroupDialogAction {
CREATION, UPDATE, NONE; CREATION, UPDATE, NONE;
@@ -74,13 +90,11 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
mPopulateIconMethod?.invoke(iconButtonView, mGroupInfo.icon) mPopulateIconMethod?.invoke(iconButtonView, mGroupInfo.icon)
} }
mGroupEditViewModel.onDateSelected.observe(this) { viewModelDate -> mGroupEditViewModel.onDateSelected.observe(this) { dateMilliseconds ->
// Save the date // Save the date
mGroupInfo.expiryTime = DateInstant( mGroupInfo.expiryTime = DateInstant(
DateTime(mGroupInfo.expiryTime.date) DateTime(mGroupInfo.expiryTime.date)
.withYear(viewModelDate.year) .withMillis(dateMilliseconds)
.withMonthOfYear(viewModelDate.month + 1)
.withDayOfMonth(viewModelDate.day)
.toDate()) .toDate())
expirationView.dateTime = mGroupInfo.expiryTime expirationView.dateTime = mGroupInfo.expiryTime
if (expirationView.dateTime.type == DateInstant.Type.DATE_TIME) { if (expirationView.dateTime.type == DateInstant.Type.DATE_TIME) {
@@ -105,12 +119,32 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
} }
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
mPopulateIconMethod = { imageView, icon -> mPopulateIconMethod = { imageView, icon ->
database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor) database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor)
} }
mPopulateIconMethod?.invoke(iconButtonView, mGroupInfo.icon) mPopulateIconMethod?.invoke(iconButtonView, mGroupInfo.icon)
searchableContainerView.visibility = if (database?.allowCustomSearchableGroup() == true) {
View.VISIBLE
} else {
View.GONE
}
if (database?.allowAutoType() == true) {
autoTypeContainerView.visibility = View.VISIBLE
} else {
autoTypeContainerView.visibility = View.GONE
}
tagsAdapter = TagsProposalAdapter(requireContext(), database?.tagPool)
tagsCompletionView.apply {
threshold = 1
setAdapter(tagsAdapter)
}
tagsContainerView.visibility = if (database?.allowTags() == true) View.VISIBLE else View.GONE
} }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
@@ -122,6 +156,13 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
notesTextLayoutView = root.findViewById(R.id.group_edit_note_container) notesTextLayoutView = root.findViewById(R.id.group_edit_note_container)
notesTextView = root.findViewById(R.id.group_edit_note) notesTextView = root.findViewById(R.id.group_edit_note)
expirationView = root.findViewById(R.id.group_edit_expiration) expirationView = root.findViewById(R.id.group_edit_expiration)
searchableContainerView = root.findViewById(R.id.group_edit_searchable_container)
searchableView = root.findViewById(R.id.group_edit_searchable)
autoTypeContainerView = root.findViewById(R.id.group_edit_auto_type_container)
autoTypeInheritedView = root.findViewById(R.id.group_edit_auto_type_inherited)
autoTypeSequenceView = root.findViewById(R.id.group_edit_auto_type_sequence)
tagsContainerView = root.findViewById(R.id.group_tags_label)
tagsCompletionView = root.findViewById(R.id.group_tags_completion_view)
// Retrieve the textColor to tint the icon // Retrieve the textColor to tint the icon
val ta = activity.theme.obtainStyledAttributes(intArrayOf(android.R.attr.textColor)) val ta = activity.theme.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
@@ -132,13 +173,13 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
&& savedInstanceState.containsKey(KEY_ACTION_ID) && savedInstanceState.containsKey(KEY_ACTION_ID)
&& savedInstanceState.containsKey(KEY_GROUP_INFO)) { && savedInstanceState.containsKey(KEY_GROUP_INFO)) {
mEditGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID)) mEditGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID))
mGroupInfo = savedInstanceState.getParcelable(KEY_GROUP_INFO) ?: mGroupInfo mGroupInfo = savedInstanceState.getParcelableCompat(KEY_GROUP_INFO) ?: mGroupInfo
} else { } else {
arguments?.apply { arguments?.apply {
if (containsKey(KEY_ACTION_ID)) if (containsKey(KEY_ACTION_ID))
mEditGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(getInt(KEY_ACTION_ID)) mEditGroupDialogAction = EditGroupDialogAction.getActionFromOrdinal(getInt(KEY_ACTION_ID))
if (containsKey(KEY_GROUP_INFO)) { if (containsKey(KEY_GROUP_INFO)) {
mGroupInfo = getParcelable(KEY_GROUP_INFO) ?: mGroupInfo mGroupInfo = getParcelableCompat(KEY_GROUP_INFO) ?: mGroupInfo
} }
} }
} }
@@ -197,6 +238,19 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
} }
expirationView.activation = groupInfo.expires expirationView.activation = groupInfo.expires
expirationView.dateTime = groupInfo.expiryTime expirationView.dateTime = groupInfo.expiryTime
// Set searchable
searchableView.setValue(groupInfo.searchable)
// Set auto-type
autoTypeInheritedView.setValue(groupInfo.enableAutoType)
autoTypeSequenceView.text = groupInfo.defaultAutoTypeSequence
// Set Tags
groupInfo.tags.let { tags ->
tagsCompletionView.setText("")
for (i in 0 until tags.size()) {
tagsCompletionView.addObjectSync(tags.get(i))
}
}
} }
private fun retrieveGroupInfoFromViews() { private fun retrieveGroupInfoFromViews() {
@@ -208,6 +262,10 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
} }
mGroupInfo.expires = expirationView.activation mGroupInfo.expires = expirationView.activation
mGroupInfo.expiryTime = expirationView.dateTime mGroupInfo.expiryTime = expirationView.dateTime
mGroupInfo.searchable = searchableView.getValue()
mGroupInfo.enableAutoType = autoTypeInheritedView.getValue()
mGroupInfo.defaultAutoTypeSequence = autoTypeSequenceView.text.toString()
mGroupInfo.tags = tagsCompletionView.getTags()
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
@@ -246,8 +304,8 @@ class GroupEditDialogFragment : DatabaseDialogFragment() {
companion object { companion object {
const val TAG_CREATE_GROUP = "TAG_CREATE_GROUP" const val TAG_CREATE_GROUP = "TAG_CREATE_GROUP"
const val KEY_ACTION_ID = "KEY_ACTION_ID" private const val KEY_ACTION_ID = "KEY_ACTION_ID"
const val KEY_GROUP_INFO = "KEY_GROUP_INFO" private const val KEY_GROUP_INFO = "KEY_GROUP_INFO"
fun create(groupInfo: GroupInfo): GroupEditDialogFragment { fun create(groupInfo: GroupInfo): GroupEditDialogFragment {
val bundle = Bundle() val bundle = Bundle()

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2021 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.activities.dialogs
import android.app.Dialog
import android.os.Bundle
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
class IconEditDialogFragment : DatabaseDialogFragment() {
private val mIconPickerViewModel: IconPickerViewModel by activityViewModels()
private var mPopulateIconMethod: ((ImageView, IconImage) -> Unit)? = null
private lateinit var iconView: ImageView
private lateinit var nameTextLayoutView: TextInputLayout
private lateinit var nameTextView: TextView
private var mCustomIcon: IconImageCustom? = null
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database)
mPopulateIconMethod = { imageView, icon ->
database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon)
}
mCustomIcon?.let { customIcon ->
populateViewsWithCustomIcon(customIcon)
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
val root = activity.layoutInflater.inflate(R.layout.fragment_icon_edit, null)
iconView = root.findViewById(R.id.icon_edit_image)
nameTextLayoutView = root.findViewById(R.id.icon_edit_name_container)
nameTextView = root.findViewById(R.id.icon_edit_name)
if (savedInstanceState != null
&& savedInstanceState.containsKey(KEY_CUSTOM_ICON_ID)) {
mCustomIcon = savedInstanceState.getParcelableCompat(KEY_CUSTOM_ICON_ID) ?: mCustomIcon
} else {
arguments?.apply {
if (containsKey(KEY_CUSTOM_ICON_ID)) {
mCustomIcon = getParcelableCompat(KEY_CUSTOM_ICON_ID) ?: mCustomIcon
}
}
}
val builder = AlertDialog.Builder(activity)
builder.setView(root)
.setPositiveButton(android.R.string.ok) { _, _ ->
retrieveIconInfoFromViews()
mCustomIcon?.let { customIcon ->
mIconPickerViewModel.updateCustomIcon(
IconPickerViewModel.IconCustomState(customIcon, false)
)
}
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
// Do nothing
mIconPickerViewModel.updateCustomIcon(
IconPickerViewModel.IconCustomState(null, false)
)
}
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
private fun populateViewsWithCustomIcon(customIcon: IconImageCustom) {
mPopulateIconMethod?.invoke(iconView, customIcon.getIconImageToDraw())
nameTextView.text = customIcon.name
}
private fun retrieveIconInfoFromViews() {
mCustomIcon?.name = nameTextView.text.toString()
mCustomIcon?.lastModificationTime = DateInstant()
}
override fun onSaveInstanceState(outState: Bundle) {
retrieveIconInfoFromViews()
outState.putParcelable(KEY_CUSTOM_ICON_ID, mCustomIcon)
super.onSaveInstanceState(outState)
}
companion object {
const val TAG_UPDATE_ICON = "TAG_UPDATE_ICON"
const val KEY_CUSTOM_ICON_ID = "KEY_CUSTOM_ICON_ID"
fun update(customIcon: IconImageCustom): IconEditDialogFragment {
val bundle = Bundle()
bundle.putParcelable(KEY_CUSTOM_ICON_ID, IconImageCustom(customIcon))
val fragment = IconEditDialogFragment()
fragment.arguments = bundle
return fragment
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2022 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.activities.dialogs
import android.app.Dialog
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.view.MainCredentialView
class MainCredentialDialogFragment : DatabaseDialogFragment() {
private var mainCredentialView: MainCredentialView? = null
private var mListener: AskMainCredentialDialogListener? = null
private var mExternalFileHelper: ExternalFileHelper? = null
interface AskMainCredentialDialogListener {
fun onAskMainCredentialDialogPositiveClick(databaseUri: Uri?, mainCredential: MainCredential)
fun onAskMainCredentialDialogNegativeClick(databaseUri: Uri?, mainCredential: MainCredential)
}
override fun onAttach(activity: Context) {
super.onAttach(activity)
try {
mListener = activity as AskMainCredentialDialogListener
} catch (e: ClassCastException) {
throw ClassCastException(activity.toString()
+ " must implement " + AskMainCredentialDialogListener::class.java.name)
}
}
override fun onDetach() {
mListener = null
super.onDetach()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
var databaseUri: Uri? = null
arguments?.apply {
if (containsKey(KEY_ASK_CREDENTIAL_URI))
databaseUri = getParcelableCompat(KEY_ASK_CREDENTIAL_URI)
}
val builder = AlertDialog.Builder(activity)
val root = activity.layoutInflater.inflate(R.layout.fragment_main_credential, null)
mainCredentialView = root.findViewById(R.id.main_credential_view)
databaseUri?.let {
root.findViewById<TextView>(R.id.title_database)?.text =
it.getDocumentFile(requireContext())?.name
}
builder.setView(root)
// Add action buttons
.setPositiveButton(android.R.string.ok) { _, _ ->
mListener?.onAskMainCredentialDialogPositiveClick(
databaseUri,
retrieveMainCredential()
)
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
mListener?.onAskMainCredentialDialogNegativeClick(
databaseUri,
retrieveMainCredential()
)
}
mExternalFileHelper = ExternalFileHelper(this)
mExternalFileHelper?.buildOpenDocument { uri ->
if (uri != null) {
mainCredentialView?.populateKeyFileView(uri)
}
}
mainCredentialView?.setOpenKeyfileClickListener(mExternalFileHelper)
return builder.create()
}
return super.onCreateDialog(savedInstanceState)
}
private fun retrieveMainCredential(): MainCredential {
return mainCredentialView?.getMainCredential() ?: MainCredential()
}
companion object {
private const val KEY_ASK_CREDENTIAL_URI = "KEY_ASK_CREDENTIAL_URI"
const val TAG_ASK_MAIN_CREDENTIAL = "TAG_ASK_MAIN_CREDENTIAL"
fun getInstance(uri: Uri?): MainCredentialDialogFragment {
val fragment = MainCredentialDialogFragment()
val args = Bundle()
args.putParcelable(KEY_ASK_CREDENTIAL_URI, uri)
fragment.arguments = args
return fragment
}
}
}

View File

@@ -26,7 +26,8 @@ import android.os.Bundle
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.MainCredential import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.utils.getParcelableCompat
class PasswordEncodingDialogFragment : DialogFragment() { class PasswordEncodingDialogFragment : DialogFragment() {
@@ -49,8 +50,8 @@ class PasswordEncodingDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val databaseUri: Uri? = savedInstanceState?.getParcelable(DATABASE_URI_KEY) val databaseUri: Uri? = savedInstanceState?.getParcelableCompat(DATABASE_URI_KEY)
val mainCredential: MainCredential = savedInstanceState?.getParcelable(MAIN_CREDENTIAL) ?: MainCredential() val mainCredential: MainCredential = savedInstanceState?.getParcelableCompat(MAIN_CREDENTIAL) ?: MainCredential()
activity?.let { activity -> activity?.let { activity ->
val builder = AlertDialog.Builder(activity) val builder = AlertDialog.Builder(activity)
@@ -78,8 +79,10 @@ class PasswordEncodingDialogFragment : DialogFragment() {
private const val DATABASE_URI_KEY = "DATABASE_URI_KEY" private const val DATABASE_URI_KEY = "DATABASE_URI_KEY"
private const val MAIN_CREDENTIAL = "MAIN_CREDENTIAL" private const val MAIN_CREDENTIAL = "MAIN_CREDENTIAL"
fun getInstance(databaseUri: Uri, fun getInstance(
mainCredential: MainCredential): SortDialogFragment { databaseUri: Uri,
mainCredential: MainCredential
): SortDialogFragment {
val fragment = SortDialogFragment() val fragment = SortDialogFragment()
fragment.arguments = Bundle().apply { fragment.arguments = Bundle().apply {
putParcelable(DATABASE_URI_KEY, databaseUri) putParcelable(DATABASE_URI_KEY, databaseUri)

View File

@@ -28,7 +28,7 @@ import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.BuildConfig import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil.openUrl
/** /**
* Custom Dialog that asks the user to download the pro version or make a donation. * Custom Dialog that asks the user to download the pro version or make a donation.
@@ -45,13 +45,16 @@ class ProFeatureDialogFragment : DialogFragment() {
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_ad_free), FROM_HTML_MODE_LEGACY)).append("\n\n") stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_ad_free), FROM_HTML_MODE_LEGACY)).append("\n\n")
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_buy_pro), FROM_HTML_MODE_LEGACY)) stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_buy_pro), FROM_HTML_MODE_LEGACY))
builder.setPositiveButton(R.string.download) { _, _ -> builder.setPositiveButton(R.string.download) { _, _ ->
UriUtil.gotoUrl(requireContext(), R.string.app_pro_url) activity.openUrl(
activity.getString(R.string.play_store_url,
activity.getString(R.string.keepro_app_id))
)
} }
} else { } else {
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_feature_generosity), FROM_HTML_MODE_LEGACY)).append("\n\n") stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_feature_generosity), FROM_HTML_MODE_LEGACY)).append("\n\n")
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_donation), FROM_HTML_MODE_LEGACY)) stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_donation), FROM_HTML_MODE_LEGACY))
builder.setPositiveButton(R.string.contribute) { _, _ -> builder.setPositiveButton(R.string.contribute) { _, _ ->
UriUtil.gotoUrl(requireContext(), R.string.contribution_url) activity.openUrl(R.string.contribution_url)
} }
} }
builder.setMessage(stringBuilder) builder.setMessage(stringBuilder)

View File

@@ -27,6 +27,7 @@ import android.text.SpannableStringBuilder
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Attachment import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.utils.getParcelableCompat
/** /**
* Custom Dialog to confirm big file to upload * Custom Dialog to confirm big file to upload
@@ -62,8 +63,8 @@ class ReplaceFileDialogFragment : DatabaseDialogFragment() {
}) })
builder.setPositiveButton(android.R.string.ok) { _, _ -> builder.setPositiveButton(android.R.string.ok) { _, _ ->
mActionChooseListener?.onValidateReplaceFile( mActionChooseListener?.onValidateReplaceFile(
arguments?.getParcelable(KEY_FILE_URI), arguments?.getParcelableCompat(KEY_FILE_URI),
arguments?.getParcelable(KEY_ENTRY_ATTACHMENT)) arguments?.getParcelableCompat(KEY_ENTRY_ATTACHMENT))
} }
builder.setNegativeButton(android.R.string.cancel) { _, _ -> builder.setNegativeButton(android.R.string.cancel) { _, _ ->
dismiss() dismiss()

View File

@@ -0,0 +1,374 @@
/*
* Copyright 2019 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.activities.dialogs
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.text.SpannableStringBuilder
import android.text.TextWatcher
import android.view.View
import android.widget.CompoundButton
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.hardware.HardwareKey
import com.kunzisoft.keepass.hardware.HardwareKeyActivity
import com.kunzisoft.keepass.password.PasswordEntropy
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.applyFontVisibility
class SetMainCredentialDialogFragment : DatabaseDialogFragment() {
private var mMasterPassword: String? = null
private var mKeyFileUri: Uri? = null
private var mHardwareKey: HardwareKey? = null
private lateinit var rootView: View
private lateinit var passwordCheckBox: CompoundButton
private lateinit var passwordView: PassKeyView
private lateinit var passwordRepeatTextInputLayout: TextInputLayout
private lateinit var passwordRepeatView: TextView
private lateinit var keyFileCheckBox: CompoundButton
private lateinit var keyFileSelectionView: KeyFileSelectionView
private lateinit var hardwareKeyCheckBox: CompoundButton
private lateinit var hardwareKeySelectionView: HardwareKeySelectionView
private var mListener: AssignMainCredentialDialogListener? = null
private var mExternalFileHelper: ExternalFileHelper? = null
private var mPasswordEntropyCalculator: PasswordEntropy? = null
private var mEmptyPasswordConfirmationDialog: AlertDialog? = null
private var mNoKeyConfirmationDialog: AlertDialog? = null
private var mEmptyKeyFileConfirmationDialog: AlertDialog? = null
private var mAllowNoMasterKey: Boolean = false
private val passwordTextWatcher = object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
passwordCheckBox.isChecked = true
}
}
interface AssignMainCredentialDialogListener {
fun onAssignKeyDialogPositiveClick(mainCredential: MainCredential)
fun onAssignKeyDialogNegativeClick(mainCredential: MainCredential)
}
override fun onAttach(activity: Context) {
super.onAttach(activity)
try {
mListener = activity as AssignMainCredentialDialogListener
} catch (e: ClassCastException) {
throw ClassCastException(activity.toString()
+ " must implement " + AssignMainCredentialDialogListener::class.java.name)
}
}
override fun onDetach() {
mListener = null
mEmptyPasswordConfirmationDialog?.dismiss()
mEmptyPasswordConfirmationDialog = null
mNoKeyConfirmationDialog?.dismiss()
mNoKeyConfirmationDialog = null
mEmptyKeyFileConfirmationDialog?.dismiss()
mEmptyKeyFileConfirmationDialog = null
super.onDetach()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Create the password entropy object
mPasswordEntropyCalculator = PasswordEntropy()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
activity?.let { activity ->
arguments?.apply {
if (containsKey(ALLOW_NO_MASTER_KEY_ARG))
mAllowNoMasterKey = getBoolean(ALLOW_NO_MASTER_KEY_ARG, false)
}
val builder = AlertDialog.Builder(activity)
val inflater = activity.layoutInflater
rootView = inflater.inflate(R.layout.fragment_set_main_credential, null)
builder.setView(rootView)
// Add action buttons
.setPositiveButton(android.R.string.ok) { _, _ -> }
.setNegativeButton(android.R.string.cancel) { _, _ -> }
rootView.findViewById<View>(R.id.credentials_information)?.setOnClickListener {
activity.openUrl(R.string.credentials_explanation_url)
}
passwordCheckBox = rootView.findViewById(R.id.password_checkbox)
passwordView = 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)
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?.buildOpenDocument { uri ->
uri?.let { pathUri ->
pathUri.getDocumentFile(requireContext())?.length()?.let { lengthFile ->
keyFileSelectionView.error = null
keyFileCheckBox.isChecked = true
keyFileSelectionView.uri = pathUri
if (lengthFile <= 0L) {
showEmptyKeyFileConfirmationDialog()
}
}
}
}
keyFileSelectionView.setOpenDocumentClickListener(mExternalFileHelper)
hardwareKeySelectionView.selectionListener = { hardwareKey ->
hardwareKeyCheckBox.isChecked = true
hardwareKeySelectionView.error =
if (!HardwareKeyActivity.isHardwareKeyAvailable(requireActivity(), hardwareKey)) {
// show hardware driver dialog if required
getString(R.string.error_driver_required, hardwareKey.toString())
} else {
null
}
}
val dialog = builder.create()
dialog.setOnShowListener { dialog1 ->
val positiveButton = (dialog1 as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE)
positiveButton.setOnClickListener {
mMasterPassword = ""
mKeyFileUri = null
mHardwareKey = null
approveMainCredential()
}
val negativeButton = dialog1.getButton(DialogInterface.BUTTON_NEGATIVE)
negativeButton.setOnClickListener {
mListener?.onAssignKeyDialogNegativeClick(retrieveMainCredential())
dismiss()
}
}
return dialog
}
return super.onCreateDialog(savedInstanceState)
}
private fun approveMainCredential() {
val errorPassword = verifyPassword()
val errorKeyFile = verifyKeyFile()
val errorHardwareKey = verifyHardwareKey()
// Check all to fill error
var error = errorPassword || errorKeyFile || errorHardwareKey
val hardwareKey = hardwareKeySelectionView.hardwareKey
if (!error
&& (!passwordCheckBox.isChecked)
&& (!keyFileCheckBox.isChecked)
&& (!hardwareKeyCheckBox.isChecked)
) {
error = true
if (mAllowNoMasterKey) {
// show no key dialog if required
showNoKeyConfirmationDialog()
} else {
passwordRepeatTextInputLayout.error =
getString(R.string.error_disallow_no_credentials)
}
} else if (!error
&& mMasterPassword.isNullOrEmpty()
&& !keyFileCheckBox.isChecked
&& !hardwareKeyCheckBox.isChecked
) {
// show empty password dialog if required
error = true
showEmptyPasswordConfirmationDialog()
} else if (!error
&& hardwareKey != null
&& !HardwareKeyActivity.isHardwareKeyAvailable(
requireActivity(), hardwareKey, false)
) {
// show hardware driver dialog if required
error = true
hardwareKeySelectionView.error =
getString(R.string.error_driver_required, hardwareKey.toString())
}
if (!error) {
mListener?.onAssignKeyDialogPositiveClick(retrieveMainCredential())
dismiss()
}
}
private fun verifyPassword(): Boolean {
var error = false
passwordRepeatTextInputLayout.error = null
if (passwordCheckBox.isChecked) {
mMasterPassword = passwordView.passwordString
val confPassword = passwordRepeatView.text.toString()
// Verify that passwords match
if (mMasterPassword != confPassword) {
error = true
// Passwords do not match
passwordRepeatTextInputLayout.error = getString(R.string.error_pass_match)
}
}
return error
}
private fun verifyKeyFile(): Boolean {
var error = false
keyFileSelectionView.error = null
if (keyFileCheckBox.isChecked) {
keyFileSelectionView.uri?.let { uri ->
mKeyFileUri = uri
} ?: run {
error = true
keyFileSelectionView.error = getString(R.string.error_nokeyfile)
}
}
return error
}
private fun verifyHardwareKey(): Boolean {
var error = false
hardwareKeySelectionView.error = null
if (hardwareKeyCheckBox.isChecked) {
hardwareKeySelectionView.hardwareKey?.let { hardwareKey ->
mHardwareKey = hardwareKey
} ?: run {
error = true
hardwareKeySelectionView.error = getString(R.string.error_no_hardware_key)
}
}
return error
}
private fun retrieveMainCredential(): MainCredential {
val masterPassword = if (passwordCheckBox.isChecked) mMasterPassword else null
val keyFileUri = if (keyFileCheckBox.isChecked) mKeyFileUri else null
val hardwareKey = if (hardwareKeyCheckBox.isChecked) mHardwareKey else null
return MainCredential(masterPassword, keyFileUri, hardwareKey)
}
override fun onResume() {
super.onResume()
// To check checkboxes if a text is present
passwordView.addTextChangedListener(passwordTextWatcher)
}
override fun onPause() {
super.onPause()
passwordView.removeTextChangedListener(passwordTextWatcher)
}
private fun showEmptyPasswordConfirmationDialog() {
activity?.let {
val builder = AlertDialog.Builder(it)
builder.setMessage(R.string.warning_empty_password)
.setPositiveButton(android.R.string.ok) { _, _ ->
mListener?.onAssignKeyDialogPositiveClick(retrieveMainCredential())
this@SetMainCredentialDialogFragment.dismiss()
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
mEmptyPasswordConfirmationDialog = builder.create()
mEmptyPasswordConfirmationDialog?.show()
}
}
private fun showNoKeyConfirmationDialog() {
activity?.let {
val builder = AlertDialog.Builder(it)
builder.setMessage(R.string.warning_no_encryption_key)
.setPositiveButton(android.R.string.ok) { _, _ ->
mListener?.onAssignKeyDialogPositiveClick(retrieveMainCredential())
this@SetMainCredentialDialogFragment.dismiss()
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
mNoKeyConfirmationDialog = builder.create()
mNoKeyConfirmationDialog?.show()
}
}
private fun showEmptyKeyFileConfirmationDialog() {
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
}
mEmptyKeyFileConfirmationDialog = builder.create()
mEmptyKeyFileConfirmationDialog?.show()
}
}
companion object {
private const val ALLOW_NO_MASTER_KEY_ARG = "ALLOW_NO_MASTER_KEY_ARG"
fun getInstance(allowNoMasterKey: Boolean): SetMainCredentialDialogFragment {
val fragment = SetMainCredentialDialogFragment()
val args = Bundle()
args.putBoolean(ALLOW_NO_MASTER_KEY_ARG, allowNoMasterKey)
fragment.arguments = args
return fragment
}
}
}

View File

@@ -32,7 +32,6 @@ import android.view.inputmethod.EditorInfo
import android.widget.* import android.widget.*
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.OtpModel import com.kunzisoft.keepass.model.OtpModel
import com.kunzisoft.keepass.otp.OtpElement import com.kunzisoft.keepass.otp.OtpElement
@@ -45,7 +44,9 @@ import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_TOTP_PERIOD
import com.kunzisoft.keepass.otp.OtpTokenType import com.kunzisoft.keepass.otp.OtpTokenType
import com.kunzisoft.keepass.otp.OtpType import com.kunzisoft.keepass.otp.OtpType
import com.kunzisoft.keepass.otp.TokenCalculator import com.kunzisoft.keepass.otp.TokenCalculator
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.getParcelableCompat
import java.util.* import java.util.*
class SetOTPDialogFragment : DatabaseDialogFragment() { class SetOTPDialogFragment : DatabaseDialogFragment() {
@@ -126,14 +127,14 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
// Retrieve OTP model from instance state // Retrieve OTP model from instance state
if (savedInstanceState != null) { if (savedInstanceState != null) {
if (savedInstanceState.containsKey(KEY_OTP)) { if (savedInstanceState.containsKey(KEY_OTP)) {
savedInstanceState.getParcelable<OtpModel>(KEY_OTP)?.let { otpModel -> savedInstanceState.getParcelableCompat<OtpModel>(KEY_OTP)?.let { otpModel ->
mOtpElement = OtpElement(otpModel) mOtpElement = OtpElement(otpModel)
} }
} }
} else { } else {
arguments?.apply { arguments?.apply {
if (containsKey(KEY_OTP)) { if (containsKey(KEY_OTP)) {
getParcelable<OtpModel?>(KEY_OTP)?.let { otpModel -> getParcelableCompat<OtpModel>(KEY_OTP)?.let { otpModel ->
mOtpElement = OtpElement(otpModel) mOtpElement = OtpElement(otpModel)
} }
} }
@@ -204,9 +205,10 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
android.R.layout.simple_spinner_item, mHotpTokenTypeArray!!).apply { android.R.layout.simple_spinner_item, mHotpTokenTypeArray!!).apply {
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
} }
// Proprietary only on closed and full version // Proprietary only on full version
mTotpTokenTypeArray = OtpTokenType.getTotpTokenTypeValues( mTotpTokenTypeArray = OtpTokenType.getTotpTokenTypeValues(
BuildConfig.CLOSED_STORE && BuildConfig.FULL_VERSION) activity.isContributingUser()
)
totpTokenTypeAdapter = ArrayAdapter(activity, totpTokenTypeAdapter = ArrayAdapter(activity,
android.R.layout.simple_spinner_item, mTotpTokenTypeArray!!).apply { android.R.layout.simple_spinner_item, mTotpTokenTypeArray!!).apply {
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
@@ -241,7 +243,7 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
} }
root?.findViewById<View>(R.id.otp_information)?.setOnClickListener { root?.findViewById<View>(R.id.otp_information)?.setOnClickListener {
UriUtil.gotoUrl(activity, R.string.otp_explanation_url) activity.openUrl(R.string.otp_explanation_url)
} }
return builder.create() return builder.create()
@@ -309,7 +311,7 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
s?.toString()?.let { userString -> s?.toString()?.let { userString ->
try { try {
mOtpElement.setBase32Secret(userString.toUpperCase(Locale.ENGLISH)) mOtpElement.setBase32Secret(userString.uppercase(Locale.ENGLISH))
otpSecretContainer?.error = null otpSecretContainer?.error = null
} catch (exception: Exception) { } catch (exception: Exception) {
otpSecretContainer?.error = getString(R.string.error_otp_secret_key) otpSecretContainer?.error = getString(R.string.error_otp_secret_key)
@@ -469,4 +471,4 @@ class SetOTPDialogFragment : DatabaseDialogFragment() {
} }
} }
} }
} }

View File

@@ -1,63 +0,0 @@
package com.kunzisoft.keepass.activities.dialogs
import android.app.DatePickerDialog
import android.app.Dialog
import android.app.TimePickerDialog
import android.content.Context
import android.os.Bundle
import android.text.format.DateFormat
import androidx.fragment.app.DialogFragment
// Not as DatabaseDialogFragment because crash on KitKat
class TimePickerFragment : DialogFragment() {
private var defaultHour: Int = 0
private var defaultMinute: Int = 0
private var mListener: TimePickerDialog.OnTimeSetListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
try {
mListener = context as TimePickerDialog.OnTimeSetListener
} catch (e: ClassCastException) {
throw ClassCastException(context.toString()
+ " must implement " + DatePickerDialog.OnDateSetListener::class.java.name)
}
}
override fun onDetach() {
mListener = null
super.onDetach()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Create a new instance of DatePickerDialog and return it
return context?.let {
arguments?.apply {
if (containsKey(DEFAULT_HOUR_BUNDLE_KEY))
defaultHour = getInt(DEFAULT_HOUR_BUNDLE_KEY)
if (containsKey(DEFAULT_MINUTE_BUNDLE_KEY))
defaultMinute = getInt(DEFAULT_MINUTE_BUNDLE_KEY)
}
TimePickerDialog(it, mListener, defaultHour, defaultMinute, DateFormat.is24HourFormat(activity))
} ?: super.onCreateDialog(savedInstanceState)
}
companion object {
private const val DEFAULT_HOUR_BUNDLE_KEY = "DEFAULT_HOUR_BUNDLE_KEY"
private const val DEFAULT_MINUTE_BUNDLE_KEY = "DEFAULT_MINUTE_BUNDLE_KEY"
fun getInstance(defaultHour: Int,
defaultMinute: Int): TimePickerFragment {
return TimePickerFragment().apply {
arguments = Bundle().apply {
putInt(DEFAULT_HOUR_BUNDLE_KEY, defaultHour)
putInt(DEFAULT_MINUTE_BUNDLE_KEY, defaultMinute)
}
}
}
}
}

View File

@@ -22,12 +22,12 @@ package com.kunzisoft.keepass.activities.dialogs
import android.app.Dialog import android.app.Dialog
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.appcompat.app.AlertDialog
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
class UnavailableFeatureDialogFragment : DialogFragment() { class UnavailableFeatureDialogFragment : DialogFragment() {

View File

@@ -25,9 +25,8 @@ import android.text.SpannableStringBuilder
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil.openUrl
/** /**
* Custom Dialog that asks the user to download the pro version or make a donation. * Custom Dialog that asks the user to download the pro version or make a donation.
@@ -40,31 +39,22 @@ class UnderDevelopmentFeatureDialogFragment : DialogFragment() {
val builder = AlertDialog.Builder(activity) val builder = AlertDialog.Builder(activity)
val stringBuilder = SpannableStringBuilder() val stringBuilder = SpannableStringBuilder()
if (BuildConfig.CLOSED_STORE) { /*
if (BuildConfig.FULL_VERSION) { if (activity.isContributingUser()) {
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_thanks), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n") stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_thanks), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_rose), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n") .append(HtmlCompat.fromHtml(getString(R.string.html_rose), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_work_hard), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n") .append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_work_hard), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_upgrade), HtmlCompat.FROM_HTML_MODE_LEGACY)).append(" ") .append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_upgrade), HtmlCompat.FROM_HTML_MODE_LEGACY)).append(" ")
builder.setPositiveButton(android.R.string.ok) { _, _ -> dismiss() } builder.setPositiveButton(android.R.string.ok) { _, _ -> dismiss() }
} else {
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_buy_pro), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_encourage), HtmlCompat.FROM_HTML_MODE_LEGACY))
builder.setPositiveButton(R.string.download) { _, _ ->
UriUtil.gotoUrl(requireContext(), R.string.app_pro_url)
}
builder.setNegativeButton(android.R.string.cancel) { _, _ -> dismiss() }
}
} else { } else {
*/
stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n") stringBuilder.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature), HtmlCompat.FROM_HTML_MODE_LEGACY)).append("\n\n")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_contibute), HtmlCompat.FROM_HTML_MODE_LEGACY)).append(" ") .append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_contibute), HtmlCompat.FROM_HTML_MODE_LEGACY)).append(" ")
.append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_encourage), HtmlCompat.FROM_HTML_MODE_LEGACY)) .append(HtmlCompat.fromHtml(getString(R.string.html_text_dev_feature_encourage), HtmlCompat.FROM_HTML_MODE_LEGACY))
builder.setPositiveButton(R.string.contribute) { _, _ -> builder.setPositiveButton(R.string.contribute) { _, _ ->
UriUtil.gotoUrl(requireContext(), R.string.contribution_url) context?.openUrl(R.string.contribution_url)
} }
builder.setNegativeButton(android.R.string.cancel) { _, _ -> dismiss() } //}
}
builder.setMessage(stringBuilder) builder.setMessage(stringBuilder)
// Create the AlertDialog object and return it // Create the AlertDialog object and return it
return builder.create() return builder.create()

View File

@@ -2,19 +2,19 @@ package com.kunzisoft.keepass.activities.fragments
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
import com.kunzisoft.keepass.activities.stylish.StylishFragment import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.binary.BinaryData import com.kunzisoft.keepass.database.element.binary.BinaryData
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
abstract class DatabaseFragment : StylishFragment(), DatabaseRetrieval { abstract class DatabaseFragment : Fragment(), DatabaseRetrieval {
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels() private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
protected var mDatabase: Database? = null protected var mDatabase: ContextualDatabase? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@@ -38,7 +38,7 @@ abstract class DatabaseFragment : StylishFragment(), DatabaseRetrieval {
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {

View File

@@ -29,22 +29,29 @@ import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.ReplaceFileDialogFragment import com.kunzisoft.keepass.activities.dialogs.ReplaceFileDialogFragment
import com.kunzisoft.keepass.activities.dialogs.SetOTPDialogFragment import com.kunzisoft.keepass.activities.dialogs.SetOTPDialogFragment
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
import com.kunzisoft.keepass.adapters.TagsProposalAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.template.Template import com.kunzisoft.keepass.database.element.template.Template
import com.kunzisoft.keepass.model.AttachmentState import com.kunzisoft.keepass.model.AttachmentState
import com.kunzisoft.keepass.model.EntryAttachmentState import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.EntryInfo import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.StreamDirection import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.utils.getParcelableList
import com.kunzisoft.keepass.utils.putParcelableList
import com.kunzisoft.keepass.view.TagsCompletionView
import com.kunzisoft.keepass.view.TemplateEditView import com.kunzisoft.keepass.view.TemplateEditView
import com.kunzisoft.keepass.view.collapse import com.kunzisoft.keepass.view.collapse
import com.kunzisoft.keepass.view.expand import com.kunzisoft.keepass.view.expand
import com.kunzisoft.keepass.view.showByFading import com.kunzisoft.keepass.view.showByFading
import com.kunzisoft.keepass.viewmodels.EntryEditViewModel import com.kunzisoft.keepass.viewmodels.EntryEditViewModel
import com.tokenautocomplete.FilteredArrayAdapter
class EntryEditFragment: DatabaseFragment() { class EntryEditFragment: DatabaseFragment() {
@@ -55,6 +62,9 @@ class EntryEditFragment: DatabaseFragment() {
private lateinit var attachmentsContainerView: ViewGroup private lateinit var attachmentsContainerView: ViewGroup
private lateinit var attachmentsListView: RecyclerView private lateinit var attachmentsListView: RecyclerView
private var attachmentsAdapter: EntryAttachmentsItemsAdapter? = null private var attachmentsAdapter: EntryAttachmentsItemsAdapter? = null
private lateinit var tagsContainerView: TextInputLayout
private lateinit var tagsCompletionView: TagsCompletionView
private var tagsAdapter: FilteredArrayAdapter<String>? = null
private var mTemplate: Template? = null private var mTemplate: Template? = null
private var mAllowMultipleAttachments: Boolean = false private var mAllowMultipleAttachments: Boolean = false
@@ -67,12 +77,11 @@ class EntryEditFragment: DatabaseFragment() {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
// Retrieve the textColor to tint the icon // Retrieve the textColor to tint the icon
val taIconColor = contextThemed?.theme?.obtainStyledAttributes(intArrayOf(android.R.attr.textColor)) val taIconColor = context?.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
mIconColor = taIconColor?.getColor(0, Color.BLACK) ?: Color.BLACK mIconColor = taIconColor?.getColor(0, Color.BLACK) ?: Color.BLACK
taIconColor?.recycle() taIconColor?.recycle()
return inflater.cloneInContext(contextThemed) return inflater.inflate(R.layout.fragment_entry_edit, container, false)
.inflate(R.layout.fragment_entry_edit, container, false)
} }
override fun onViewCreated(view: View, override fun onViewCreated(view: View,
@@ -87,6 +96,8 @@ class EntryEditFragment: DatabaseFragment() {
templateView = view.findViewById(R.id.template_view) templateView = view.findViewById(R.id.template_view)
attachmentsContainerView = view.findViewById(R.id.entry_attachments_container) attachmentsContainerView = view.findViewById(R.id.entry_attachments_container)
attachmentsListView = view.findViewById(R.id.entry_attachments_list) attachmentsListView = view.findViewById(R.id.entry_attachments_list)
tagsContainerView = view.findViewById(R.id.entry_tags_label)
tagsCompletionView = view.findViewById(R.id.entry_tags_completion_view)
attachmentsAdapter = EntryAttachmentsItemsAdapter(requireContext()) attachmentsAdapter = EntryAttachmentsItemsAdapter(requireContext())
attachmentsListView.apply { attachmentsListView.apply {
@@ -99,6 +110,12 @@ class EntryEditFragment: DatabaseFragment() {
setOnIconClickListener { setOnIconClickListener {
mEntryEditViewModel.requestIconSelection(templateView.getIcon()) mEntryEditViewModel.requestIconSelection(templateView.getIcon())
} }
setOnBackgroundColorClickListener {
mEntryEditViewModel.requestBackgroundColorSelection(templateView.getBackgroundColor())
}
setOnForegroundColorClickListener {
mEntryEditViewModel.requestForegroundColorSelection(templateView.getForegroundColor())
}
setOnCustomEditionActionClickListener { field -> setOnCustomEditionActionClickListener { field ->
mEntryEditViewModel.requestCustomFieldEdition(field) mEntryEditViewModel.requestCustomFieldEdition(field)
} }
@@ -112,7 +129,7 @@ class EntryEditFragment: DatabaseFragment() {
if (savedInstanceState != null) { if (savedInstanceState != null) {
val attachments: List<Attachment> = val attachments: List<Attachment> =
savedInstanceState.getParcelableArrayList(ATTACHMENTS_TAG) ?: listOf() savedInstanceState.getParcelableList(ATTACHMENTS_TAG) ?: listOf()
setAttachments(attachments) setAttachments(attachments)
} }
@@ -140,13 +157,22 @@ class EntryEditFragment: DatabaseFragment() {
} }
mEntryEditViewModel.requestEntryInfoUpdate.observe(viewLifecycleOwner) { mEntryEditViewModel.requestEntryInfoUpdate.observe(viewLifecycleOwner) {
mEntryEditViewModel.saveEntryInfo(it.database, it.entry, it.parent, retrieveEntryInfo()) val entryInfo = retrieveEntryInfo()
mEntryEditViewModel.saveEntryInfo(it.database, it.entry, it.parent, entryInfo)
} }
mEntryEditViewModel.onIconSelected.observe(viewLifecycleOwner) { iconImage -> mEntryEditViewModel.onIconSelected.observe(viewLifecycleOwner) { iconImage ->
templateView.setIcon(iconImage) templateView.setIcon(iconImage)
} }
mEntryEditViewModel.onBackgroundColorSelected.observe(viewLifecycleOwner) { color ->
templateView.setBackgroundColor(color)
}
mEntryEditViewModel.onForegroundColorSelected.observe(viewLifecycleOwner) { color ->
templateView.setForegroundColor(color)
}
mEntryEditViewModel.onPasswordSelected.observe(viewLifecycleOwner) { passwordField -> mEntryEditViewModel.onPasswordSelected.observe(viewLifecycleOwner) { passwordField ->
templateView.setPasswordField(passwordField) templateView.setPasswordField(passwordField)
} }
@@ -247,7 +273,7 @@ class EntryEditFragment: DatabaseFragment() {
} }
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
templateView.populateIconMethod = { imageView, icon -> templateView.populateIconMethod = { imageView, icon ->
database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor) database?.iconDrawableFactory?.assignDatabaseIcon(imageView, icon, mIconColor)
@@ -263,18 +289,34 @@ class EntryEditFragment: DatabaseFragment() {
attachmentsContainerView.expand(true) attachmentsContainerView.expand(true)
} }
} }
tagsAdapter = TagsProposalAdapter(requireContext(), database?.tagPool)
tagsCompletionView.apply {
threshold = 1
setAdapter(tagsAdapter)
}
tagsContainerView.visibility = if (database?.allowTags() == true) View.VISIBLE else View.GONE
} }
private fun assignEntryInfo(entryInfo: EntryInfo?) { private fun assignEntryInfo(entryInfo: EntryInfo?) {
// Populate entry views // Populate entry views
templateView.setEntryInfo(entryInfo) templateView.setEntryInfo(entryInfo)
// Set Tags
entryInfo?.tags?.let { tags ->
tagsCompletionView.setText("")
for (i in 0 until tags.size()) {
tagsCompletionView.addObjectSync(tags.get(i))
}
}
// Manage attachments // Manage attachments
setAttachments(entryInfo?.attachments ?: listOf()) setAttachments(entryInfo?.attachments ?: listOf())
} }
private fun retrieveEntryInfo(): EntryInfo { private fun retrieveEntryInfo(): EntryInfo {
val entryInfo = templateView.getEntryInfo() val entryInfo = templateView.getEntryInfo()
entryInfo.tags = tagsCompletionView.getTags()
entryInfo.attachments = getAttachments().toMutableList() entryInfo.attachments = getAttachments().toMutableList()
return entryInfo return entryInfo
} }
@@ -342,7 +384,7 @@ class EntryEditFragment: DatabaseFragment() {
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putParcelableArrayList(ATTACHMENTS_TAG, ArrayList(getAttachments())) outState.putParcelableList(ATTACHMENTS_TAG, getAttachments())
} }
/* ------------- /* -------------

View File

@@ -14,24 +14,28 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Attachment import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.DateInstant
import com.kunzisoft.keepass.database.element.template.TemplateField import com.kunzisoft.keepass.database.element.template.TemplateField
import com.kunzisoft.keepass.database.helper.getLocalizedName
import com.kunzisoft.keepass.model.EntryAttachmentState import com.kunzisoft.keepass.model.EntryAttachmentState
import com.kunzisoft.keepass.model.EntryInfo import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.StreamDirection import com.kunzisoft.keepass.model.StreamDirection
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.timeout.ClipboardHelper import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
import com.kunzisoft.keepass.utils.UuidUtil import com.kunzisoft.keepass.utils.UuidUtil
import com.kunzisoft.keepass.view.TemplateView import com.kunzisoft.keepass.view.TemplateView
import com.kunzisoft.keepass.view.hideByFading
import com.kunzisoft.keepass.view.showByFading import com.kunzisoft.keepass.view.showByFading
import com.kunzisoft.keepass.viewmodels.EntryViewModel import com.kunzisoft.keepass.viewmodels.EntryViewModel
import java.util.*
class EntryFragment: DatabaseFragment() { class EntryFragment: DatabaseFragment() {
private lateinit var rootView: View private lateinit var rootView: View
private lateinit var mainSection: View
private lateinit var advancedSection: View
private lateinit var templateView: TemplateView private lateinit var templateView: TemplateView
private lateinit var creationDateView: TextView private lateinit var creationDateView: TextView
@@ -41,8 +45,9 @@ class EntryFragment: DatabaseFragment() {
private lateinit var attachmentsListView: RecyclerView private lateinit var attachmentsListView: RecyclerView
private var attachmentsAdapter: EntryAttachmentsItemsAdapter? = null private var attachmentsAdapter: EntryAttachmentsItemsAdapter? = null
private lateinit var customDataView: TextView
private lateinit var uuidContainerView: View private lateinit var uuidContainerView: View
private lateinit var uuidView: TextView
private lateinit var uuidReferenceView: TextView private lateinit var uuidReferenceView: TextView
private var mClipboardHelper: ClipboardHelper? = null private var mClipboardHelper: ClipboardHelper? = null
@@ -54,8 +59,7 @@ class EntryFragment: DatabaseFragment() {
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
return inflater.cloneInContext(contextThemed) return inflater.inflate(R.layout.fragment_entry, container, false)
.inflate(R.layout.fragment_entry, container, false)
} }
override fun onViewCreated(view: View, override fun onViewCreated(view: View,
@@ -71,6 +75,10 @@ class EntryFragment: DatabaseFragment() {
if (savedInstanceState == null) { if (savedInstanceState == null) {
view.isVisible = false view.isVisible = false
} }
mainSection = view.findViewById(R.id.entry_section_main)
advancedSection = view.findViewById(R.id.entry_section_advanced)
templateView = view.findViewById(R.id.entry_template) templateView = view.findViewById(R.id.entry_template)
loadTemplateSettings() loadTemplateSettings()
@@ -84,11 +92,13 @@ class EntryFragment: DatabaseFragment() {
creationDateView = view.findViewById(R.id.entry_created) creationDateView = view.findViewById(R.id.entry_created)
modificationDateView = view.findViewById(R.id.entry_modified) modificationDateView = view.findViewById(R.id.entry_modified)
// TODO Custom data
// customDataView = view.findViewById(R.id.entry_custom_data)
uuidContainerView = view.findViewById(R.id.entry_UUID_container) uuidContainerView = view.findViewById(R.id.entry_UUID_container)
uuidContainerView.apply { uuidContainerView.apply {
visibility = if (PreferencesUtil.showUUID(context)) View.VISIBLE else View.GONE visibility = if (PreferencesUtil.showUUID(context)) View.VISIBLE else View.GONE
} }
uuidView = view.findViewById(R.id.entry_UUID)
uuidReferenceView = view.findViewById(R.id.entry_UUID_reference) uuidReferenceView = view.findViewById(R.id.entry_UUID_reference)
mEntryViewModel.entryInfoHistory.observe(viewLifecycleOwner) { entryInfoHistory -> mEntryViewModel.entryInfoHistory.observe(viewLifecycleOwner) { entryInfoHistory ->
@@ -108,9 +118,22 @@ class EntryFragment: DatabaseFragment() {
} }
} }
} }
mEntryViewModel.sectionSelected.observe(viewLifecycleOwner) { entrySection ->
when (entrySection ?: EntryViewModel.EntrySection.MAIN) {
EntryViewModel.EntrySection.MAIN -> {
mainSection.showByFading()
advancedSection.hideByFading()
}
EntryViewModel.EntrySection.ADVANCED -> {
mainSection.hideByFading()
advancedSection.showByFading()
}
}
}
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
context?.let { context -> context?.let { context ->
attachmentsAdapter = EntryAttachmentsItemsAdapter(context) attachmentsAdapter = EntryAttachmentsItemsAdapter(context)
attachmentsAdapter?.database = database attachmentsAdapter?.database = database
@@ -135,11 +158,9 @@ class EntryFragment: DatabaseFragment() {
setOnCopyActionClickListener { field -> setOnCopyActionClickListener { field ->
mClipboardHelper?.timeoutCopyToClipboard( mClipboardHelper?.timeoutCopyToClipboard(
TemplateField.getLocalizedName(context, field.name),
field.protectedValue.stringValue, field.protectedValue.stringValue,
getString( field.protectedValue.isProtected
R.string.copy_field,
TemplateField.getLocalizedName(context, field.name)
)
) )
} }
} }
@@ -156,11 +177,14 @@ class EntryFragment: DatabaseFragment() {
assignAttachments(entryInfo?.attachments ?: listOf()) assignAttachments(entryInfo?.attachments ?: listOf())
// Assign dates // Assign dates
assignCreationDate(entryInfo?.creationTime) creationDateView.text = entryInfo?.creationTime?.getDateTimeString(resources)
assignModificationDate(entryInfo?.lastModificationTime) modificationDateView.text = entryInfo?.lastModificationTime?.getDateTimeString(resources)
// TODO Custom data
// customDataView.text = entryInfo?.customData?.toString()
// Assign special data // Assign special data
assignUUID(entryInfo?.id) uuidReferenceView.text = UuidUtil.toHexString(entryInfo?.id)
} }
private fun showClipboardDialog() { private fun showClipboardDialog() {
@@ -191,19 +215,6 @@ class EntryFragment: DatabaseFragment() {
templateView.reload() templateView.reload()
} }
private fun assignCreationDate(date: DateInstant?) {
creationDateView.text = date?.getDateTimeString(resources)
}
private fun assignModificationDate(date: DateInstant?) {
modificationDateView.text = date?.getDateTimeString(resources)
}
private fun assignUUID(uuid: UUID?) {
uuidView.text = uuid?.toString()
uuidReferenceView.text = UuidUtil.toHexString(uuid)
}
/* ------------- /* -------------
* Attachments * Attachments
* ------------- * -------------
@@ -238,8 +249,7 @@ class EntryFragment: DatabaseFragment() {
fun launchEntryCopyEducationAction() { fun launchEntryCopyEducationAction() {
val appNameString = getString(R.string.app_name) val appNameString = getString(R.string.app_name)
mClipboardHelper?.timeoutCopyToClipboard(appNameString, mClipboardHelper?.timeoutCopyToClipboard(appNameString, appNameString)
getString(R.string.copy_field, appNameString))
} }
companion object { companion object {

View File

@@ -4,16 +4,16 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.StylishFragment
import com.kunzisoft.keepass.adapters.EntryHistoryAdapter import com.kunzisoft.keepass.adapters.EntryHistoryAdapter
import com.kunzisoft.keepass.model.EntryInfo import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.viewmodels.EntryViewModel import com.kunzisoft.keepass.viewmodels.EntryViewModel
class EntryHistoryFragment: StylishFragment() { class EntryHistoryFragment: Fragment() {
private lateinit var historyContainerView: View private lateinit var historyContainerView: View
private lateinit var historyListView: RecyclerView private lateinit var historyListView: RecyclerView
@@ -28,8 +28,7 @@ class EntryHistoryFragment: StylishFragment() {
): View? { ): View? {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
return inflater.cloneInContext(contextThemed) return inflater.inflate(R.layout.fragment_entry_history, container, false)
.inflate(R.layout.fragment_entry_history, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@@ -20,40 +20,45 @@
package com.kunzisoft.keepass.activities.fragments package com.kunzisoft.keepass.activities.fragments
import android.content.Context import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.* import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.core.view.MenuProvider
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.EntryEditActivity
import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment import com.kunzisoft.keepass.activities.dialogs.SortDialogFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.adapters.NodeAdapter import com.kunzisoft.keepass.adapters.NodesAdapter
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.Group import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.SortNodeEnum import com.kunzisoft.keepass.database.element.SortNodeEnum
import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.KeyboardUtil.hideKeyboard
import com.kunzisoft.keepass.viewmodels.GroupViewModel import com.kunzisoft.keepass.viewmodels.GroupViewModel
import java.util.* import java.util.LinkedList
class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListener { class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListener {
private var nodeClickListener: NodeClickListener? = null private var nodeClickListener: NodeClickListener? = null
private var onScrollListener: OnScrollListener? = null private var onScrollListener: OnScrollListener? = null
private var groupRefreshed: GroupRefreshedListener? = null
private var mNodesRecyclerView: RecyclerView? = null private var mNodesRecyclerView: RecyclerView? = null
private var mLayoutManager: LinearLayoutManager? = null private var mLayoutManager: LinearLayoutManager? = null
private var mAdapter: NodeAdapter? = null private var mAdapter: NodesAdapter? = null
private val mGroupViewModel: GroupViewModel by activityViewModels() private val mGroupViewModel: GroupViewModel by activityViewModels()
@@ -74,9 +79,6 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
private var mRecycleBinEnable: Boolean = false private var mRecycleBinEnable: Boolean = false
private var mRecycleBin: Group? = null private var mRecycleBin: Group? = null
val isEmpty: Boolean
get() = mAdapter == null || mAdapter?.itemCount?:0 <= 0
private var mRecycleViewScrollListener = object : RecyclerView.OnScrollListener() { private var mRecycleViewScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState) super.onScrollStateChanged(recyclerView, newState)
@@ -90,14 +92,50 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
} }
private val menuProvider: MenuProvider = object: MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.tree, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.menu_sort -> {
context?.let { context ->
val sortDialogFragment: SortDialogFragment =
if (mRecycleBinEnable) {
SortDialogFragment.getInstance(
PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context),
PreferencesUtil.getRecycleBinBottomSort(context)
)
} else {
SortDialogFragment.getInstance(
PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context)
)
}
sortDialogFragment.show(childFragmentManager, "sortDialog")
}
true
}
else -> false
}
}
}
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
// TODO Change to ViewModel
try { try {
nodeClickListener = context as NodeClickListener nodeClickListener = context as NodeClickListener
} catch (e: ClassCastException) { } catch (e: ClassCastException) {
// The activity doesn't implement the interface, throw exception // The activity doesn't implement the interface, throw exception
throw ClassCastException(context.toString() throw ClassCastException(context.toString()
+ " must implement " + NodeAdapter.NodeClickCallback::class.java.name) + " must implement " + NodesAdapter.NodeClickCallback::class.java.name)
} }
try { try {
@@ -105,32 +143,36 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} catch (e: ClassCastException) { } catch (e: ClassCastException) {
onScrollListener = null onScrollListener = null
// Context menu can be omit // Context menu can be omit
Log.w(TAG, context.toString() Log.w(
TAG, context.toString()
+ " must implement " + RecyclerView.OnScrollListener::class.java.name) + " must implement " + RecyclerView.OnScrollListener::class.java.name)
} }
try {
groupRefreshed = context as GroupRefreshedListener
} catch (e: ClassCastException) {
// The activity doesn't implement the interface, throw exception
throw ClassCastException(context.toString()
+ " must implement " + GroupRefreshedListener::class.java.name)
}
} }
override fun onDetach() { override fun onDetach() {
nodeClickListener = null nodeClickListener = null
onScrollListener = null onScrollListener = null
groupRefreshed = null
super.onDetach() super.onDetach()
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onDatabaseRetrieved(database: Database?) {
mRecycleBinEnable = database?.isRecycleBinEnabled == true mRecycleBinEnable = database?.isRecycleBinEnabled == true
mRecycleBin = database?.recycleBin mRecycleBin = database?.recycleBin
contextThemed?.let { context -> context?.let { context ->
database?.let { database -> database?.let { database ->
mAdapter = NodeAdapter(context, database).apply { mAdapter = NodesAdapter(context, database).apply {
setOnNodeClickListener(object : NodeAdapter.NodeClickCallback { setOnNodeClickListener(object : NodesAdapter.NodeClickCallback {
override fun onNodeClick(database: Database, node: Node) { override fun onNodeClick(database: ContextualDatabase, node: Node) {
if (nodeActionSelectionMode) { if (nodeActionSelectionMode) {
if (listActionNodes.contains(node)) { if (listActionNodes.contains(node)) {
// Remove selected item if already selected // Remove selected item if already selected
@@ -147,7 +189,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
} }
override fun onNodeLongClick(database: Database, node: Node): Boolean { override fun onNodeLongClick(database: ContextualDatabase, node: Node): Boolean {
if (nodeActionPasteMode == PasteMode.UNDEFINED) { if (nodeActionPasteMode == PasteMode.UNDEFINED) {
// Select the first item after a long click // Select the first item after a long click
if (!listActionNodes.contains(node)) if (!listActionNodes.contains(node))
@@ -157,6 +199,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
setActionNodes(listActionNodes) setActionNodes(listActionNodes)
notifyNodeChanged(node) notifyNodeChanged(node)
activity?.hideKeyboard()
} }
return true return true
} }
@@ -168,7 +211,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {
@@ -184,13 +227,14 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
// To apply theme // To apply theme
return inflater.cloneInContext(contextThemed) return inflater.inflate(R.layout.fragment_nodes, container, false)
.inflate(R.layout.fragment_group, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
activity?.addMenuProvider(menuProvider, viewLifecycleOwner)
mNodesRecyclerView = view.findViewById(R.id.nodes_list) mNodesRecyclerView = view.findViewById(R.id.nodes_list)
notFoundView = view.findViewById(R.id.not_found_container) notFoundView = view.findViewById(R.id.not_found_container)
@@ -219,8 +263,6 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
activity?.intent?.let { activity?.intent?.let {
specialMode = EntrySelectionHelper.retrieveSpecialModeFromIntent(it) specialMode = EntrySelectionHelper.retrieveSpecialModeFromIntent(it)
} }
rebuildList()
} }
override fun onPause() { override fun onPause() {
@@ -236,9 +278,9 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
private fun rebuildList() { private fun rebuildList() {
try { try {
// Add elements to the list // Add elements to the list
mCurrentGroup?.let { mainGroup -> mCurrentGroup?.let { currentGroup ->
// Thrown an exception when sort cannot be performed // Thrown an exception when sort cannot be performed
mAdapter?.rebuildList(mainGroup) mAdapter?.rebuildList(currentGroup)
} }
} catch (e:Exception) { } catch (e:Exception) {
Log.e(TAG, "Unable to rebuild the list", e) Log.e(TAG, "Unable to rebuild the list", e)
@@ -250,6 +292,8 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} else { } else {
notFoundView?.visibility = View.GONE notFoundView?.visibility = View.GONE
} }
groupRefreshed?.onGroupRefreshed()
} }
override fun onSortSelected(sortNodeEnum: SortNodeEnum, override fun onSortSelected(sortNodeEnum: SortNodeEnum,
@@ -268,41 +312,7 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { fun actionNodesCallback(database: ContextualDatabase,
inflater.inflate(R.menu.tree, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_sort -> {
context?.let { context ->
val sortDialogFragment: SortDialogFragment =
if (mRecycleBinEnable) {
SortDialogFragment.getInstance(
PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context),
PreferencesUtil.getRecycleBinBottomSort(context))
} else {
SortDialogFragment.getInstance(
PreferencesUtil.getListSort(context),
PreferencesUtil.getAscendingSort(context),
PreferencesUtil.getGroupsBeforeSort(context))
}
sortDialogFragment.show(childFragmentManager, "sortDialog")
}
return true
}
else -> return super.onOptionsItemSelected(item)
}
}
fun actionNodesCallback(database: Database,
nodes: List<Node>, nodes: List<Node>,
menuListener: NodesActionMenuListener?, menuListener: NodesActionMenuListener?,
onDestroyActionMode: (mode: ActionMode?) -> Unit) : ActionMode.Callback { onDestroyActionMode: (mode: ActionMode?) -> Unit) : ActionMode.Callback {
@@ -336,14 +346,12 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
// Move // Move
if (database.isReadOnly if (database.isReadOnly) {
|| isASearchResult) {
menu?.removeItem(R.id.menu_move) menu?.removeItem(R.id.menu_move)
} }
// Copy (not allowed for group) // Copy (not allowed for group)
if (database.isReadOnly if (database.isReadOnly
|| isASearchResult
|| nodes.any { it.type == Type.GROUP }) { || nodes.any { it.type == Type.GROUP }) {
menu?.removeItem(R.id.menu_copy) menu?.removeItem(R.id.menu_copy)
} }
@@ -402,45 +410,24 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
} }
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE -> {
if (resultCode == EntryEditActivity.ADD_OR_UPDATE_ENTRY_RESULT_CODE) {
data?.getParcelableExtra<NodeId<UUID>>(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY)?.let {
// Simply refresh the list
rebuildList()
// Scroll to the new entry
mDatabase?.getEntryById(it)?.let { entry ->
mAdapter?.indexOf(entry)?.let { position ->
mNodesRecyclerView?.scrollToPosition(position)
}
}
} ?: Log.e(this.javaClass.name, "Entry cannot be retrieved in Activity Result")
}
}
}
}
/** /**
* Callback listener to redefine to do an action when a node is click * Callback listener to redefine to do an action when a node is click
*/ */
interface NodeClickListener { interface NodeClickListener {
fun onNodeClick(database: Database, node: Node) fun onNodeClick(database: ContextualDatabase, node: Node)
fun onNodeSelected(database: Database, nodes: List<Node>): Boolean fun onNodeSelected(database: ContextualDatabase, nodes: List<Node>): Boolean
} }
/** /**
* Menu listener to redefine to do an action in menu * Menu listener to redefine to do an action in menu
*/ */
interface NodesActionMenuListener { interface NodesActionMenuListener {
fun onOpenMenuClick(database: Database, node: Node): Boolean fun onOpenMenuClick(database: ContextualDatabase, node: Node): Boolean
fun onEditMenuClick(database: Database, node: Node): Boolean fun onEditMenuClick(database: ContextualDatabase, node: Node): Boolean
fun onCopyMenuClick(database: Database, nodes: List<Node>): Boolean fun onCopyMenuClick(database: ContextualDatabase, nodes: List<Node>): Boolean
fun onMoveMenuClick(database: Database, nodes: List<Node>): Boolean fun onMoveMenuClick(database: ContextualDatabase, nodes: List<Node>): Boolean
fun onDeleteMenuClick(database: Database, nodes: List<Node>): Boolean fun onDeleteMenuClick(database: ContextualDatabase, nodes: List<Node>): Boolean
fun onPasteMenuClick(database: Database, pasteMode: PasteMode?, nodes: List<Node>): Boolean fun onPasteMenuClick(database: ContextualDatabase, pasteMode: PasteMode?, nodes: List<Node>): Boolean
} }
enum class PasteMode { enum class PasteMode {
@@ -458,6 +445,10 @@ class GroupFragment : DatabaseFragment(), SortDialogFragment.SortSelectionListen
fun onScrolled(dy: Int) fun onScrolled(dy: Int)
} }
interface GroupRefreshedListener {
fun onGroupRefreshed()
}
companion object { companion object {
private val TAG = GroupFragment::class.java.name private val TAG = GroupFragment::class.java.name
} }

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.activities.fragments
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImageCustom import com.kunzisoft.keepass.database.element.icon.IconImageCustom
@@ -32,7 +32,7 @@ class IconCustomFragment : IconFragment<IconImageCustom>() {
return R.layout.fragment_icon_grid return R.layout.fragment_icon_grid
} }
override fun defineIconList(database: Database?) { override fun defineIconList(database: ContextualDatabase?) {
database?.doForEachCustomIcons { customIcon, _ -> database?.doForEachCustomIcons { customIcon, _ ->
iconPickerAdapter.addIcon(customIcon, false) iconPickerAdapter.addIcon(customIcon, false)
} }
@@ -55,8 +55,10 @@ class IconCustomFragment : IconFragment<IconImageCustom>() {
iconCustomAdded?.iconCustom?.let { icon -> iconCustomAdded?.iconCustom?.let { icon ->
iconPickerAdapter.addIcon(icon) iconPickerAdapter.addIcon(icon)
iconCustomAdded.iconCustom = null iconCustomAdded.iconCustom = null
try {
iconsGridView.smoothScrollToPosition(iconPickerAdapter.lastPosition)
} catch (ignore: Exception) {}
} }
iconsGridView.smoothScrollToPosition(iconPickerAdapter.lastPosition)
} }
} }
iconPickerViewModel.customIconRemoved.observe(viewLifecycleOwner) { iconCustomRemoved -> iconPickerViewModel.customIconRemoved.observe(viewLifecycleOwner) { iconCustomRemoved ->
@@ -67,6 +69,14 @@ class IconCustomFragment : IconFragment<IconImageCustom>() {
} }
} }
} }
iconPickerViewModel.customIconUpdated.observe(viewLifecycleOwner) { iconCustomUpdated ->
if (!iconCustomUpdated.error) {
iconCustomUpdated?.iconCustom?.let { icon ->
iconPickerAdapter.updateIcon(icon)
iconCustomUpdated.iconCustom = null
}
}
}
} }
override fun onIconClickListener(icon: IconImageCustom) { override fun onIconClickListener(icon: IconImageCustom) {

View File

@@ -28,7 +28,7 @@ import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.IconPickerAdapter import com.kunzisoft.keepass.adapters.IconPickerAdapter
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImageDraw import com.kunzisoft.keepass.database.element.icon.IconImageDraw
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -47,7 +47,7 @@ abstract class IconFragment<T: IconImageDraw> : DatabaseFragment(),
abstract fun retrieveMainLayoutId(): Int abstract fun retrieveMainLayoutId(): Int
abstract fun defineIconList(database: Database?) abstract fun defineIconList(database: ContextualDatabase?)
override fun onCreateView(inflater: LayoutInflater, override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@@ -59,7 +59,7 @@ abstract class IconFragment<T: IconImageDraw> : DatabaseFragment(),
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// Retrieve the textColor to tint the icon // Retrieve the textColor to tint the icon
val ta = contextThemed?.obtainStyledAttributes(intArrayOf(android.R.attr.textColor)) val ta = context?.obtainStyledAttributes(intArrayOf(android.R.attr.textColor))
val tintColor = ta?.getColor(0, Color.BLACK) ?: Color.BLACK val tintColor = ta?.getColor(0, Color.BLACK) ?: Color.BLACK
ta?.recycle() ta?.recycle()
@@ -71,7 +71,7 @@ abstract class IconFragment<T: IconImageDraw> : DatabaseFragment(),
resetAppTimeoutWhenViewFocusedOrChanged(view) resetAppTimeoutWhenViewFocusedOrChanged(view)
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
iconPickerAdapter.iconDrawableFactory = database?.iconDrawableFactory iconPickerAdapter.iconDrawableFactory = database?.iconDrawableFactory
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {

View File

@@ -10,7 +10,7 @@ import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.IconPickerPagerAdapter import com.kunzisoft.keepass.adapters.IconPickerPagerAdapter
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.viewmodels.IconPickerViewModel import com.kunzisoft.keepass.viewmodels.IconPickerViewModel
class IconPickerFragment : DatabaseFragment() { class IconPickerFragment : DatabaseFragment() {
@@ -26,14 +26,14 @@ class IconPickerFragment : DatabaseFragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
return inflater.inflate(R.layout.fragment_icon_picker, container, false) return inflater.inflate(R.layout.fragment_tabs_pagination, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewPager = view.findViewById(R.id.icon_picker_pager) viewPager = view.findViewById(R.id.tabs_view_pager)
tabLayout = view.findViewById(R.id.icon_picker_tabs) tabLayout = view.findViewById(R.id.tabs_layout)
resetAppTimeoutWhenViewFocusedOrChanged(view) resetAppTimeoutWhenViewFocusedOrChanged(view)
arguments?.apply { arguments?.apply {
@@ -48,7 +48,7 @@ class IconPickerFragment : DatabaseFragment() {
} }
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
iconPickerPagerAdapter = IconPickerPagerAdapter(this, iconPickerPagerAdapter = IconPickerPagerAdapter(this,
if (database?.allowCustomIcons == true) 2 else 1) if (database?.allowCustomIcons == true) 2 else 1)
viewPager.adapter = iconPickerPagerAdapter viewPager.adapter = iconPickerPagerAdapter

View File

@@ -20,7 +20,7 @@
package com.kunzisoft.keepass.activities.fragments package com.kunzisoft.keepass.activities.fragments
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.element.icon.IconImageStandard import com.kunzisoft.keepass.database.element.icon.IconImageStandard
@@ -30,7 +30,7 @@ class IconStandardFragment : IconFragment<IconImageStandard>() {
return R.layout.fragment_icon_grid return R.layout.fragment_icon_grid
} }
override fun defineIconList(database: Database?) { override fun defineIconList(database: ContextualDatabase?) {
database?.doForEachStandardIcons { standardIcon -> database?.doForEachStandardIcons { standardIcon ->
iconPickerAdapter.addIcon(standardIcon, false) iconPickerAdapter.addIcon(standardIcon, false)
} }

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2022 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.activities.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.fragment.app.activityViewModels
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.adapters.KeyGeneratorPagerAdapter
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.viewmodels.KeyGeneratorViewModel
class KeyGeneratorFragment : DatabaseFragment() {
private var keyGeneratorPagerAdapter: KeyGeneratorPagerAdapter? = null
private lateinit var viewPager: ViewPager2
private lateinit var tabLayout: TabLayout
private val mKeyGeneratorViewModel: KeyGeneratorViewModel by activityViewModels()
private var mSelectedTab = KeyGeneratorTab.PASSWORD
private var mOnPageChangeCallback: ViewPager2.OnPageChangeCallback = object:
ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
mSelectedTab = KeyGeneratorTab.getKeyGeneratorTabByPosition(position)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_tabs_pagination, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
keyGeneratorPagerAdapter = KeyGeneratorPagerAdapter(this, )
viewPager = view.findViewById(R.id.tabs_view_pager)
tabLayout = view.findViewById(R.id.tabs_layout)
viewPager.adapter = keyGeneratorPagerAdapter
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = getString(KeyGeneratorTab.getKeyGeneratorTabByPosition(position).stringId)
}.attach()
viewPager.registerOnPageChangeCallback(mOnPageChangeCallback)
resetAppTimeoutWhenViewFocusedOrChanged(view)
arguments?.apply {
if (containsKey(PASSWORD_TAB_ARG)) {
viewPager.currentItem = getInt(PASSWORD_TAB_ARG)
}
remove(PASSWORD_TAB_ARG)
}
mKeyGeneratorViewModel.requireKeyGeneration.observe(viewLifecycleOwner) {
when (mSelectedTab) {
KeyGeneratorTab.PASSWORD -> {
mKeyGeneratorViewModel.requirePasswordGeneration()
}
KeyGeneratorTab.PASSPHRASE -> {
mKeyGeneratorViewModel.requirePassphraseGeneration()
}
}
}
mKeyGeneratorViewModel.keyGeneratedValidated.observe(viewLifecycleOwner) {
when (mSelectedTab) {
KeyGeneratorTab.PASSWORD -> {
mKeyGeneratorViewModel.validatePasswordGenerated()
}
KeyGeneratorTab.PASSPHRASE -> {
mKeyGeneratorViewModel.validatePassphraseGenerated()
}
}
}
}
override fun onDestroyView() {
viewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback)
super.onDestroyView()
}
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Nothing here
}
enum class KeyGeneratorTab(@StringRes val stringId: Int) {
PASSWORD(R.string.password), PASSPHRASE(R.string.passphrase);
companion object {
fun getKeyGeneratorTabByPosition(position: Int): KeyGeneratorTab {
return when (position) {
0 -> PASSWORD
else -> PASSPHRASE
}
}
}
}
companion object {
private const val PASSWORD_TAB_ARG = "PASSWORD_TAB_ARG"
fun getInstance(keyGeneratorTab: KeyGeneratorTab): KeyGeneratorFragment {
val fragment = KeyGeneratorFragment()
fragment.arguments = Bundle().apply {
putInt(PASSWORD_TAB_ARG, keyGeneratorTab.ordinal)
}
return fragment
}
}
}

View File

@@ -0,0 +1,254 @@
/*
* Copyright 2022 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.activities.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.activityViewModels
import com.google.android.material.slider.Slider
import com.kunzisoft.keepass.R
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.viewmodels.KeyGeneratorViewModel
class PassphraseGeneratorFragment : DatabaseFragment() {
private lateinit var passKeyView: PassKeyView
private lateinit var sliderWordCount: Slider
private lateinit var wordCountText: EditText
private lateinit var charactersCountText: TextView
private lateinit var wordSeparator: EditText
private lateinit var wordCaseSpinner: Spinner
private var minSliderWordCount: Int = 0
private var maxSliderWordCount: Int = 0
private var wordCaseAdapter: ArrayAdapter<String>? = null
private val mKeyGeneratorViewModel: KeyGeneratorViewModel by activityViewModels()
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_generate_passphrase, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
passKeyView = 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)
charactersCountText = view.findViewById(R.id.character_count)
wordSeparator = view.findViewById(R.id.word_separator)
wordCaseSpinner = view.findViewById(R.id.word_case)
minSliderWordCount = resources.getInteger(R.integer.passphrase_generator_word_count_min)
maxSliderWordCount = resources.getInteger(R.integer.passphrase_generator_word_count_max)
context?.let { context ->
passphraseCopyView?.visibility = if(PreferencesUtil.allowCopyProtectedFields(context))
View.VISIBLE else View.GONE
val clipboardHelper = ClipboardHelper(context)
passphraseCopyView?.setOnClickListener {
clipboardHelper.timeoutCopyToClipboard(
getString(R.string.passphrase),
passKeyView.passwordString,
true
)
}
wordCaseAdapter = ArrayAdapter(context,
android.R.layout.simple_spinner_item, resources.getStringArray(R.array.word_case_array)).apply {
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
}
wordCaseSpinner.adapter = wordCaseAdapter
}
loadSettings()
var listenSlider = true
var listenEditText = true
sliderWordCount.addOnChangeListener { _, value, _ ->
try {
listenEditText = false
if (listenSlider) {
wordCountText.setText(value.toInt().toString())
}
} catch (e: Exception) {
Log.e(TAG, "Unable to set the word count value", e)
} finally {
listenEditText = true
}
}
sliderWordCount.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
// TODO upgrade material-components lib
// https://stackoverflow.com/questions/70873160/material-slider-onslidertouchlisteners-methods-can-only-be-called-from-within-t
@SuppressLint("RestrictedApi")
override fun onStartTrackingTouch(slider: Slider) {}
@SuppressLint("RestrictedApi")
override fun onStopTrackingTouch(slider: Slider) {
generatePassphrase()
}
})
wordCountText.doOnTextChanged { _, _, _, _ ->
if (listenEditText) {
try {
listenSlider = false
setSliderValue(getWordCount())
} catch (e: Exception) {
Log.e(TAG, "Unable to get the word count value", e)
} finally {
listenSlider = true
generatePassphrase()
}
}
}
wordSeparator.doOnTextChanged { _, _, _, _ ->
generatePassphrase()
}
wordCaseSpinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
generatePassphrase()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
generatePassphrase()
mKeyGeneratorViewModel.passphraseGeneratedValidated.observe(viewLifecycleOwner) {
mKeyGeneratorViewModel.setKeyGenerated(passKeyView.passwordString)
}
mKeyGeneratorViewModel.requirePassphraseGeneration.observe(viewLifecycleOwner) {
generatePassphrase()
}
resetAppTimeoutWhenViewFocusedOrChanged(view)
}
private fun getWordCount(): Int {
return try {
Integer.valueOf(wordCountText.text.toString())
} catch (numberException: NumberFormatException) {
minSliderWordCount
}
}
private fun setWordCount(wordCount: Int) {
setSliderValue(wordCount)
wordCountText.setText(wordCount.toString())
}
private fun setSliderValue(value: Int) {
when {
value < minSliderWordCount -> {
sliderWordCount.value = minSliderWordCount.toFloat()
}
value > maxSliderWordCount -> {
sliderWordCount.value = maxSliderWordCount.toFloat()
}
else -> {
sliderWordCount.value = value.toFloat()
}
}
}
private fun getWordSeparator(): String {
return wordSeparator.text.toString().ifEmpty { " " }
}
private fun getWordCase(): PassphraseGenerator.WordCase {
var wordCase = PassphraseGenerator.WordCase.LOWER_CASE
try {
wordCase = PassphraseGenerator.WordCase.getByOrdinal(wordCaseSpinner.selectedItemPosition)
} catch (caseException: Exception) {
Log.e(TAG, "Unable to retrieve the word case", caseException)
}
return wordCase
}
private fun setWordCase(wordCase: PassphraseGenerator.WordCase) {
wordCaseSpinner.setSelection(wordCase.ordinal)
}
private fun getSeparator(): String {
return wordSeparator.text?.toString() ?: ""
}
private fun setSeparator(separator: String) {
wordSeparator.setText(separator)
}
private fun generatePassphrase() {
var passphrase = ""
try {
passphrase = PassphraseGenerator().generatePassphrase(
getWordCount(),
getWordSeparator(),
getWordCase())
} catch (e: Exception) {
Log.e(TAG, "Unable to generate a passphrase", e)
}
passKeyView.passwordString = passphrase
charactersCountText.text = getString(R.string.character_count, passphrase.length)
}
override fun onDestroy() {
saveSettings()
super.onDestroy()
}
private fun saveSettings() {
context?.let { context ->
PreferencesUtil.setDefaultPassphraseWordCount(context, getWordCount())
PreferencesUtil.setDefaultPassphraseWordCase(context, getWordCase())
PreferencesUtil.setDefaultPassphraseSeparator(context, getSeparator())
}
}
private fun loadSettings() {
context?.let { context ->
setWordCount(PreferencesUtil.getDefaultPassphraseWordCount(context))
setWordCase(PreferencesUtil.getDefaultPassphraseWordCase(context))
setSeparator(PreferencesUtil.getDefaultPassphraseSeparator(context))
}
}
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Nothing here
}
companion object {
private const val TAG = "PassphraseGnrtrFrgmt"
}
}

View File

@@ -0,0 +1,360 @@
/*
* Copyright 2019 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.activities.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import android.widget.EditText
import android.widget.ImageView
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.activityViewModels
import com.google.android.material.slider.Slider
import com.kunzisoft.keepass.R
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.viewmodels.KeyGeneratorViewModel
class PasswordGeneratorFragment : DatabaseFragment() {
private lateinit var passKeyView: PassKeyView
private lateinit var sliderLength: Slider
private lateinit var lengthEditView: EditText
private lateinit var uppercaseCompound: CompoundButton
private lateinit var lowercaseCompound: CompoundButton
private lateinit var digitsCompound: CompoundButton
private lateinit var minusCompound: CompoundButton
private lateinit var underlineCompound: CompoundButton
private lateinit var spaceCompound: CompoundButton
private lateinit var specialsCompound: CompoundButton
private lateinit var bracketsCompound: CompoundButton
private lateinit var extendedCompound: CompoundButton
private lateinit var considerCharsEditText: EditText
private lateinit var ignoreCharsEditText: EditText
private lateinit var atLeastOneCompound: CompoundButton
private lateinit var excludeAmbiguousCompound: CompoundButton
private var minLengthSlider: Int = 0
private var maxLengthSlider: Int = 0
private val mKeyGeneratorViewModel: KeyGeneratorViewModel by activityViewModels()
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_generate_password, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
passKeyView = view.findViewById(R.id.password_view)
val passwordCopyView: ImageView? = view.findViewById(R.id.password_copy_button)
sliderLength = view.findViewById(R.id.slider_length)
lengthEditView = view.findViewById(R.id.length)
uppercaseCompound = view.findViewById(R.id.upperCase_filter)
lowercaseCompound = view.findViewById(R.id.lowerCase_filter)
digitsCompound = view.findViewById(R.id.digits_filter)
minusCompound = view.findViewById(R.id.minus_filter)
underlineCompound = view.findViewById(R.id.underline_filter)
spaceCompound = view.findViewById(R.id.space_filter)
specialsCompound = view.findViewById(R.id.special_filter)
bracketsCompound = view.findViewById(R.id.brackets_filter)
extendedCompound = view.findViewById(R.id.extendedASCII_filter)
considerCharsEditText = view.findViewById(R.id.consider_chars_filter)
ignoreCharsEditText = view.findViewById(R.id.ignore_chars_filter)
atLeastOneCompound = view.findViewById(R.id.atLeastOne_filter)
excludeAmbiguousCompound = view.findViewById(R.id.excludeAmbiguous_filter)
context?.let { context ->
passwordCopyView?.visibility = if(PreferencesUtil.allowCopyProtectedFields(context))
View.VISIBLE else View.GONE
val clipboardHelper = ClipboardHelper(context)
passwordCopyView?.setOnClickListener {
clipboardHelper.timeoutCopyToClipboard(
getString(R.string.password),
passKeyView.passwordString,
true
)
}
}
minLengthSlider = resources.getInteger(R.integer.password_generator_length_min)
maxLengthSlider = resources.getInteger(R.integer.password_generator_length_max)
loadSettings()
uppercaseCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
lowercaseCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
digitsCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
minusCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
underlineCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
spaceCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
specialsCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
bracketsCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
extendedCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
considerCharsEditText.doOnTextChanged { _, _, _, _ ->
generatePassword()
}
ignoreCharsEditText.doOnTextChanged { _, _, _, _ ->
generatePassword()
}
atLeastOneCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
excludeAmbiguousCompound.setOnCheckedChangeListener { _, _ ->
generatePassword()
}
var listenSlider = true
var listenEditText = true
sliderLength.addOnChangeListener { _, value, _ ->
try {
listenEditText = false
if (listenSlider) {
lengthEditView.setText(value.toInt().toString())
}
} catch (e: Exception) {
Log.e(TAG, "Unable to set the length value", e)
} finally {
listenEditText = true
}
}
sliderLength.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
// TODO upgrade material-components lib
// https://stackoverflow.com/questions/70873160/material-slider-onslidertouchlisteners-methods-can-only-be-called-from-within-t
@SuppressLint("RestrictedApi")
override fun onStartTrackingTouch(slider: Slider) {}
@SuppressLint("RestrictedApi")
override fun onStopTrackingTouch(slider: Slider) {
generatePassword()
}
})
lengthEditView.doOnTextChanged { _, _, _, _ ->
if (listenEditText) {
try {
listenSlider = false
setSliderValue(getPasswordLength())
} catch (e: Exception) {
Log.e(TAG, "Unable to get the length value", e)
} finally {
listenSlider = true
generatePassword()
}
}
}
// Pre-populate a password to possibly save the user a few clicks
generatePassword()
mKeyGeneratorViewModel.passwordGeneratedValidated.observe(viewLifecycleOwner) {
mKeyGeneratorViewModel.setKeyGenerated(passKeyView.passwordString)
}
mKeyGeneratorViewModel.requirePasswordGeneration.observe(viewLifecycleOwner) {
generatePassword()
}
resetAppTimeoutWhenViewFocusedOrChanged(view)
}
private fun getPasswordLength(): Int {
return try {
Integer.valueOf(lengthEditView.text.toString())
} catch (numberException: NumberFormatException) {
minLengthSlider
}
}
private fun setPasswordLength(passwordLength: Int) {
setSliderValue(passwordLength)
lengthEditView.setText(passwordLength.toString())
}
private fun getOptions(): Set<String> {
val optionsSet = mutableSetOf<String>()
if (uppercaseCompound.isChecked)
optionsSet.add(getString(R.string.value_password_uppercase))
if (lowercaseCompound.isChecked)
optionsSet.add(getString(R.string.value_password_lowercase))
if (digitsCompound.isChecked)
optionsSet.add(getString(R.string.value_password_digits))
if (minusCompound.isChecked)
optionsSet.add(getString(R.string.value_password_minus))
if (underlineCompound.isChecked)
optionsSet.add(getString(R.string.value_password_underline))
if (spaceCompound.isChecked)
optionsSet.add(getString(R.string.value_password_space))
if (specialsCompound.isChecked)
optionsSet.add(getString(R.string.value_password_special))
if (bracketsCompound.isChecked)
optionsSet.add(getString(R.string.value_password_brackets))
if (extendedCompound.isChecked)
optionsSet.add(getString(R.string.value_password_extended))
if (atLeastOneCompound.isChecked)
optionsSet.add(getString(R.string.value_password_atLeastOne))
if (excludeAmbiguousCompound.isChecked)
optionsSet.add(getString(R.string.value_password_excludeAmbiguous))
return optionsSet
}
private fun setOptions(options: Set<String>) {
uppercaseCompound.isChecked = false
lowercaseCompound.isChecked = false
digitsCompound.isChecked = false
minusCompound.isChecked = false
underlineCompound.isChecked = false
spaceCompound.isChecked = false
specialsCompound.isChecked = false
bracketsCompound.isChecked = false
extendedCompound.isChecked = false
atLeastOneCompound.isChecked = false
excludeAmbiguousCompound.isChecked = false
for (option in options) {
when (option) {
getString(R.string.value_password_uppercase) -> uppercaseCompound.isChecked = true
getString(R.string.value_password_lowercase) -> lowercaseCompound.isChecked = true
getString(R.string.value_password_digits) -> digitsCompound.isChecked = true
getString(R.string.value_password_minus) -> minusCompound.isChecked = true
getString(R.string.value_password_underline) -> underlineCompound.isChecked = true
getString(R.string.value_password_space) -> spaceCompound.isChecked = true
getString(R.string.value_password_special) -> specialsCompound.isChecked = true
getString(R.string.value_password_brackets) -> bracketsCompound.isChecked = true
getString(R.string.value_password_extended) -> extendedCompound.isChecked = true
getString(R.string.value_password_atLeastOne) -> atLeastOneCompound.isChecked = true
getString(R.string.value_password_excludeAmbiguous) -> excludeAmbiguousCompound.isChecked = true
}
}
}
private fun getConsiderChars(): String {
return considerCharsEditText.text.toString()
}
private fun setConsiderChars(chars: String) {
considerCharsEditText.setText(chars)
}
private fun getIgnoreChars(): String {
return ignoreCharsEditText.text.toString()
}
private fun setIgnoreChars(chars: String) {
ignoreCharsEditText.setText(chars)
}
private fun generatePassword() {
var password = ""
try {
password = PasswordGenerator(resources).generatePassword(getPasswordLength(),
uppercaseCompound.isChecked,
lowercaseCompound.isChecked,
digitsCompound.isChecked,
minusCompound.isChecked,
underlineCompound.isChecked,
spaceCompound.isChecked,
specialsCompound.isChecked,
bracketsCompound.isChecked,
extendedCompound.isChecked,
getConsiderChars(),
getIgnoreChars(),
atLeastOneCompound.isChecked,
excludeAmbiguousCompound.isChecked)
} catch (e: Exception) {
Log.e(TAG, "Unable to generate a password", e)
}
passKeyView.passwordString = password
}
override fun onDestroy() {
saveSettings()
super.onDestroy()
}
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
// Nothing here
}
private fun saveSettings() {
context?.let { context ->
PreferencesUtil.setDefaultPasswordOptions(context, getOptions())
PreferencesUtil.setDefaultPasswordLength(context, getPasswordLength())
PreferencesUtil.setDefaultPasswordConsiderChars(context, getConsiderChars())
PreferencesUtil.setDefaultPasswordIgnoreChars(context, getIgnoreChars())
}
}
private fun loadSettings() {
context?.let { context ->
setOptions(PreferencesUtil.getDefaultPasswordOptions(context))
setPasswordLength(PreferencesUtil.getDefaultPasswordLength(context))
setConsiderChars(PreferencesUtil.getDefaultPasswordConsiderChars(context))
setIgnoreChars(PreferencesUtil.getDefaultPasswordIgnoreChars(context))
}
}
private fun setSliderValue(value: Int) {
when {
value < minLengthSlider -> {
sliderLength.value = minLengthSlider.toFloat()
}
value > maxLengthSlider -> {
sliderLength.value = maxLengthSlider.toFloat()
}
else -> {
sliderLength.value = value.toFloat()
}
}
}
companion object {
private const val TAG = "PasswordGeneratorFrgmt"
}
}

View File

@@ -26,7 +26,9 @@ import com.kunzisoft.keepass.autofill.AutofillComponent
import com.kunzisoft.keepass.autofill.AutofillHelper import com.kunzisoft.keepass.autofill.AutofillHelper
import com.kunzisoft.keepass.model.RegisterInfo import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo import com.kunzisoft.keepass.model.SearchInfo
import java.io.Serializable import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.utils.getEnumExtra
import com.kunzisoft.keepass.utils.putEnumExtra
object EntrySelectionHelper { object EntrySelectionHelper {
@@ -82,17 +84,17 @@ object EntrySelectionHelper {
} }
fun retrieveSearchInfoFromIntent(intent: Intent): SearchInfo? { fun retrieveSearchInfoFromIntent(intent: Intent): SearchInfo? {
return intent.getParcelableExtra(KEY_SEARCH_INFO) return intent.getParcelableExtraCompat(KEY_SEARCH_INFO)
} }
fun addRegisterInfoInIntent(intent: Intent, registerInfo: RegisterInfo?) { private fun addRegisterInfoInIntent(intent: Intent, registerInfo: RegisterInfo?) {
registerInfo?.let { registerInfo?.let {
intent.putExtra(KEY_REGISTER_INFO, it) intent.putExtra(KEY_REGISTER_INFO, it)
} }
} }
fun retrieveRegisterInfoFromIntent(intent: Intent): RegisterInfo? { fun retrieveRegisterInfoFromIntent(intent: Intent): RegisterInfo? {
return intent.getParcelableExtra(KEY_REGISTER_INFO) return intent.getParcelableExtraCompat(KEY_REGISTER_INFO)
} }
fun removeInfoFromIntent(intent: Intent) { fun removeInfoFromIntent(intent: Intent) {
@@ -101,7 +103,7 @@ object EntrySelectionHelper {
} }
fun addSpecialModeInIntent(intent: Intent, specialMode: SpecialMode) { fun addSpecialModeInIntent(intent: Intent, specialMode: SpecialMode) {
intent.putExtra(KEY_SPECIAL_MODE, specialMode as Serializable) intent.putEnumExtra(KEY_SPECIAL_MODE, specialMode)
} }
fun retrieveSpecialModeFromIntent(intent: Intent): SpecialMode { fun retrieveSpecialModeFromIntent(intent: Intent): SpecialMode {
@@ -109,12 +111,11 @@ object EntrySelectionHelper {
if (AutofillHelper.retrieveAutofillComponent(intent) != null) if (AutofillHelper.retrieveAutofillComponent(intent) != null)
return SpecialMode.SELECTION return SpecialMode.SELECTION
} }
return intent.getSerializableExtra(KEY_SPECIAL_MODE) as SpecialMode? return intent.getEnumExtra<SpecialMode>(KEY_SPECIAL_MODE) ?: SpecialMode.DEFAULT
?: SpecialMode.DEFAULT
} }
fun addTypeModeInIntent(intent: Intent, typeMode: TypeMode) { private fun addTypeModeInIntent(intent: Intent, typeMode: TypeMode) {
intent.putExtra(KEY_TYPE_MODE, typeMode as Serializable) intent.putEnumExtra(KEY_TYPE_MODE, typeMode)
} }
fun retrieveTypeModeFromIntent(intent: Intent): TypeMode { fun retrieveTypeModeFromIntent(intent: Intent): TypeMode {
@@ -122,7 +123,7 @@ object EntrySelectionHelper {
if (AutofillHelper.retrieveAutofillComponent(intent) != null) if (AutofillHelper.retrieveAutofillComponent(intent) != null)
return TypeMode.AUTOFILL return TypeMode.AUTOFILL
} }
return intent.getSerializableExtra(KEY_TYPE_MODE) as TypeMode? ?: TypeMode.DEFAULT return intent.getEnumExtra<TypeMode>(KEY_TYPE_MODE) ?: TypeMode.DEFAULT
} }
fun removeModesFromIntent(intent: Intent) { fun removeModesFromIntent(intent: Intent) {
@@ -175,7 +176,7 @@ object EntrySelectionHelper {
} }
} }
if (!autofillComponentInit) { if (!autofillComponentInit) {
if (intent.getSerializableExtra(KEY_SPECIAL_MODE) != null) { if (intent.getEnumExtra<SpecialMode>(KEY_SPECIAL_MODE) != null) {
when (retrieveTypeModeFromIntent(intent)) { when (retrieveTypeModeFromIntent(intent)) {
TypeMode.DEFAULT -> { TypeMode.DEFAULT -> {
removeModesFromIntent(intent) removeModesFromIntent(intent)

View File

@@ -20,24 +20,29 @@
package com.kunzisoft.keepass.activities.helpers package com.kunzisoft.keepass.activities.helpers
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity.RESULT_OK import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import androidx.annotation.RequiresApi import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.kunzisoft.keepass.activities.dialogs.FileManagerDialogFragment import com.kunzisoft.keepass.activities.dialogs.FileManagerDialogFragment
import com.kunzisoft.keepass.utils.UriUtil import com.kunzisoft.keepass.utils.UriUtil.takeUriPermission
class ExternalFileHelper { class ExternalFileHelper {
private var activity: FragmentActivity? = null private var activity: FragmentActivity? = null
private var fragment: Fragment? = null private var fragment: Fragment? = null
private var getContentResultLauncher: ActivityResultLauncher<String>? = null
private var openDocumentResultLauncher: ActivityResultLauncher<Array<String>>? = null
private var createDocumentResultLauncher: ActivityResultLauncher<String>? = null
constructor(context: FragmentActivity) { constructor(context: FragmentActivity) {
this.activity = context this.activity = context
this.fragment = null this.fragment = null
@@ -48,94 +53,79 @@ class ExternalFileHelper {
this.fragment = context this.fragment = context
} }
fun buildOpenDocument(onFileSelected: ((uri: Uri?) -> Unit)?) {
val resultCallback = ActivityResultCallback<Uri?> { result ->
activity?.contentResolver?.takeUriPermission(result)
onFileSelected?.invoke(result)
}
getContentResultLauncher = if (fragment != null) {
fragment?.registerForActivityResult(
GetContent(),
resultCallback
)
} else {
activity?.registerForActivityResult(
GetContent(),
resultCallback
)
}
openDocumentResultLauncher = if (fragment != null) {
fragment?.registerForActivityResult(
OpenDocument(),
resultCallback
)
} else {
activity?.registerForActivityResult(
OpenDocument(),
resultCallback
)
}
}
fun buildCreateDocument(typeString: String = "application/octet-stream",
onFileCreated: (fileCreated: Uri?)->Unit) {
val resultCallback = ActivityResultCallback<Uri?> { result ->
onFileCreated.invoke(result)
}
createDocumentResultLauncher = if (fragment != null) {
fragment?.registerForActivityResult(
CreateDocument(typeString),
resultCallback
)
} else {
activity?.registerForActivityResult(
CreateDocument(typeString),
resultCallback
)
}
}
fun openDocument(getContent: Boolean = false, fun openDocument(getContent: Boolean = false,
typeString: String = "*/*") { typeString: String = "*/*") {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { try {
try { if (getContent) {
if (getContent) { getContentResultLauncher?.launch(typeString)
openActivityWithActionGetContent(typeString) } else {
} else { openDocumentResultLauncher?.launch(arrayOf(typeString))
openActivityWithActionOpenDocument(typeString)
}
} catch (e: Exception) {
Log.e(TAG, "Unable to open document", e)
showFileManagerDialogFragment()
} }
} else { } catch (e: Exception) {
Log.e(TAG, "Unable to open document", e)
showFileManagerDialogFragment() showFileManagerDialogFragment()
} }
} }
@RequiresApi(Build.VERSION_CODES.KITKAT) fun createDocument(titleString: String) {
private fun openActivityWithActionOpenDocument(typeString: String) { try {
val intentOpenDocument = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { createDocumentResultLauncher?.launch(titleString)
addCategory(Intent.CATEGORY_OPENABLE) } catch (e: Exception) {
type = typeString Log.e(TAG, "Unable to create document", e)
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) showFileManagerDialogFragment()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
}
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
} }
if (fragment != null)
fragment?.startActivityForResult(intentOpenDocument, OPEN_DOC)
else
activity?.startActivityForResult(intentOpenDocument, OPEN_DOC)
}
@RequiresApi(Build.VERSION_CODES.KITKAT)
private fun openActivityWithActionGetContent(typeString: String) {
val intentGetContent = Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = typeString
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
}
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}
if (fragment != null)
fragment?.startActivityForResult(intentGetContent, GET_CONTENT)
else
activity?.startActivityForResult(intentGetContent, GET_CONTENT)
}
/**
* To use in onActivityResultCallback in Fragment or Activity
* @param onFileSelected Callback retrieve from data
* @return true if requestCode was captured, false elsewhere
*/
fun onOpenDocumentResult(requestCode: Int, resultCode: Int, data: Intent?,
onFileSelected: ((uri: Uri?) -> Unit)?): Boolean {
when (requestCode) {
FILE_BROWSE -> {
if (resultCode == RESULT_OK) {
val filename = data?.dataString
var keyUri: Uri? = null
if (filename != null) {
keyUri = UriUtil.parse(filename)
}
onFileSelected?.invoke(keyUri)
}
return true
}
GET_CONTENT, OPEN_DOC -> {
if (resultCode == RESULT_OK) {
if (data != null) {
val uri = data.data
if (uri != null) {
UriUtil.takeUriPermission(activity?.contentResolver, uri)
onFileSelected?.invoke(uri)
}
}
}
return true
}
}
return false
} }
/** /**
@@ -155,83 +145,54 @@ class ExternalFileHelper {
} }
} }
fun createDocument(titleString: String, class OpenDocument : ActivityResultContracts.OpenDocument() {
typeString: String = "application/octet-stream"): Int? { @SuppressLint("InlinedApi")
val idCode = getUnusedCreateFileRequestCode() override fun createIntent(context: Context, input: Array<String>): Intent {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { return super.createIntent(context, input).apply {
try { addCategory(Intent.CATEGORY_OPENABLE)
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
addCategory(Intent.CATEGORY_OPENABLE) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
type = typeString addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
putExtra(Intent.EXTRA_TITLE, titleString)
} }
if (fragment != null) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
fragment?.startActivityForResult(intent, idCode) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
else
activity?.startActivityForResult(intent, idCode)
return idCode
} catch (e: Exception) {
Log.e(TAG, "Unable to create document", e)
showFileManagerDialogFragment()
} }
} else {
showFileManagerDialogFragment()
} }
return null
} }
/** class GetContent : ActivityResultContracts.GetContent() {
* To use in onActivityResultCallback in Fragment or Activity @SuppressLint("InlinedApi")
* @param onFileCreated Callback retrieve from data override fun createIntent(context: Context, input: String): Intent {
* @return true if requestCode was captured, false elsewhere return super.createIntent(context, input).apply {
*/ addCategory(Intent.CATEGORY_OPENABLE)
fun onCreateDocumentResult(requestCode: Int, resultCode: Int, data: Intent?, addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
onFileCreated: (fileCreated: Uri?)->Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Retrieve the created URI from the file manager addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
if (fileRequestCodes.contains(requestCode) && resultCode == RESULT_OK) { }
onFileCreated.invoke(data?.data) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
fileRequestCodes.remove(requestCode) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}
} }
} }
class CreateDocument(typeString: String) : ActivityResultContracts.CreateDocument(typeString) {
override fun createIntent(context: Context, input: String): Intent {
return super.createIntent(context, input).apply {
addCategory(Intent.CATEGORY_OPENABLE)
}
}
}
companion object { companion object {
private const val TAG = "OpenFileHelper" private const val TAG = "OpenFileHelper"
private const val GET_CONTENT = 25745
private const val OPEN_DOC = 25845
private const val FILE_BROWSE = 25645
private var CREATE_FILE_REQUEST_CODE_DEFAULT = 3853
private var fileRequestCodes = ArrayList<Int>()
private fun getUnusedCreateFileRequestCode(): Int {
val newCreateFileRequestCode = CREATE_FILE_REQUEST_CODE_DEFAULT++
fileRequestCodes.add(newCreateFileRequestCode)
return newCreateFileRequestCode
}
@SuppressLint("InlinedApi")
fun allowCreateDocumentByStorageAccessFramework(packageManager: PackageManager,
typeString: String = "application/octet-stream"): Boolean {
return when {
// To check if a custom file manager can manage the ACTION_CREATE_DOCUMENT
Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT -> {
packageManager.queryIntentActivities(Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = typeString
}, PackageManager.MATCH_DEFAULT_ONLY).isNotEmpty()
}
else -> true
}
}
} }
} }
fun View.setOpenDocumentClickListener(externalFileHelper: ExternalFileHelper?) { fun View.setOpenDocumentClickListener(externalFileHelper: ExternalFileHelper?) {
externalFileHelper?.let { fileHelper -> externalFileHelper?.let { fileHelper ->
setOnClickListener { setOnClickListener {
fileHelper.openDocument() fileHelper.openDocument(false)
} }
setOnLongClickListener { setOnLongClickListener {
fileHelper.openDocument(true) fileHelper.openDocument(true)

View File

@@ -4,23 +4,24 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.activity.viewModels import androidx.activity.viewModels
import com.kunzisoft.keepass.activities.stylish.StylishActivity import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.action.DatabaseTaskProvider import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.DatabaseTaskProvider
import com.kunzisoft.keepass.model.MainCredential import com.kunzisoft.keepass.model.CipherEncryptDatabase
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.getBinaryDir
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval { abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
protected val mDatabaseViewModel: DatabaseViewModel by viewModels() protected val mDatabaseViewModel: DatabaseViewModel by viewModels()
protected var mDatabaseTaskProvider: DatabaseTaskProvider? = null protected var mDatabaseTaskProvider: DatabaseTaskProvider? = null
protected var mDatabase: Database? = null protected var mDatabase: ContextualDatabase? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
mDatabaseTaskProvider = DatabaseTaskProvider(this) mDatabaseTaskProvider = DatabaseTaskProvider(this, showDatabaseDialog())
mDatabaseTaskProvider?.onDatabaseRetrieved = { database -> mDatabaseTaskProvider?.onDatabaseRetrieved = { database ->
val databaseWasReloaded = database?.wasReloaded == true val databaseWasReloaded = database?.wasReloaded == true
@@ -36,14 +37,25 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
} }
} }
override fun onDatabaseRetrieved(database: Database?) { protected open fun showDatabaseDialog(): Boolean {
return true
}
override fun onDestroy() {
mDatabaseTaskProvider?.destroy()
mDatabaseTaskProvider = null
mDatabase = null
super.onDestroy()
}
override fun onDatabaseRetrieved(database: ContextualDatabase?) {
mDatabase = database mDatabase = database
mDatabaseViewModel.defineDatabase(database) mDatabaseViewModel.defineDatabase(database)
// optional method implementation // optional method implementation
} }
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {
@@ -51,21 +63,25 @@ abstract class DatabaseActivity: StylishActivity(), DatabaseRetrieval {
// optional method implementation // optional method implementation
} }
fun createDatabase(databaseUri: Uri, fun createDatabase(
mainCredential: MainCredential) { databaseUri: Uri,
mainCredential: MainCredential
) {
mDatabaseTaskProvider?.startDatabaseCreate(databaseUri, mainCredential) mDatabaseTaskProvider?.startDatabaseCreate(databaseUri, mainCredential)
} }
fun loadDatabase(databaseUri: Uri, fun loadDatabase(
mainCredential: MainCredential, databaseUri: Uri,
readOnly: Boolean, mainCredential: MainCredential,
cipherEntity: CipherDatabaseEntity?, readOnly: Boolean,
fixDuplicateUuid: Boolean) { cipherEncryptDatabase: CipherEncryptDatabase?,
mDatabaseTaskProvider?.startDatabaseLoad(databaseUri, mainCredential, readOnly, cipherEntity, fixDuplicateUuid) fixDuplicateUuid: Boolean
) {
mDatabaseTaskProvider?.startDatabaseLoad(databaseUri, mainCredential, readOnly, cipherEncryptDatabase, fixDuplicateUuid)
} }
protected fun closeDatabase() { protected fun closeDatabase() {
mDatabase?.clearAndClose(this) mDatabase?.clearAndClose(this.getBinaryDir())
} }
override fun onResume() { override fun onResume() {

View File

@@ -24,24 +24,25 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.DeleteNodesDialogFragment import com.kunzisoft.keepass.activities.dialogs.DeleteNodesDialogFragment
import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment import com.kunzisoft.keepass.activities.dialogs.PasswordEncodingDialogFragment
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.MainCredential
import com.kunzisoft.keepass.database.element.Entry import com.kunzisoft.keepass.database.element.Entry
import com.kunzisoft.keepass.database.element.Group import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.element.node.Node import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.model.GroupInfo import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.model.MainCredential
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService import com.kunzisoft.keepass.services.DatabaseTaskNotificationService
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
@@ -62,10 +63,9 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
private var mExitLock: Boolean = false private var mExitLock: Boolean = false
protected var mDatabaseReadOnly: Boolean = true protected var mDatabaseReadOnly: Boolean = true
protected var mMergeDataAllowed: Boolean = false
private var mAutoSaveEnable: Boolean = true private var mAutoSaveEnable: Boolean = true
protected var mIconDrawableFactory: IconDrawableFactory? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -87,8 +87,14 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabaseTaskProvider?.startDatabaseSave(save) mDatabaseTaskProvider?.startDatabaseSave(save)
} }
mDatabaseViewModel.mergeDatabase.observe(this) { save ->
mDatabaseTaskProvider?.startDatabaseMerge(save)
}
mDatabaseViewModel.reloadDatabase.observe(this) { fixDuplicateUuid -> mDatabaseViewModel.reloadDatabase.observe(this) { fixDuplicateUuid ->
mDatabaseTaskProvider?.startDatabaseReload(fixDuplicateUuid) mDatabaseTaskProvider?.askToStartDatabaseReload(mDatabase?.dataModifiedSinceLastLoading != false) {
mDatabaseTaskProvider?.startDatabaseReload(fixDuplicateUuid)
}
} }
mDatabaseViewModel.saveName.observe(this) { mDatabaseViewModel.saveName.observe(this) {
@@ -100,7 +106,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
} }
mDatabaseViewModel.saveDefaultUsername.observe(this) { mDatabaseViewModel.saveDefaultUsername.observe(this) {
mDatabaseTaskProvider?.startDatabaseSaveName(it.oldValue, it.newValue, it.save) mDatabaseTaskProvider?.startDatabaseSaveDefaultUsername(it.oldValue, it.newValue, it.save)
} }
mDatabaseViewModel.saveColor.observe(this) { mDatabaseViewModel.saveColor.observe(this) {
@@ -158,7 +164,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
return true return true
} }
override fun onDatabaseRetrieved(database: Database?) { override fun onDatabaseRetrieved(database: ContextualDatabase?) {
super.onDatabaseRetrieved(database) super.onDatabaseRetrieved(database)
// End activity if database not loaded // End activity if database not loaded
@@ -180,8 +186,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
closeDatabase(database) closeDatabase(database)
if (LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK == null) if (LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK == null)
LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK = LOCKING_ACTIVITY_UI_VISIBLE LOCKING_ACTIVITY_UI_VISIBLE_DURING_LOCK = LOCKING_ACTIVITY_UI_VISIBLE
// Add onActivityForResult response mExitLock = true
setResult(RESULT_EXIT_LOCK)
closeOptionsMenu() closeOptionsMenu()
finish() finish()
} }
@@ -198,25 +203,38 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
} }
mDatabaseReadOnly = database.isReadOnly mDatabaseReadOnly = database.isReadOnly
mIconDrawableFactory = database.iconDrawableFactory mMergeDataAllowed = database.isMergeDataAllowed()
checkRegister() checkRegister()
} }
} }
override fun finish() {
// To fix weird crash
try {
super.finish()
} catch (e: Exception) {
Log.e(TAG, "Unable to finish the activity", e)
}
}
abstract fun viewToInvalidateTimeout(): View? abstract fun viewToInvalidateTimeout(): View?
override fun onDatabaseActionFinished( override fun onDatabaseActionFinished(
database: Database, database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result result: ActionRunnable.Result
) { ) {
super.onDatabaseActionFinished(database, actionTask, result) super.onDatabaseActionFinished(database, actionTask, result)
when (actionTask) { when (actionTask) {
DatabaseTaskNotificationService.ACTION_DATABASE_MERGE_TASK,
DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> { DatabaseTaskNotificationService.ACTION_DATABASE_RELOAD_TASK -> {
// Reload the current activity // Reload the current activity
if (result.isSuccess) { if (result.isSuccess) {
reloadActivity() reloadActivity()
if (actionTask == DatabaseTaskNotificationService.ACTION_DATABASE_MERGE_TASK) {
Toast.makeText(this, R.string.merge_success, Toast.LENGTH_LONG).show()
}
} else { } else {
this.showActionErrorIfNeeded(result) this.showActionErrorIfNeeded(result)
finish() finish()
@@ -225,15 +243,19 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
} }
} }
override fun onPasswordEncodingValidateListener(databaseUri: Uri?, override fun onPasswordEncodingValidateListener(
mainCredential: MainCredential) { databaseUri: Uri?,
mainCredential: MainCredential
) {
assignDatabasePassword(databaseUri, mainCredential) assignDatabasePassword(databaseUri, mainCredential)
} }
private fun assignDatabasePassword(databaseUri: Uri?, private fun assignDatabasePassword(
mainCredential: MainCredential) { databaseUri: Uri?,
mainCredential: MainCredential
) {
if (databaseUri != null) { if (databaseUri != null) {
mDatabaseTaskProvider?.startDatabaseAssignPassword(databaseUri, mainCredential) mDatabaseTaskProvider?.startDatabaseAssignCredential(databaseUri, mainCredential)
} }
} }
@@ -241,7 +263,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabase?.let { database -> mDatabase?.let { database ->
database.fileUri?.let { databaseUri -> database.fileUri?.let { databaseUri ->
// Show the progress dialog now or after dialog confirmation // Show the progress dialog now or after dialog confirmation
if (database.validatePasswordEncoding(mainCredential)) { if (database.isValidCredential(mainCredential.toMasterCredential(contentResolver))) {
assignDatabasePassword(databaseUri, mainCredential) assignDatabasePassword(databaseUri, mainCredential)
} else { } else {
PasswordEncodingDialogFragment.getInstance(databaseUri, mainCredential) PasswordEncodingDialogFragment.getInstance(databaseUri, mainCredential)
@@ -255,8 +277,22 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabaseTaskProvider?.startDatabaseSave(true) mDatabaseTaskProvider?.startDatabaseSave(true)
} }
fun saveDatabaseTo(uri: Uri) {
mDatabaseTaskProvider?.startDatabaseSave(true, uri)
}
fun mergeDatabase() {
mDatabaseTaskProvider?.startDatabaseMerge(mAutoSaveEnable)
}
fun mergeDatabaseFrom(uri: Uri, mainCredential: MainCredential) {
mDatabaseTaskProvider?.startDatabaseMerge(mAutoSaveEnable, uri, mainCredential)
}
fun reloadDatabase() { fun reloadDatabase() {
mDatabaseTaskProvider?.startDatabaseReload(false) mDatabaseTaskProvider?.askToStartDatabaseReload(mDatabase?.dataModifiedSinceLastLoading != false) {
mDatabaseTaskProvider?.startDatabaseReload(false)
}
} }
fun createEntry(newEntry: Entry, fun createEntry(newEntry: Entry,
@@ -279,7 +315,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabaseTaskProvider?.startDatabaseMoveNodes(nodesToMove, newParent, mAutoSaveEnable) mDatabaseTaskProvider?.startDatabaseMoveNodes(nodesToMove, newParent, mAutoSaveEnable)
} }
private fun eachNodeRecyclable(database: Database, nodes: List<Node>): Boolean { private fun eachNodeRecyclable(database: ContextualDatabase, nodes: List<Node>): Boolean {
return nodes.find { node -> return nodes.find { node ->
var cannotRecycle = true var cannotRecycle = true
if (node is Entry) { if (node is Entry) {
@@ -295,7 +331,7 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabase?.let { database -> mDatabase?.let { database ->
// If recycle bin enabled, ensure it exists // If recycle bin enabled, ensure it exists
if (database.isRecycleBinEnabled) { if (database.isRecycleBinEnabled) {
database.ensureRecycleBinExists(resources) database.ensureRecycleBinExists(resources.getString(R.string.recycle_bin))
} }
// If recycle bin enabled and not in recycle bin, move in recycle bin // If recycle bin enabled and not in recycle bin, move in recycle bin
@@ -353,14 +389,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabaseTaskProvider?.startDatabaseDeleteEntryHistory(mainEntryId, entryHistoryPosition, mAutoSaveEnable) mDatabaseTaskProvider?.startDatabaseDeleteEntryHistory(mainEntryId, entryHistoryPosition, mAutoSaveEnable)
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_EXIT_LOCK) {
mExitLock = true
lockAndExit()
}
}
private fun checkRegister() { private fun checkRegister() {
// If in ave or registration mode, don't allow read only // If in ave or registration mode, don't allow read only
if ((mSpecialMode == SpecialMode.SAVE if ((mSpecialMode == SpecialMode.SAVE
@@ -417,7 +445,17 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
} }
protected fun lockAndExit() { protected fun lockAndExit() {
sendBroadcast(Intent(LOCK_ACTION)) // Ask confirmation if modification not saved
if (mDatabase?.dataModifiedSinceLastLoading == true) {
AlertDialog.Builder(this)
.setMessage(R.string.discard_changes)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.lock) { _, _ ->
sendBroadcast(Intent(LOCK_ACTION))
}.create().show()
} else {
sendBroadcast(Intent(LOCK_ACTION))
}
} }
fun resetAppTimeout() { fun resetAppTimeout() {
@@ -425,14 +463,14 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
mDatabase?.loaded ?: false) mDatabase?.loaded ?: false)
} }
override fun onBackPressed() { override fun onDatabaseBackPressed() {
if (mTimeoutEnable) { if (mTimeoutEnable) {
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(this, TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(this,
mDatabase?.loaded == true) { mDatabase?.loaded == true) {
super.onBackPressed() super.onDatabaseBackPressed()
} }
} else { } else {
super.onBackPressed() super.onDatabaseBackPressed()
} }
} }
@@ -440,8 +478,6 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
const val TAG = "LockingActivity" const val TAG = "LockingActivity"
const val RESULT_EXIT_LOCK = 1450
const val TIMEOUT_ENABLE_KEY = "TIMEOUT_ENABLE_KEY" const val TIMEOUT_ENABLE_KEY = "TIMEOUT_ENABLE_KEY"
const val TIMEOUT_ENABLE_KEY_DEFAULT = true const val TIMEOUT_ENABLE_KEY_DEFAULT = true
@@ -455,25 +491,33 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(),
*/ */
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
fun View.resetAppTimeoutWhenViewTouchedOrFocused(context: Context, databaseLoaded: Boolean?) { fun View.resetAppTimeoutWhenViewTouchedOrFocused(context: Context, databaseLoaded: Boolean?) {
// Log.d(DatabaseLockActivity.TAG, "View prepared to reset app timeout") try {
setOnTouchListener { _, event -> // Log.d(DatabaseLockActivity.TAG, "View prepared to reset app timeout")
when (event.action) { setOnTouchListener { _, event ->
MotionEvent.ACTION_DOWN -> { when (event.action) {
// Log.d(DatabaseLockActivity.TAG, "View touched, try to reset app timeout") MotionEvent.ACTION_DOWN -> {
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(context, // Log.d(DatabaseLockActivity.TAG, "View touched, try to reset app timeout")
databaseLoaded ?: false) TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(
context,
databaseLoaded ?: false
)
}
}
false
}
setOnFocusChangeListener { _, _ ->
// Log.d(DatabaseLockActivity.TAG, "View focused, try to reset app timeout")
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(
context,
databaseLoaded ?: false
)
}
if (this is ViewGroup) {
for (i in 0..childCount) {
getChildAt(i)?.resetAppTimeoutWhenViewTouchedOrFocused(context, databaseLoaded)
} }
} }
false } catch (e: Exception) {
} Log.e("AppTimeout", "Unable to reset app timeout", e)
setOnFocusChangeListener { _, _ ->
// Log.d(DatabaseLockActivity.TAG, "View focused, try to reset app timeout")
TimeoutHelper.checkTimeAndLockIfTimeoutOrResetTimeout(context,
databaseLoaded ?: false)
}
if (this is ViewGroup) {
for (i in 0..childCount) {
getChildAt(i)?.resetAppTimeoutWhenViewTouchedOrFocused(context, databaseLoaded)
}
} }
} }

View File

@@ -3,13 +3,15 @@ package com.kunzisoft.keepass.activities.legacy
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.SpecialMode import com.kunzisoft.keepass.activities.helpers.SpecialMode
import com.kunzisoft.keepass.activities.helpers.TypeMode import com.kunzisoft.keepass.activities.helpers.TypeMode
import com.kunzisoft.keepass.model.SearchInfo import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.view.SpecialModeView import com.kunzisoft.keepass.view.ToolbarSpecial
/** /**
* Activity to manage database special mode (ie: selection mode) * Activity to manage database special mode (ie: selection mode)
@@ -19,20 +21,22 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
protected var mSpecialMode: SpecialMode = SpecialMode.DEFAULT protected var mSpecialMode: SpecialMode = SpecialMode.DEFAULT
private var mTypeMode: TypeMode = TypeMode.DEFAULT private var mTypeMode: TypeMode = TypeMode.DEFAULT
private var mSpecialModeView: SpecialModeView? = null private var mToolbarSpecial: ToolbarSpecial? = null
override fun onBackPressed() { open fun onDatabaseBackPressed() {
if (mSpecialMode != SpecialMode.DEFAULT) if (mSpecialMode != SpecialMode.DEFAULT)
onCancelSpecialMode() onCancelSpecialMode()
else else
super.onBackPressed() onRegularBackPressed()
} }
/** /**
* To call the regular onBackPressed() method in special mode * To call the regular onBackPressed() method in special mode
*/ */
protected fun onRegularBackPressed() { protected fun onRegularBackPressed() {
super.onBackPressed() // Do not call onBackPressedDispatcher.onBackPressed() to avoid loop
// Calling onBackPressed() is now deprecated, directly finish the activity
finish()
} }
/** /**
@@ -63,8 +67,7 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
EntrySelectionHelper.removeModesFromIntent(intent) EntrySelectionHelper.removeModesFromIntent(intent)
EntrySelectionHelper.removeInfoFromIntent(intent) EntrySelectionHelper.removeInfoFromIntent(intent)
if (mSpecialMode != SpecialMode.DEFAULT) { if (mSpecialMode != SpecialMode.DEFAULT) {
// To move the app in background backToTheMainAppAndFinish()
moveTaskToBack(true)
} }
} }
} }
@@ -72,13 +75,12 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
open fun onCancelSpecialMode() { open fun onCancelSpecialMode() {
if (isIntentSender()) { if (isIntentSender()) {
// To get the app caller, only for IntentSender // To get the app caller, only for IntentSender
super.onBackPressed() onRegularBackPressed()
} else { } else {
EntrySelectionHelper.removeModesFromIntent(intent) EntrySelectionHelper.removeModesFromIntent(intent)
EntrySelectionHelper.removeInfoFromIntent(intent) EntrySelectionHelper.removeInfoFromIntent(intent)
if (mSpecialMode != SpecialMode.DEFAULT) { if (mSpecialMode != SpecialMode.DEFAULT) {
// To move the app in background backToTheMainAppAndFinish()
moveTaskToBack(true)
} }
} }
} }
@@ -86,16 +88,27 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
protected fun backToTheAppCaller() { protected fun backToTheAppCaller() {
if (isIntentSender()) { if (isIntentSender()) {
// To get the app caller, only for IntentSender // To get the app caller, only for IntentSender
super.onBackPressed() onRegularBackPressed()
} else { } else {
// To move the app in background backToTheMainAppAndFinish()
moveTaskToBack(true)
} }
} }
private fun backToTheMainAppAndFinish() {
// To move the app in background and return to the main app
moveTaskToBack(true)
// Not using FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or finish() because kills the service
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
onDatabaseBackPressed()
}
})
mSpecialMode = EntrySelectionHelper.retrieveSpecialModeFromIntent(intent) mSpecialMode = EntrySelectionHelper.retrieveSpecialModeFromIntent(intent)
mTypeMode = EntrySelectionHelper.retrieveTypeModeFromIntent(intent) mTypeMode = EntrySelectionHelper.retrieveTypeModeFromIntent(intent)
} }
@@ -109,8 +122,8 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
?: EntrySelectionHelper.retrieveSearchInfoFromIntent(intent) ?: EntrySelectionHelper.retrieveSearchInfoFromIntent(intent)
// To show the selection mode // To show the selection mode
mSpecialModeView = findViewById(R.id.special_mode_view) mToolbarSpecial = findViewById(R.id.special_mode_view)
mSpecialModeView?.apply { mToolbarSpecial?.apply {
// Populate title // Populate title
val selectionModeStringId = when (mSpecialMode) { val selectionModeStringId = when (mSpecialMode) {
SpecialMode.DEFAULT, // Not important because hidden SpecialMode.DEFAULT, // Not important because hidden
@@ -160,12 +173,17 @@ abstract class DatabaseModeActivity : DatabaseActivity() {
} }
// To hide home button from the regular toolbar in special mode // To hide home button from the regular toolbar in special mode
if (mSpecialMode != SpecialMode.DEFAULT) { if (mSpecialMode != SpecialMode.DEFAULT
&& hideHomeButtonIfModeIsNotDefault()) {
supportActionBar?.setDisplayHomeAsUpEnabled(false) supportActionBar?.setDisplayHomeAsUpEnabled(false)
supportActionBar?.setDisplayShowHomeEnabled(false) supportActionBar?.setDisplayShowHomeEnabled(false)
} }
} }
open fun hideHomeButtonIfModeIsNotDefault(): Boolean {
return true
}
private fun blockAutofill(searchInfo: SearchInfo?) { private fun blockAutofill(searchInfo: SearchInfo?) {
val webDomain = searchInfo?.webDomain val webDomain = searchInfo?.webDomain
val applicationId = searchInfo?.applicationId val applicationId = searchInfo?.applicationId

View File

@@ -1,11 +1,11 @@
package com.kunzisoft.keepass.activities.legacy package com.kunzisoft.keepass.activities.legacy
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ActionRunnable
interface DatabaseRetrieval { interface DatabaseRetrieval {
fun onDatabaseRetrieved(database: Database?) fun onDatabaseRetrieved(database: ContextualDatabase?)
fun onDatabaseActionFinished(database: Database, fun onDatabaseActionFinished(database: ContextualDatabase,
actionTask: String, actionTask: String,
result: ActionRunnable.Result) result: ActionRunnable.Result)
} }

View File

@@ -23,6 +23,7 @@ import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.util.Log import android.util.Log
import androidx.annotation.StyleRes import androidx.annotation.StyleRes
import com.google.android.material.color.DynamicColors
import com.kunzisoft.keepass.R import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.settings.PreferencesUtil import com.kunzisoft.keepass.settings.PreferencesUtil
@@ -38,11 +39,15 @@ object Stylish {
* @param context Context to retrieve the theme preference * @param context Context to retrieve the theme preference
*/ */
fun load(context: Context) { fun load(context: Context) {
Log.d(Stylish::class.java.name, "Attatching to " + context.packageName) Log.d(Stylish::class.java.name, "Attaching to " + context.packageName)
themeString = PreferencesUtil.getStyle(context) try {
themeString = PreferencesUtil.getStyle(context)
} catch (e: Exception) {
Log.e("Stylish", "Unable to get preference style", e)
}
} }
fun retrieveEquivalentSystemStyle(context: Context, styleString: String): String { fun retrieveEquivalentSystemStyle(context: Context, styleString: String?): String {
val systemNightMode = when (PreferencesUtil.getStyleBrightness(context)) { val systemNightMode = when (PreferencesUtil.getStyleBrightness(context)) {
context.getString(R.string.list_style_brightness_light) -> false context.getString(R.string.list_style_brightness_light) -> false
context.getString(R.string.list_style_brightness_night) -> true context.getString(R.string.list_style_brightness_night) -> true
@@ -54,19 +59,28 @@ object Stylish {
} }
} }
return if (systemNightMode) { return if (systemNightMode) {
retrieveEquivalentNightStyle(context, styleString) retrieveEquivalentNightStyle(
context,
styleString ?: context.getString(R.string.list_style_name_night)
)
} else { } else {
retrieveEquivalentLightStyle(context, styleString) retrieveEquivalentLightStyle(
context,
styleString ?: context.getString(R.string.list_style_name_light)
)
} }
} }
fun retrieveEquivalentLightStyle(context: Context, styleString: String): String { fun retrieveEquivalentLightStyle(context: Context, styleString: String): String {
return when (styleString) { return when (styleString) {
context.getString(R.string.list_style_name_dynamic_night) -> context.getString(R.string.list_style_name_dynamic_light)
context.getString(R.string.list_style_name_night) -> context.getString(R.string.list_style_name_light) context.getString(R.string.list_style_name_night) -> context.getString(R.string.list_style_name_light)
context.getString(R.string.list_style_name_black) -> context.getString(R.string.list_style_name_white) context.getString(R.string.list_style_name_black) -> context.getString(R.string.list_style_name_white)
context.getString(R.string.list_style_name_dark) -> context.getString(R.string.list_style_name_clear) context.getString(R.string.list_style_name_dark) -> context.getString(R.string.list_style_name_clear)
context.getString(R.string.list_style_name_simple_night) -> context.getString(R.string.list_style_name_simple)
context.getString(R.string.list_style_name_blue_night) -> context.getString(R.string.list_style_name_blue) context.getString(R.string.list_style_name_blue_night) -> context.getString(R.string.list_style_name_blue)
context.getString(R.string.list_style_name_red_night) -> context.getString(R.string.list_style_name_red) context.getString(R.string.list_style_name_red_night) -> context.getString(R.string.list_style_name_red)
context.getString(R.string.list_style_name_reply_night) -> context.getString(R.string.list_style_name_reply)
context.getString(R.string.list_style_name_purple_dark) -> context.getString(R.string.list_style_name_purple) context.getString(R.string.list_style_name_purple_dark) -> context.getString(R.string.list_style_name_purple)
else -> styleString else -> styleString
} }
@@ -74,11 +88,14 @@ object Stylish {
private fun retrieveEquivalentNightStyle(context: Context, styleString: String): String { private fun retrieveEquivalentNightStyle(context: Context, styleString: String): String {
return when (styleString) { return when (styleString) {
context.getString(R.string.list_style_name_dynamic_light) -> context.getString(R.string.list_style_name_dynamic_night)
context.getString(R.string.list_style_name_light) -> context.getString(R.string.list_style_name_night) context.getString(R.string.list_style_name_light) -> context.getString(R.string.list_style_name_night)
context.getString(R.string.list_style_name_white) -> context.getString(R.string.list_style_name_black) context.getString(R.string.list_style_name_white) -> context.getString(R.string.list_style_name_black)
context.getString(R.string.list_style_name_clear) -> context.getString(R.string.list_style_name_dark) context.getString(R.string.list_style_name_clear) -> context.getString(R.string.list_style_name_dark)
context.getString(R.string.list_style_name_simple) -> context.getString(R.string.list_style_name_simple_night)
context.getString(R.string.list_style_name_blue) -> context.getString(R.string.list_style_name_blue_night) context.getString(R.string.list_style_name_blue) -> context.getString(R.string.list_style_name_blue_night)
context.getString(R.string.list_style_name_red) -> context.getString(R.string.list_style_name_red_night) context.getString(R.string.list_style_name_red) -> context.getString(R.string.list_style_name_red_night)
context.getString(R.string.list_style_name_reply) -> context.getString(R.string.list_style_name_reply_night)
context.getString(R.string.list_style_name_purple) -> context.getString(R.string.list_style_name_purple_dark) context.getString(R.string.list_style_name_purple) -> context.getString(R.string.list_style_name_purple_dark)
else -> styleString else -> styleString
} }
@@ -96,6 +113,13 @@ object Stylish {
PreferencesUtil.setStyle(context, styleString) PreferencesUtil.setStyle(context, styleString)
} }
fun isDynamic(context: Context): Boolean {
return DynamicColors.isDynamicColorAvailable() && (
themeString == context.getString(R.string.list_style_name_dynamic_night)
|| themeString == context.getString(R.string.list_style_name_dynamic_light)
)
}
/** /**
* Function that returns the current id of the style selected in the preference * Function that returns the current id of the style selected in the preference
* @param context Context to retrieve the id * @param context Context to retrieve the id
@@ -103,18 +127,24 @@ object Stylish {
*/ */
@StyleRes @StyleRes
fun getThemeId(context: Context): Int { fun getThemeId(context: Context): Int {
return when (retrieveEquivalentSystemStyle(context, themeString ?: context.getString(R.string.list_style_name_light))) { return when (retrieveEquivalentSystemStyle(context, themeString)) {
context.getString(R.string.list_style_name_night) -> R.style.KeepassDXStyle_Night context.getString(R.string.list_style_name_night) -> R.style.KeepassDXStyle_Night
context.getString(R.string.list_style_name_white) -> R.style.KeepassDXStyle_White context.getString(R.string.list_style_name_white) -> R.style.KeepassDXStyle_White
context.getString(R.string.list_style_name_black) -> R.style.KeepassDXStyle_Black context.getString(R.string.list_style_name_black) -> R.style.KeepassDXStyle_Black
context.getString(R.string.list_style_name_clear) -> R.style.KeepassDXStyle_Clear context.getString(R.string.list_style_name_clear) -> R.style.KeepassDXStyle_Clear
context.getString(R.string.list_style_name_dark) -> R.style.KeepassDXStyle_Dark context.getString(R.string.list_style_name_dark) -> R.style.KeepassDXStyle_Dark
context.getString(R.string.list_style_name_simple) -> R.style.KeepassDXStyle_Simple
context.getString(R.string.list_style_name_simple_night) -> R.style.KeepassDXStyle_Simple_Night
context.getString(R.string.list_style_name_blue) -> R.style.KeepassDXStyle_Blue context.getString(R.string.list_style_name_blue) -> R.style.KeepassDXStyle_Blue
context.getString(R.string.list_style_name_blue_night) -> R.style.KeepassDXStyle_Blue_Night context.getString(R.string.list_style_name_blue_night) -> R.style.KeepassDXStyle_Blue_Night
context.getString(R.string.list_style_name_red) -> R.style.KeepassDXStyle_Red context.getString(R.string.list_style_name_red) -> R.style.KeepassDXStyle_Red
context.getString(R.string.list_style_name_red_night) -> R.style.KeepassDXStyle_Red_Night context.getString(R.string.list_style_name_red_night) -> R.style.KeepassDXStyle_Red_Night
context.getString(R.string.list_style_name_reply) -> R.style.KeepassDXStyle_Reply
context.getString(R.string.list_style_name_reply_night) -> R.style.KeepassDXStyle_Reply_Night
context.getString(R.string.list_style_name_purple) -> R.style.KeepassDXStyle_Purple context.getString(R.string.list_style_name_purple) -> R.style.KeepassDXStyle_Purple
context.getString(R.string.list_style_name_purple_dark) -> R.style.KeepassDXStyle_Purple_Dark context.getString(R.string.list_style_name_purple_dark) -> R.style.KeepassDXStyle_Purple_Dark
context.getString(R.string.list_style_name_dynamic_light) -> R.style.KeepassDXStyle_Light_Dynamic
context.getString(R.string.list_style_name_dynamic_night) -> R.style.KeepassDXStyle_Night_Dynamic
else -> R.style.KeepassDXStyle_Light else -> R.style.KeepassDXStyle_Light
} }
} }

View File

@@ -21,14 +21,22 @@ package com.kunzisoft.keepass.activities.stylish
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.view.WindowManager import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.WindowManager.LayoutParams.FLAG_SECURE
import androidx.annotation.StyleRes import androidx.annotation.StyleRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.kunzisoft.keepass.settings.NestedAppSettingsFragment.Companion.DATABASE_APPEARANCE_PREFERENCE_CHANGED import androidx.preference.PreferenceManager
import com.google.android.material.color.DynamicColors
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.settings.NestedAppSettingsFragment.Companion.DATABASE_PREFERENCE_CHANGED
import com.kunzisoft.keepass.settings.PreferencesUtil
/** /**
* Stylish Hide Activity that apply a dynamic style and sets FLAG_SECURE to prevent screenshots / from * Stylish Hide Activity that apply a dynamic style and sets FLAG_SECURE to prevent screenshots / from
@@ -77,23 +85,45 @@ abstract class StylishActivity : AppCompatActivity() {
customStyle = applyCustomStyle() customStyle = applyCustomStyle()
if (customStyle) { if (customStyle) {
// Preconfigured themes
this.themeId = Stylish.getThemeId(this) this.themeId = Stylish.getThemeId(this)
setTheme(themeId) setTheme(themeId)
if (Stylish.isDynamic(this)) {
// Material You theme
DynamicColors.applyToActivityIfAvailable(this)
}
} }
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(onScreenshotModePrefListener)
}
private val onScreenshotModePrefListener = OnSharedPreferenceChangeListener { _, key ->
if (key != getString(R.string.enable_screenshot_mode_key)) return@OnSharedPreferenceChangeListener
setScreenshotMode(PreferencesUtil.isScreenshotModeEnabled(this))
}
private fun setScreenshotMode(isEnabled: Boolean) {
findViewById<View>(R.id.screenshot_mode_banner)?.visibility = if (isEnabled) VISIBLE else GONE
// Several gingerbread devices have problems with FLAG_SECURE // Several gingerbread devices have problems with FLAG_SECURE
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE) if (isEnabled) {
window.clearFlags(FLAG_SECURE)
} else {
window.setFlags(FLAG_SECURE, FLAG_SECURE)
}
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if ((customStyle && Stylish.getThemeId(this) != this.themeId) if ((customStyle && Stylish.getThemeId(this) != this.themeId)
|| DATABASE_APPEARANCE_PREFERENCE_CHANGED) { || DATABASE_PREFERENCE_CHANGED) {
DATABASE_APPEARANCE_PREFERENCE_CHANGED = false DATABASE_PREFERENCE_CHANGED = false
Log.d(this.javaClass.name, "Theme change detected, restarting activity") Log.d(this.javaClass.name, "Theme change detected, restarting activity")
recreateActivity() recreateActivity()
} }
setScreenshotMode(PreferencesUtil.isScreenshotModeEnabled(this))
} }
private fun recreateActivity() { private fun recreateActivity() {

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