From 252eb30b13f9635aad429d2baadd1560e158805e Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Fri, 24 Oct 2025 18:22:45 +0200 Subject: [PATCH 01/29] Translated using Weblate (Albanian) Currently translated at 92.0% (647 of 703 strings) Translation: KeePassDX/Strings Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/sq/ --- app/src/main/res/values-sq/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index f8e18ee5c..01f408af0 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -569,7 +569,7 @@ Paketë ikonash të përdorura te aplikacioni Zërat e skaduar nuk shfaqen Caktoni shërbim parazgjedhje vetëplotësimesh - Aktivizoni vetëplotësimet, për të plotësuar shpejt formularë në aplikacione të tjerë + Formësoni vetëplotësimet, për të plotësuar shpejt formularë në aplikacione të tjerë Rregullime vetëplotësimi Cakton madhësinë parazgjedhje për fjalëkalimet e prodhuar Caktoni shenja të lejuara për prodhuesin e fjalëkalimeve @@ -623,14 +623,14 @@ Ç’kopjohet te fusha, mund të ngjitet kudo.\n\nPërdorni metodën mbushje formularësh, nëse parapëlqeni. Ndihmoni të shtohet qëndrueshmëria, siguria dhe në shtimin e më tepër veçorive. Ndryshe nga shumë aplikacione administrimi fjalëkalimesh, ky është <strong>pa reklama</strong>, <strong>software i lirë në copylef</strong> dhe s’grumbullon të dhëna personale në shërbyesit e tij, pavarësisht versionit që përdorni. - Duke blerë versionin Pro, do të mund të përdorni këtë <strong>stil pamor</strong> dhe do të ndihmoni veçanërisht në <strong>realizimin e projekteve të bashkësisë.<strong> + Duke blerë versionin Pro, do të mund të përdorni këtë stil pamor dhe do të ndihmoni veçanërisht në realizimin e projekteve të bashkësisë. S’mbulohet shifër “Arcfour stream”. Një bazë të dhënash KeePass supozohet se përmban vetëm kartela të vockla mjetesh (b.f., kartela kyçesh PGP).\n\nMe këtë ngarkim baza juaj e të dhënave mund të bëhet shumë e madhe dhe të ulet funksionimi i saj. Ndryshoni mënyrë hapjeje për këtë sesion. \n \n“Mbrojtur nga shkimi” parandalon ndryshime të paqëllimta te baza e të dhënave. \n“E ndryshueshme” ju lejon të shtoni, fshini ose ndryshoni krejt elementët, sipas dëshirës. po i nxisni zhvilluesit të krijojnë <strong>veçori të reja</strong> dhe të <strong>ndreqin të meta</strong> në përputhje me sugjerimet tuaja. Nuk rekomandohet të shtohet një kartelë kyç e madhe, kjo mund të pengojë hapjen e bazës së të dhënave. Përpunojeni zërin tuaj me fusha vetjake. Pool data can be referenced between different entry fields. - Lloji OTP ekzistues s’njihet nga ky formular, vlerësimi i tij mund të mos prodhojë më saktë token-in. + Lloji OTP ekzistues s’njihet nga ky formular dhe vlerësimi i tij mund të mos prodhojë më saktë token-in. Akordo hyrje për shkrim kartelash, që të ruhen ndryshimet e bazës së të dhënave Përzieni të dhënat, mbishkruani ndryshimet që nga jashtë duke e ruajtur bazën e të dhënave, ose duke e ringarkuar me ndryshimet më të reja. Hyrja te kartela e shfuqizuar nga përgjegjësi i kartelave, mbylleni bazën e të dhënave dhe rihapeni që prej vendndodhjes së saj. From ddf890b861c7f8e7011d0e6e5b1d8128e2670be1 Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:48:21 +0200 Subject: [PATCH 02/29] Translated using Weblate (Russian) Currently translated at 66.6% (2 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/ru/ --- fastlane/metadata/android/ru-RU/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/ru-RU/title.txt b/fastlane/metadata/android/ru-RU/title.txt index bbbc16e86..c595ef20f 100644 --- a/fastlane/metadata/android/ru-RU/title.txt +++ b/fastlane/metadata/android/ru-RU/title.txt @@ -1 +1 @@ -KeePassDX - менеджер паролей/ключей +KeePassDX Pass(key/word) Vault From c462dae6f5bddb4c4c1ac592a1f0947476ecced9 Mon Sep 17 00:00:00 2001 From: solokot Date: Sat, 25 Oct 2025 09:02:06 +0200 Subject: [PATCH 03/29] Translated using Weblate (Russian) Currently translated at 66.6% (2 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/ru/ --- fastlane/metadata/android/ru-RU/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/ru-RU/title.txt b/fastlane/metadata/android/ru-RU/title.txt index c595ef20f..34e93bdc4 100644 --- a/fastlane/metadata/android/ru-RU/title.txt +++ b/fastlane/metadata/android/ru-RU/title.txt @@ -1 +1 @@ -KeePassDX Pass(key/word) Vault +KeePassDX - менеджер паролей From b63ceb37a41b4a6e7d910f38620eb82e6f0f6599 Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:48:56 +0200 Subject: [PATCH 04/29] Translated using Weblate (Turkish) Currently translated at 100.0% (3 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/tr/ --- fastlane/metadata/android/tr-TR/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/tr-TR/title.txt b/fastlane/metadata/android/tr-TR/title.txt index 179c6275d..c595ef20f 100644 --- a/fastlane/metadata/android/tr-TR/title.txt +++ b/fastlane/metadata/android/tr-TR/title.txt @@ -1 +1 @@ -KeePassDX - Parola/Anahtar Kasası +KeePassDX Pass(key/word) Vault From 0cf9253ea4fe68741c5e3987c91c90b433656378 Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:51:57 +0200 Subject: [PATCH 05/29] Translated using Weblate (Spanish) Currently translated at 33.3% (1 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/es/ --- fastlane/metadata/android/es-ES/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/es-ES/title.txt b/fastlane/metadata/android/es-ES/title.txt index b5651e34a..c595ef20f 100644 --- a/fastlane/metadata/android/es-ES/title.txt +++ b/fastlane/metadata/android/es-ES/title.txt @@ -1 +1 @@ -KeePassDX - Contraseñas FOSS +KeePassDX Pass(key/word) Vault From aebf6b21deff0ee8fe15f15fbd5701691d62286a Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:47:32 +0200 Subject: [PATCH 06/29] Translated using Weblate (Arabic) Currently translated at 66.6% (2 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/ar/ --- fastlane/metadata/android/ar/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/ar/title.txt b/fastlane/metadata/android/ar/title.txt index ee6b1afb4..b8cd79f80 100644 --- a/fastlane/metadata/android/ar/title.txt +++ b/fastlane/metadata/android/ar/title.txt @@ -1 +1 @@ -KeePassDX مدير كلمات سر مفتوح المصدر +KeePassDX From 8bee0ec2204c2f051580444041818fcbfdf41b6e Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:49:20 +0200 Subject: [PATCH 07/29] Translated using Weblate (Macedonian) Currently translated at 33.3% (1 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/mk/ --- fastlane/metadata/android/mk-MK/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/mk-MK/title.txt b/fastlane/metadata/android/mk-MK/title.txt index 54f4311f3..c595ef20f 100644 --- a/fastlane/metadata/android/mk-MK/title.txt +++ b/fastlane/metadata/android/mk-MK/title.txt @@ -1 +1 @@ -KeePassDX - Безбедносен софтвер за лозинки и е слободен софтвер +KeePassDX Pass(key/word) Vault From a1da3b4fbd69f8947553ba2f98d8c71832062ae5 Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:50:04 +0200 Subject: [PATCH 08/29] Translated using Weblate (Italian) Currently translated at 100.0% (3 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/it/ --- fastlane/metadata/android/it-IT/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/it-IT/title.txt b/fastlane/metadata/android/it-IT/title.txt index 8a6cd07a4..c595ef20f 100644 --- a/fastlane/metadata/android/it-IT/title.txt +++ b/fastlane/metadata/android/it-IT/title.txt @@ -1 +1 @@ -Cassaforte di pass(key/word) KeePassDX +KeePassDX Pass(key/word) Vault From ba9e2892ef3adbded0d4b27eabd4e04012e83fe2 Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:50:27 +0200 Subject: [PATCH 09/29] Translated using Weblate (Indonesian) Currently translated at 33.3% (1 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/id/ --- fastlane/metadata/android/id/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/id/title.txt b/fastlane/metadata/android/id/title.txt index 00694681a..c595ef20f 100644 --- a/fastlane/metadata/android/id/title.txt +++ b/fastlane/metadata/android/id/title.txt @@ -1 +1 @@ -KeePassDX – Pengaman Sandi FOSS +KeePassDX Pass(key/word) Vault From 46685592dfd3fc30df7d30f95a011b65f6826bf3 Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:49:38 +0200 Subject: [PATCH 10/29] Translated using Weblate (Croatian) Currently translated at 33.3% (1 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/hr/ --- fastlane/metadata/android/hr/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/hr/title.txt b/fastlane/metadata/android/hr/title.txt index 1c4f55356..c595ef20f 100644 --- a/fastlane/metadata/android/hr/title.txt +++ b/fastlane/metadata/android/hr/title.txt @@ -1 +1 @@ -KeePassDX – FOSS trezor za lozinke +KeePassDX Pass(key/word) Vault From ba58d5d47c27a11600230d2c2f98546080ba3211 Mon Sep 17 00:00:00 2001 From: Kunzisoft Date: Fri, 24 Oct 2025 17:51:40 +0200 Subject: [PATCH 11/29] Translated using Weblate (Chinese (Traditional Han script)) Currently translated at 33.3% (1 of 3 strings) Translation: KeePassDX/Metadata Translate-URL: https://hosted.weblate.org/projects/keepass-dx/metadata/zh_Hant/ --- fastlane/metadata/android/zh-TW/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/zh-TW/title.txt b/fastlane/metadata/android/zh-TW/title.txt index 844550948..c595ef20f 100644 --- a/fastlane/metadata/android/zh-TW/title.txt +++ b/fastlane/metadata/android/zh-TW/title.txt @@ -1 +1 @@ -KeePassDX - FOSS 密碼管理器 +KeePassDX Pass(key/word) Vault From a202f66d48876f4d382269641ff89e7c45898d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=EC=84=B8=ED=9B=88?= Date: Mon, 27 Oct 2025 03:54:13 +0100 Subject: [PATCH 12/29] Translated using Weblate (Korean) Currently translated at 52.6% (370 of 703 strings) Translation: KeePassDX/Strings Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ko/ --- app/src/main/res/values-ko/strings.xml | 77 +++++++++++++------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index f4bd6fa4b..efb562eea 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -19,7 +19,7 @@ --> 피드백 홈페이지 - KeePass 암호 관리자의 Android 구현본 + KeePass 암호 관리자의 Android 구현체. 확인 항목 추가 항목 수정 @@ -40,14 +40,13 @@ 클립보드를 비울 수 없음 클립보드 시간 초과 클립보드 저장이 유지될 시간 (장치가 지원한다면) - %1$s 을(를) 클립보드에 복사하려면 선택하십시오. + %1$s 을(를) 클립보드에 복사하기 데이터베이스 키를 검색하는 중… 데이터베이스 데이터베이스 컨텐츠 암호 해독 중… 기본 데이터베이스로 사용 단위 - KeePassDX © %1$d Kunzisoft는 보증이 적용되지 않습니다; 이것은 자유 소프트웨어이며, 광고가 없습니다. -\n이 것은 보증 없이 있는 그대로, GPL 버전 3하에 제공됩니다. + KeePassDX © %1$d Kunzisoft는 보증이 적용되지 않습니다; 이것은 자유 소프트웨어이며, 광고가 없습니다. \n이 것은 보증 없이 있는 그대로, GPL 버전 3 라이선스로 제공됩니다. 접근됨 취소 노트 @@ -81,22 +80,22 @@ 필드 이름 필드 값 파일을 찾을 수 없습니다. 파일 탐색기에서 열리는지 확인해 주세요. - 파일 탐색기 + 파일 관리자 비밀번호 생성 - 비밀번호 확인 - 생성된 비밀번호 + 패스워드 확인 + 생성된 패스워드 그룹 이름 키 파일 길이 - 비밀번호 + 패스워드 비밀번호 - 비밀번호나 키 파일을 읽을 수 없습니다. + 패스워드나 키 파일을 읽을 수 없습니다. 잘못된 알고리즘입니다. 데이터베이스 형식을 인식할 수 없습니다. 이 키 파일은 비어 있습니다. 길이 아이디 보이기 - 엔트리 목록에 아이디 보이기 + 항목 리스트에 사용자 이름을 표시합니다 리스트 항목 크기 요소 목록 텍스트 크기 데이터베이스 로딩 중… @@ -105,7 +104,7 @@ 기본 비밀번호를 (***) 로 가리기 정보 마스터 키 바꾸기 - %1$s 복사됨 + %1$s의 사본 설정 앱 설정 폼 채우기 @@ -129,8 +128,8 @@ 절대 하지 않음 검색 결과가 없음 이 URL을 열기 위해 웹 브라우저를 설치하십시오. - 가지고 있는 데이터베이스 열기 - 새 데이터베이스 생성 + 기존 저장소 열기 + 새 저장소 생성 새 데이터베이스 생성 중… 작업 중… 보호 @@ -138,7 +137,7 @@ KeePassDX는 데이터베이스를 수정하기 위해 쓰기 권한이 필요합니다. 삭제 루트 - 데이터베이스 암호화 알고리즘이 모든 데이터에 적용됩니다. + 데이터베이스 암호화 알고리즘이 모든 데이터에 적용됩니다 메모리 사용량 바이너리 바이트 단위의 메모리 용량이 키 파생 기능에 사용됩니다. 데이터베이스 저장 중… @@ -250,10 +249,10 @@ 그 필드 이름은 이미 존재합니다. 상속 자동입력 - 데이터베이스가 이미 열려있습니다. 새 것을 열려면 지금 것을 먼저 닫아주세요. + 데이터베이스가 이미 열려있습니다. 새 것을 열려면 지금 것을 먼저 닫아주세요 최근 데이터베이스 목록에서 파손된 링크를 감춤 - 앱 속성을 내보낼 파일을 선택 - 앱 속성을 가져왔습니다. + 가져올 앱 설정 파일 선택 + 앱 설정 가져옴 암호화 알고리즘 용 키를 생성하기 위해, 마스터키는 임의의 솔트(salt) 키 파생 함수를 사용하여 변환됩니다. 경고 이미 요청된 시도입니다. @@ -262,14 +261,14 @@ 이미 응답했습니다. 데이터 베이스 위치를 알 수 없어 데이터 베이스 액션을 수행할 수 없습니다. %1$s 를 위한 드라이버가 요구됩니다. - 데이터베이스 V1로부터 병합할 수 없습니다. + kdb 데이터베이스 파일과 병합할 수 없습니다. 하드웨어 키는 지원하지 않습니다. 키는 반드시 입력해야 합니다. 아이콘명 암호문 비밀번호에 색상 부여 타입에 따라 비밀번호 문자에 색상을 부여 - 앱 속성을 내보내기 + 앱 설정 내보내기 대문자 보안 설정 데이터 다시 읽기 @@ -280,7 +279,7 @@ 저장 모드 선택 모드 하드웨어 키를 기억 - 앱 속성을 내보낼 파일을 생성 + 앱 설정을 내보내기 위해 파일 생성 앱 속성을 가져오던 중 오류 발생. 데이터베이스가 중복된 UUID를 포함하고 있습니다. 데이터 베이스가 저장된 곳을 추적 @@ -311,7 +310,7 @@ 이력을 복구 보조 도메인 제한하에 웹 도메인을 검색 중복에 대해 새로운 UUID를 생성하여 문제를 해결하고 진행할까요\? - 앱 속성을 내보냈습니다. + 앱 설정 내보냄 병렬 처리 명령 실행중… 마스터 키 설정 @@ -321,14 +320,14 @@ 고급 잠금 해제 검색 모드 추가적인 암호화 차수를 설정함으로써 무차별 대입 공격(brute force attack)에 대한 방어를 강화할 수 있습니다. 대신 읽기/저장시 느려질 수 있습니다. - 앱을 강제 종료하지 마세요. + 앱을 강제 종료하지 마세요… 휴지통을 바닥에 - 파일에 대한 접근이 파일 관리자에 의해 철회되었습니다. + 파일에 대한 접근이 파일 관리자에 의해 철회되었습니다 파손된 데이터페이스 링크를 감춤 - 앱 속성을 가져오기 + 앱 설정 가져오기 앱 속성을 내보내던 중 오류 발생. 변환 차수 - 키 파생 함수에 사용되는 병렬 처리 수준 (즉, 스레드의 갯수) + 키 파생 함수에 사용되는 병렬 처리 수준(즉, 스레드의 갯수). <strong>사용자 데이터를 받아오지 않습니다.</strong> 어떤 서버에도 연결하지 않고 로컬로만 동작하며 사용자의 사생활(프라이버시)를 최우선시합니다. 목록 재구축을 알맞게 할 수 없습니다. 업로드하려는 파일이 너무 큽니다. @@ -339,50 +338,50 @@ 항목 목록에서 OTP 토큰을 표시 UUID를 표시 항목이나 그룹에 연결된 UUID를 표시 - 데이터 베이스를 생성 + 데이터베이스 생성중… 데이터 병합 - ... 로부터 병합 - ... 에 복사본 저장 - 고급 잠금 해제 키를 삭제 + …로부터 병합 + …에 복사본 저장 + 디바이스 잠금 해제 키 삭제 접근 %1$s 와 동일한 UUID %2$s 가 이미 존재합니다. 밑줄 지원하지 않는 데이터베이스 버전입니다. - 허용 + 권한 테마 생체 인증 기기 자격 증명 키 파일 생성하기 키보드, 자동 완성, 클립보드 검색, 잠금, 기록, 속성 - 병합을 성공했습니다 + 병합이 성공적으로 완료되었습니다 버전 %1$s 암호화된 비밀번호가 저장되었습니다 정보 빌드 %1$s 생체 인식 또는 장치 자격 증명이 등록되지 않았습니다. 속성 - 테마, 색상, 속성 + 테마, 색상, 아이콘, 글꼴, 속성 자동 입력 - 비밀번호 입력 후 이 버튼을 눌러주세요 - 사용할 수 없습니다 - 기록 + 비밀번호 입력 후 이 버튼을 눌러주세요. + 사용 불가 + 이력 유형 설정 등록된 생체정보를 업데이트해 주세요. - 항목을 선택하세요 + 항목 선택… 클립보드 클립보드 알림 - 화면이 꺼지면 몇 초 후에 데이터베이스를 잠급니다. + 화면이 꺼지면 몇 초 후에 데이터베이스를 잠급니다 \'­뒤로가기\'를 눌러 잠금 이 기능을 사용할 수 없습니다. UI에 잠금버튼을 표시합니다 - 사용자가 뒤로 가기 버튼을 누르면 데이터베이스를 잠급니다 + 데이터베이스 루트 화면에 있는 경우 \'뒤로\' 버튼을 눌러 데이터베이스를 잠그십시오 잠금 버튼 표시 잠금 해제 잠금 KeePassDX로 로그인 - 생성된 비밀번호 크기 + 생성된 패스워드 길이 자동 완성 설정 기본 자동완성 서비스 설정 화면 꺼짐 시 잠금 From 79777801e88b7c23511ab3daffb1c4894bc064bb Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 27 Oct 2025 16:34:38 +0100 Subject: [PATCH 13/29] fix: merge algorithm --- .../database/merge/DatabaseKDBXMerger.kt | 82 ++++++++++++------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt b/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt index ba6c540b4..3f9ef8f07 100644 --- a/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt +++ b/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt @@ -433,6 +433,32 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { } } + /** + * Return the real parent in database from a group defined as parent + * If the parent is null, simply return the root group + * Guaranteed that a return group is linked to the database tree through its ancestors + */ + private fun getAttachedParent( + group: GroupKDBX? + ): GroupKDBX { + var realParent: GroupKDBX = database.rootGroup!! + group?.let { parent -> + val parentInDatabase = database.getGroupById(parent.nodeId) + if (parentInDatabase == null) { + realParent = GroupKDBX().apply { + updateWith(parent, updateParents = false) + } + database.addGroupTo( + realParent, + getAttachedParent(parent.parent) + ) + } else { + realParent = parentInDatabase + } + } + return realParent + } + /** * Utility method to merge a KDBX entry */ @@ -443,10 +469,7 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { databaseToMerge.getEntryById(entryId)?.let { srcEntryToMerge -> // Retrieve parent in current database - var parentEntryToMerge: GroupKDBX? = null - srcEntryToMerge.parent?.nodeId?.let { - parentEntryToMerge = database.getGroupById(it) - } + val parentEntryToMerge: GroupKDBX = getAttachedParent(srcEntryToMerge.parent) val entryToMerge = EntryKDBX().apply { updateWith(srcEntryToMerge, copyHistory = true, updateParents = false) } @@ -478,8 +501,7 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { // If it's a deleted object, but another instance was updated // If entry parent to add exists and in current database if ((deletedObject == null - || deletedObject.deletionTime.isBefore(entryToMerge.lastModificationTime)) - && parentEntryToMerge != null) { + || deletedObject.deletionTime.isBefore(entryToMerge.lastModificationTime))) { database.addEntryTo(entryToMerge, parentEntryToMerge) } } else { @@ -490,21 +512,24 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { // Update entry with databaseEntryToMerge and merge history addHistory(entry, entryToMerge) if (parentEntryToMerge == entry.parent) { + // Update the current entry to keep modification entry.updateWith(entryToMerge, copyHistory = true, updateParents = false) - } else { + // Move the current entry to the verified location database.removeEntryFrom(entry, entry.parent) - if (parentEntryToMerge != null) { - database.addEntryTo(entryToMerge, parentEntryToMerge) - } - } - } else if (entry.lastModificationTime.isAfter(entryToMerge.lastModificationTime)) { - addHistory(entryToMerge, entry) - } else if (entry.lastModificationTime.isEquals(entryToMerge.lastModificationTime)) { - // If it's the same modification time, simply move entry to the right location - parentEntryToMerge?.let { + database.addEntryTo(entry, parentEntryToMerge) + } else { + // Remove the current entry and add the entry to merge to the correct location database.removeEntryFrom(entry, entry.parent) database.addEntryTo(entryToMerge, parentEntryToMerge) } + } else if (entry.lastModificationTime.isAfter(entryToMerge.lastModificationTime)) { + // Don't touch the location but update the entry history + addHistory(entryToMerge, entry) + } else if (entry.lastModificationTime.isEquals(entryToMerge.lastModificationTime)) { + // If it's the same modification time, simply move entry to the right location, + // Current entry and entry to merge are normally the same + database.removeEntryFrom(entry, entry.parent) + database.addEntryTo(entryToMerge, parentEntryToMerge) } } } @@ -546,10 +571,7 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { databaseToMerge.getGroupById(groupId)?.let { srcGroupToMerge -> // Retrieve parent in current database - var parentGroupToMerge: GroupKDBX? = null - srcGroupToMerge.parent?.nodeId?.let { - parentGroupToMerge = database.getGroupById(it) - } + val parentGroupToMerge: GroupKDBX = getAttachedParent(srcGroupToMerge.parent) val groupToMerge = GroupKDBX().apply { updateWith(srcGroupToMerge, updateParents = false) } @@ -557,8 +579,7 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { if (group == null) { // If group parent to add exists and in current database if ((deletedObject == null - || deletedObject.deletionTime.isBefore(groupToMerge.lastModificationTime)) - && parentGroupToMerge != null) { + || deletedObject.deletionTime.isBefore(groupToMerge.lastModificationTime))) { database.addGroupTo(groupToMerge, parentGroupToMerge) } } else { @@ -567,19 +588,18 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { // Merge by modification time if (group.lastModificationTime.isBefore(groupToMerge.lastModificationTime)) { if (parentGroupToMerge == group.parent) { - group.updateWith(groupToMerge, false) - } else { + group.updateWith(groupToMerge, updateParents = false) + // Update the current group location to the verified one database.removeGroupFrom(group, group.parent) - if (parentGroupToMerge != null) { - database.addGroupTo(groupToMerge, parentGroupToMerge) - } - } - } else if (group.lastModificationTime.isEquals(groupToMerge.lastModificationTime)) { - // If it's the same modification time, simply move group to the right location - parentGroupToMerge?.let { + database.addGroupTo(group, parentGroupToMerge) + } else { database.removeGroupFrom(group, group.parent) database.addGroupTo(groupToMerge, parentGroupToMerge) } + } else if (group.lastModificationTime.isEquals(groupToMerge.lastModificationTime)) { + // If it's the same modification time, simply move group to the right location + database.removeGroupFrom(group, group.parent) + database.addGroupTo(groupToMerge, parentGroupToMerge) } } } From 3468b0f6f5abeec3efef726824b4ae6cdc297363 Mon Sep 17 00:00:00 2001 From: solokot Date: Mon, 27 Oct 2025 18:10:58 +0100 Subject: [PATCH 14/29] Translated using Weblate (Russian) Currently translated at 100.0% (703 of 703 strings) Translation: KeePassDX/Strings Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/ru/ --- app/src/main/res/values-ru/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d27829bf9..900e8a4ec 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -475,7 +475,7 @@ Запрашивать сохранение данных после завершения заполнения формы Запрос сохранения данных Закрывать базу после выбора автозаполнения - Закрыть базу + Закрывать базу Уведомление Требуется обновление биометрической системы безопасности. Удалить всё содержимое корзины безвозвратно\? @@ -585,7 +585,7 @@ Показывать токены OTP в списке записей Внешний значок Выбор записи… - Показывать функцию, позволяющую пользователю вручную выбирать запись из базы + Показывать элемент управления для ручного выбора пользователем записи из базы Ручной выбор Название значка Разрешение From d6ae17657baf21448ffdf34a0541626d832e150d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Mon, 27 Oct 2025 15:02:14 +0100 Subject: [PATCH 15/29] Translated using Weblate (Estonian) Currently translated at 100.0% (703 of 703 strings) Translation: KeePassDX/Strings Translate-URL: https://hosted.weblate.org/projects/keepass-dx/strings/et/ --- app/src/main/res/values-et/strings.xml | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index f27845fa8..092647aed 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -666,4 +666,41 @@ Sulge andmebaas Rakendust ei õnnestu tuvastada Kas soovid olemasolevad andmed üle kirjutada? + Selle toiminguga asendad kirje olemasolevad andmed, aga kui ajaloo logimine on kasutusel, siis saad vanu kirjeid ka hiljem näha. + kasutajanime/salasõna automaattäite teenus + WebAuthn pääsuvõtmed + Seadista WebAuthn pääsuvõtmed, mis võimaldavad kiiret ja turvalist salasõnadeta ligipääsu + Pääsuvõtmete seadistused + Peale pääsuvõtme valimist sulge andmebaas + Eesõigustega rakendused + Halda brausereid sinu loodud eesõigustega rakenduste loendis + HOIATUS: Eesõigustega rakendus toimib lüüsina autentimise algallikaga suhtlemisel. Turvaprobleemide vältimiseks palun taga, et kasutad õiget rakendust. + %1$s kaset pääsuvõtmega autentimiseks.\n\nKas lisame ta eesõigustega rakenduste loendisse? + Allkiri on puudu + HOAITUS: See pääsuluba on loodud teise kliendi poolt või on allkiri kustutatud. Turvaprobleemide vältimiseks palun kontrolli rakendus, milles soovi end tuvastada on sama teenuse osa ning sisuliselt õige.\n\nKui rakendus on veebibrauser, siis ära lisa allkirja kirje juurde vaid seadistustes leiduva eesõigustega rakenduste loendisse. + %1$s on antud kontekstis tundmatu ja mittetunnustatud ning ta proovib autentimist olemasoleva pääsuvõtmega. + Kas soovid lisada rakenduse allkirja pääsuvõtme kirjele? + Automaatne valik + Vali automaatselt vaid siis, kui vaid üks kirje ja andmebaas on avatud ning vaid siis, kui rakendus ühildub + Varunduse kõlblikkus + Otsusta loomise hetkel, kas avaliku võtme allikat on lubatud varundada + Varunduse olek + Anna märku, kas autentimisandmed on varundatud ja kaitstud üksiku seadme kaotsimineku puhul + Pääsuvõtmed - automaattäite teenusepakkuja + WebAuthn pääsuvõti + KeePassDX autentimisteenusepakkuja + Salvesta pääsuvõti uue kirjena + Uuenda pääsuvõtit: %1$s + Pääsuvõtit ei leidu + Vali olemasolev pääsuvõti + KeePassDX-i andmebaas + Vali lukustuse eemaldamiseks + Pääsuvõtme kasutajanimi + Pääsuvõtme privaatvõti + Pääsuvõtme autentimisühiku tunnus + Pääsuvõtme kasutaja võrgutunnus + Pääsuvõtit edastav osapool + Pääsuvõtme kõlblikkus varundamiseks + Pääsuvõtme varunduse olek + Pääsuvõtme väljastamine vastuseks ei õnnestu From d557e8b516a05b4912f2af14fba41a4558e955e2 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 27 Oct 2025 18:51:19 +0100 Subject: [PATCH 16/29] fix: merge algorithm #2223 --- CHANGELOG | 3 ++ app/build.gradle | 4 +- .../database/merge/DatabaseKDBXMerger.kt | 51 ++++++++----------- .../metadata/android/en-US/changelogs/147.txt | 1 + .../metadata/android/fr-FR/changelogs/147.txt | 1 + 5 files changed, 27 insertions(+), 33 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/147.txt create mode 100644 fastlane/metadata/android/fr-FR/changelogs/147.txt diff --git a/CHANGELOG b/CHANGELOG index ede1134b9..23c050b41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +KeePassDX(4.2.2) + * Fix database merge algorithm #2223 + KeePassDX(4.2.1) * Fix Magikeyboard autosearch #2233 * Fix database merge #2223 diff --git a/app/build.gradle b/app/build.gradle index 21fe4d380..c154fe923 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "com.kunzisoft.keepass" minSdkVersion 19 targetSdkVersion 35 - versionCode = 146 - versionName = "4.2.1" + versionCode = 147 + versionName = "4.2.2" multiDexEnabled true testApplicationId = "com.kunzisoft.keepass.tests" diff --git a/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt b/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt index 3f9ef8f07..982b9e5d0 100644 --- a/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt +++ b/database/src/main/java/com/kunzisoft/keepass/database/merge/DatabaseKDBXMerger.kt @@ -510,54 +510,46 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { // Merge by modification time if (entry.lastModificationTime.isBefore(entryToMerge.lastModificationTime)) { // Update entry with databaseEntryToMerge and merge history - addHistory(entry, entryToMerge) - if (parentEntryToMerge == entry.parent) { - // Update the current entry to keep modification - entry.updateWith(entryToMerge, copyHistory = true, updateParents = false) - // Move the current entry to the verified location - database.removeEntryFrom(entry, entry.parent) - database.addEntryTo(entry, parentEntryToMerge) - } else { - // Remove the current entry and add the entry to merge to the correct location - database.removeEntryFrom(entry, entry.parent) - database.addEntryTo(entryToMerge, parentEntryToMerge) - } + entryToMerge.addHistoryFrom(entry) + entry.updateWith(entryToMerge, copyHistory = true, updateParents = false) + // Move the current entry to the verified location + database.removeEntryFrom(entry, entry.parent) + database.addEntryTo(entry, parentEntryToMerge) } else if (entry.lastModificationTime.isAfter(entryToMerge.lastModificationTime)) { // Don't touch the location but update the entry history - addHistory(entryToMerge, entry) + entry.addHistoryFrom(entryToMerge) } else if (entry.lastModificationTime.isEquals(entryToMerge.lastModificationTime)) { // If it's the same modification time, simply move entry to the right location, // Current entry and entry to merge are normally the same database.removeEntryFrom(entry, entry.parent) - database.addEntryTo(entryToMerge, parentEntryToMerge) + database.addEntryTo(entry, parentEntryToMerge) } } } } /** - * Utility method to merge an history from an [entryA] to an [entryB], - * [entryB] is modified + * Utility method to merge an history from an [entryA] */ - private fun addHistory(entryA: EntryKDBX, entryB: EntryKDBX) { + private fun EntryKDBX.addHistoryFrom(entryA: EntryKDBX) { // Keep entry as history if already not present entryA.history.forEach { history -> // If history not present - if (!entryB.history.any { + if (!this.history.any { it.lastModificationTime == history.lastModificationTime }) { - entryB.addEntryToHistory(history) + this.addEntryToHistory(history) } } // Last entry not present - if (entryB.history.find { + if (this.history.find { it.lastModificationTime == entryA.lastModificationTime } == null) { val history = EntryKDBX().apply { updateWith(entryA, copyHistory = false, updateParents = false) parent = null } - entryB.addEntryToHistory(history) + this.addEntryToHistory(history) } } @@ -587,19 +579,16 @@ class DatabaseKDBXMerger(private var database: DatabaseKDBX) { mergeCustomData(group.customData, groupToMerge.customData) // Merge by modification time if (group.lastModificationTime.isBefore(groupToMerge.lastModificationTime)) { - if (parentGroupToMerge == group.parent) { - group.updateWith(groupToMerge, updateParents = false) - // Update the current group location to the verified one - database.removeGroupFrom(group, group.parent) - database.addGroupTo(group, parentGroupToMerge) - } else { - database.removeGroupFrom(group, group.parent) - database.addGroupTo(groupToMerge, parentGroupToMerge) - } + group.updateWith(groupToMerge, updateParents = false) + // Update the current group location to the verified one + database.removeGroupFrom(group, group.parent) + database.addGroupTo(group, parentGroupToMerge) + } else if (group.lastModificationTime.isAfter(group.lastModificationTime)) { + // Don't touch the location } else if (group.lastModificationTime.isEquals(groupToMerge.lastModificationTime)) { // If it's the same modification time, simply move group to the right location database.removeGroupFrom(group, group.parent) - database.addGroupTo(groupToMerge, parentGroupToMerge) + database.addGroupTo(group, parentGroupToMerge) } } } diff --git a/fastlane/metadata/android/en-US/changelogs/147.txt b/fastlane/metadata/android/en-US/changelogs/147.txt new file mode 100644 index 000000000..db2d01af9 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/147.txt @@ -0,0 +1 @@ + * Fix database merge algorithm #2223 \ No newline at end of file diff --git a/fastlane/metadata/android/fr-FR/changelogs/147.txt b/fastlane/metadata/android/fr-FR/changelogs/147.txt new file mode 100644 index 000000000..94fba0dd3 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/147.txt @@ -0,0 +1 @@ + * Correction de l'algorithme de fusion des bases de données #2223 \ No newline at end of file From 7db3d0502fc3dde2f90aacdf8c491153c1dc47c0 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 27 Oct 2025 19:32:00 +0100 Subject: [PATCH 17/29] fix: Save search info #2243 --- CHANGELOG | 1 + .../java/com/kunzisoft/keepass/activities/GroupActivity.kt | 6 ++++-- .../java/com/kunzisoft/keepass/model/AppOriginEntryField.kt | 2 ++ fastlane/metadata/android/en-US/changelogs/147.txt | 3 ++- fastlane/metadata/android/fr-FR/changelogs/147.txt | 3 ++- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 23c050b41..9abad5cd6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ KeePassDX(4.2.2) * Fix database merge algorithm #2223 + * Fix save search info #2243 KeePassDX(4.2.1) * Fix Magikeyboard autosearch #2233 diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt index 238c950d5..7bc23e553 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt @@ -871,8 +871,9 @@ class GroupActivity : DatabaseLockActivity(), entryVersioned, searchInfo.toRegisterInfo() ) + } else { + entrySelectedForKeyboardSelection(database, entryVersioned) } - entrySelectedForKeyboardSelection(database, entryVersioned) } TypeMode.PASSKEY -> { entrySelectedForPasskeySelection(database, entryVersioned) @@ -887,8 +888,9 @@ class GroupActivity : DatabaseLockActivity(), entryVersioned, searchInfo.toRegisterInfo() ) + } else { + entrySelectedForAutofillSelection(database, entryVersioned) } - entrySelectedForAutofillSelection(database, entryVersioned) } } loadGroup() diff --git a/database/src/main/java/com/kunzisoft/keepass/model/AppOriginEntryField.kt b/database/src/main/java/com/kunzisoft/keepass/model/AppOriginEntryField.kt index 323a15c3e..bc9580458 100644 --- a/database/src/main/java/com/kunzisoft/keepass/model/AppOriginEntryField.kt +++ b/database/src/main/java/com/kunzisoft/keepass/model/AppOriginEntryField.kt @@ -159,5 +159,7 @@ object AppOriginEntryField { */ fun Field.isWebDomain(): Boolean { return this.name.startsWith(WEB_DOMAIN_FIELD_NAME) + || this.name.contains("_$WEB_DOMAIN_FIELD_NAME") + || this.name.contains("${WEB_DOMAIN_FIELD_NAME}_") } } \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/147.txt b/fastlane/metadata/android/en-US/changelogs/147.txt index db2d01af9..7c142c059 100644 --- a/fastlane/metadata/android/en-US/changelogs/147.txt +++ b/fastlane/metadata/android/en-US/changelogs/147.txt @@ -1 +1,2 @@ - * Fix database merge algorithm #2223 \ No newline at end of file + * Fix database merge algorithm #2223 + * Fix save search info #2243 \ No newline at end of file diff --git a/fastlane/metadata/android/fr-FR/changelogs/147.txt b/fastlane/metadata/android/fr-FR/changelogs/147.txt index 94fba0dd3..38d5eb173 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/147.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/147.txt @@ -1 +1,2 @@ - * Correction de l'algorithme de fusion des bases de données #2223 \ No newline at end of file + * Correction de l'algorithme de fusion des bases de données #2223 + * Correction de la sauvegarde des infos de recherche #2243 \ No newline at end of file From c39e4ba69379388d3ee6575a68b0b9e169ba5c34 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 27 Oct 2025 20:15:02 +0100 Subject: [PATCH 18/29] fix: Play service as privileged app for Passkey Cross Device Authentication #2244 --- CHANGELOG | 1 + .../com/kunzisoft/keepass/utils/AppUtil.kt | 44 +++++++++++++------ .../metadata/android/en-US/changelogs/147.txt | 3 +- .../metadata/android/fr-FR/changelogs/147.txt | 3 +- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9abad5cd6..41a6b2bbf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ KeePassDX(4.2.2) * Fix database merge algorithm #2223 * Fix save search info #2243 + * Fix Play Service as privileged app for Passkey Cross Device Authentication #2244 KeePassDX(4.2.1) * Fix Magikeyboard autosearch #2233 diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/AppUtil.kt b/app/src/main/java/com/kunzisoft/keepass/utils/AppUtil.kt index 88e3741ef..0e7c85dd3 100644 --- a/app/src/main/java/com/kunzisoft/keepass/utils/AppUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/utils/AppUtil.kt @@ -98,25 +98,43 @@ object AppUtil { } val processedPackageNames = mutableSetOf() - for (resolveInfo in resolveInfoList) { val packageName = resolveInfo.activityInfo.packageName if (packageName != null && !processedPackageNames.contains(packageName)) { - try { - val packageInfo = packageManager.getPackageInfo( - packageName, - PackageManager.GET_SIGNING_CERTIFICATES - ) - val signatureFingerprints = packageInfo.signingInfo?.getAllFingerprints() - signatureFingerprints?.let { - browserList.add(AndroidPrivilegedApp(packageName, signatureFingerprints)) - processedPackageNames.add(packageName) - } - } catch (e: Exception) { - Log.e(AppUtil::class.simpleName, "Error processing package: $packageName", e) + buildAndroidPrivilegedApp(packageManager, packageName)?.let { privilegedApp -> + browserList.add(privilegedApp) + processedPackageNames.add(packageName) } } } + + // Add the Play Service + val gServices = "com.google.android.gms" + buildAndroidPrivilegedApp(packageManager, gServices)?.let { privilegedApp -> + browserList.add(privilegedApp) + processedPackageNames.add(gServices) + } + return browserList.distinctBy { it.packageName } // Ensure uniqueness just in case } + + @RequiresApi(Build.VERSION_CODES.P) + private fun buildAndroidPrivilegedApp( + packageManager: PackageManager, + packageName: String + ): AndroidPrivilegedApp? { + return try { + val packageInfo = packageManager.getPackageInfo( + packageName, + PackageManager.GET_SIGNING_CERTIFICATES + ) + val signatureFingerprints = packageInfo.signingInfo?.getAllFingerprints() + signatureFingerprints?.let { + AndroidPrivilegedApp(packageName, signatureFingerprints) + } + } catch (e: Exception) { + Log.e(AppUtil::class.simpleName, "Error processing package: $packageName", e) + null + } + } } \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/147.txt b/fastlane/metadata/android/en-US/changelogs/147.txt index 7c142c059..4237d6158 100644 --- a/fastlane/metadata/android/en-US/changelogs/147.txt +++ b/fastlane/metadata/android/en-US/changelogs/147.txt @@ -1,2 +1,3 @@ * Fix database merge algorithm #2223 - * Fix save search info #2243 \ No newline at end of file + * Fix save search info #2243 + * Fix Play Service as privileged app for Passkey Cross Device Authentication #2244 \ No newline at end of file diff --git a/fastlane/metadata/android/fr-FR/changelogs/147.txt b/fastlane/metadata/android/fr-FR/changelogs/147.txt index 38d5eb173..34d700275 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/147.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/147.txt @@ -1,2 +1,3 @@ * Correction de l'algorithme de fusion des bases de données #2223 - * Correction de la sauvegarde des infos de recherche #2243 \ No newline at end of file + * Correction de la sauvegarde des infos de recherche #2243 + * Correction Play Service comme appli privilégiée pour l'authentification Passkey multi-appareils #2244 \ No newline at end of file From 9a5c782d5d6ee052fd739952e0dce3c799c61027 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 27 Oct 2025 20:45:40 +0100 Subject: [PATCH 19/29] fix: Small fix, info dialog --- .../com/kunzisoft/keepass/activities/EntryActivity.kt | 2 ++ .../kunzisoft/keepass/activities/EntryEditActivity.kt | 2 ++ .../keepass/activities/FileDatabaseSelectActivity.kt | 2 ++ .../com/kunzisoft/keepass/activities/GroupActivity.kt | 2 ++ .../kunzisoft/keepass/activities/IconPickerActivity.kt | 2 ++ .../keepass/activities/ImageViewerActivity.kt | 2 ++ .../keepass/activities/KeyGeneratorActivity.kt | 2 ++ .../keepass/activities/MainCredentialActivity.kt | 2 ++ .../activity/AutofillLauncherActivity.kt | 10 ++++------ .../activity/EntrySelectionLauncherActivity.kt | 2 ++ .../keepass/settings/ExternalSettingsActivity.kt | 2 ++ 11 files changed, 24 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt index e061a27c2..dfd503f85 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt @@ -125,6 +125,8 @@ class EntryActivity : DatabaseLockActivity() { private var mBackgroundColor: Int? = null private var mForegroundColor: Int? = null + override fun manageDatabaseInfo(): Boolean = true + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt index 9ac3e99b0..c3fe06deb 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt @@ -157,6 +157,8 @@ class EntryEditActivity : DatabaseLockActivity(), } } + override fun manageDatabaseInfo(): Boolean = true + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_entry_edit) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt index 28cd408fe..28ed08fe2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt @@ -94,6 +94,8 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(), private var mExternalFileHelper: ExternalFileHelper? = null + override fun manageDatabaseInfo(): Boolean = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt index 7bc23e553..0b37f2378 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt @@ -274,6 +274,8 @@ class GroupActivity : DatabaseLockActivity(), mGroupEditViewModel.selectIcon(icon) } + override fun manageDatabaseInfo(): Boolean = true + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt index 9ff62a512..2773089d6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/IconPickerActivity.kt @@ -78,6 +78,8 @@ class IconPickerActivity : DatabaseLockActivity() { private var mExternalFileHelper: ExternalFileHelper? = null + override fun manageDatabaseInfo(): Boolean = true + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/ImageViewerActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/ImageViewerActivity.kt index af258b61d..e3c0b52d4 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/ImageViewerActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/ImageViewerActivity.kt @@ -45,6 +45,8 @@ class ImageViewerActivity : DatabaseLockActivity() { private lateinit var imageView: ImageView private lateinit var progressView: View + override fun manageDatabaseInfo(): Boolean = false + @SuppressLint("ClickableViewAccessibility") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/KeyGeneratorActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/KeyGeneratorActivity.kt index 18c29b694..4c3ac31fb 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/KeyGeneratorActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/KeyGeneratorActivity.kt @@ -28,6 +28,8 @@ class KeyGeneratorActivity : DatabaseLockActivity() { private lateinit var validationButton: View private var lockView: View? = null + override fun manageDatabaseInfo(): Boolean = true + private val keyGeneratorViewModel: KeyGeneratorViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt index 63bba08eb..f88ed643d 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/MainCredentialActivity.kt @@ -124,6 +124,8 @@ class MainCredentialActivity : DatabaseModeActivity() { private var mReadOnly: Boolean = false private var mForceReadOnly: Boolean = false + override fun manageDatabaseInfo(): Boolean = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt index 2e02fbf8f..8702a75a7 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/AutofillLauncherActivity.kt @@ -70,13 +70,11 @@ class AutofillLauncherActivity : DatabaseModeActivity() { autofillLauncherViewModel.manageRegistrationResult(it) } - override fun applyCustomStyle(): Boolean { - return false - } + override fun applyCustomStyle(): Boolean = false - override fun finishActivityIfReloadRequested(): Boolean { - return true - } + override fun finishActivityIfReloadRequested(): Boolean = true + + override fun manageDatabaseInfo(): Boolean = false override fun onCreate(savedInstanceState: Bundle?) { // To apply the bypass https://github.com/Kunzisoft/KeePassDX/issues/2238 diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/EntrySelectionLauncherActivity.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/EntrySelectionLauncherActivity.kt index 561d64184..448338dad 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/EntrySelectionLauncherActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/EntrySelectionLauncherActivity.kt @@ -56,6 +56,8 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() { override fun finishActivityIfReloadRequested() = false + override fun manageDatabaseInfo(): Boolean = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) entrySelectionViewModel.initialize() diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/ExternalSettingsActivity.kt b/app/src/main/java/com/kunzisoft/keepass/settings/ExternalSettingsActivity.kt index 68dfee71d..21daad42c 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/ExternalSettingsActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/ExternalSettingsActivity.kt @@ -13,6 +13,8 @@ abstract class ExternalSettingsActivity : DatabaseModeActivity() { private var lockView: FloatingActionButton? = null + override fun manageDatabaseInfo(): Boolean = true + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) From 7923a63d369eb30f52ee7a9572a0391096a0ad21 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 27 Oct 2025 20:53:30 +0100 Subject: [PATCH 20/29] fix: Database dialog stopped --- .../kunzisoft/keepass/activities/legacy/DatabaseActivity.kt | 2 +- .../com/kunzisoft/keepass/database/DatabaseTaskProvider.kt | 1 - .../keepass/services/DatabaseTaskNotificationService.kt | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt index 183f21ddc..b92e02ce6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt @@ -87,7 +87,7 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { showDialog(uiState.progressMessage) } is DatabaseViewModel.ActionState.OnDatabaseActionStopped -> { - // nothing here, wait for the action to finish + stopDialog() } is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> { onDatabaseActionFinished( diff --git a/app/src/main/java/com/kunzisoft/keepass/database/DatabaseTaskProvider.kt b/app/src/main/java/com/kunzisoft/keepass/database/DatabaseTaskProvider.kt index 9b1c9faa2..f4e8414ff 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/DatabaseTaskProvider.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/DatabaseTaskProvider.kt @@ -121,7 +121,6 @@ class DatabaseTaskProvider( } private fun initServiceConnection() { - actionTaskListener?.onActionStopped() if (serviceConnection == null) { serviceConnection = object : ServiceConnection { override fun onBindingDied(name: ComponentName?) { diff --git a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt index b42b07f27..f60a5b220 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt @@ -262,11 +262,12 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress ) } } else { + /* Do not stopped here, service cannot be connected mActionTaskListeners.forEach { actionTaskListener -> actionTaskListener.onActionStopped( database ) - } + }*/ } } } From 88a93829a9ead6029b9bbbc38b57ec538dc7939e Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Mon, 27 Oct 2025 21:28:29 +0100 Subject: [PATCH 21/29] fix: Lock finish --- .../kunzisoft/keepass/activities/legacy/DatabaseLockActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseLockActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseLockActivity.kt index dc0bf7f2e..c8926abb2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseLockActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseLockActivity.kt @@ -370,9 +370,11 @@ abstract class DatabaseLockActivity : DatabaseModeActivity(), .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(R.string.lock) { _, _ -> sendBroadcast(Intent(LOCK_ACTION)) + finish() }.create().show() } else { sendBroadcast(Intent(LOCK_ACTION)) + finish() } } From 26daac4637ba335f9df29decb00ce2d683c35297 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 13:28:20 +0100 Subject: [PATCH 22/29] fix: Dialog progress tasks --- .../activities/legacy/DatabaseActivity.kt | 31 +++++--- .../keepass/database/ProgressMessage.kt | 11 +-- .../DatabaseTaskNotificationService.kt | 41 +++++----- .../tasks/ProgressTaskDialogFragment.kt | 77 +++++++------------ .../keepass/tasks/ProgressTaskViewModel.kt | 33 ++++++++ 5 files changed, 104 insertions(+), 89 deletions(-) create mode 100644 app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt index b92e02ce6..ad4ce1f08 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/legacy/DatabaseActivity.kt @@ -18,11 +18,11 @@ import com.kunzisoft.keepass.activities.dialogs.DatabaseChangedDialogFragment.Co import com.kunzisoft.keepass.activities.stylish.StylishActivity import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.database.DatabaseTaskProvider.Companion.startDatabaseService -import com.kunzisoft.keepass.database.ProgressMessage import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment.Companion.PROGRESS_TASK_DIALOG_TAG +import com.kunzisoft.keepass.tasks.ProgressTaskViewModel import com.kunzisoft.keepass.viewmodels.DatabaseViewModel import kotlinx.coroutines.launch @@ -32,6 +32,7 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { protected val mDatabase: ContextualDatabase? get() = mDatabaseViewModel.database + private val progressTaskViewModel: ProgressTaskViewModel by viewModels() private var progressTaskDialogFragment: ProgressTaskDialogFragment? = null private var databaseChangedDialogFragment: DatabaseChangedDialogFragment? = null @@ -81,13 +82,13 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { ) } is DatabaseViewModel.ActionState.OnDatabaseActionStarted -> { - showDialog(uiState.progressMessage) + progressTaskViewModel.start(uiState.progressMessage) } is DatabaseViewModel.ActionState.OnDatabaseActionUpdated -> { - showDialog(uiState.progressMessage) + progressTaskViewModel.update(uiState.progressMessage) } is DatabaseViewModel.ActionState.OnDatabaseActionStopped -> { - stopDialog() + progressTaskViewModel.stop() } is DatabaseViewModel.ActionState.OnDatabaseActionFinished -> { onDatabaseActionFinished( @@ -95,12 +96,24 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { uiState.actionTask, uiState.result ) - stopDialog() + progressTaskViewModel.stop() } } } } } + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + progressTaskViewModel.progressTaskState.collect { state -> + when (state) { + ProgressTaskViewModel.ProgressTaskState.Start -> + showDialog() + ProgressTaskViewModel.ProgressTaskState.Stop -> + stopDialog() + } + } + } + } lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.RESUMED) { mDatabaseViewModel.databaseState.collect { database -> @@ -194,7 +207,7 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { } } - private fun showDialog(progressMessage: ProgressMessage) { + private fun showDialog() { lifecycleScope.launch { if (showDatabaseDialog()) { if (progressTaskDialogFragment == null) { @@ -208,12 +221,6 @@ abstract class DatabaseActivity : StylishActivity(), DatabaseRetrieval { PROGRESS_TASK_DIALOG_TAG ) } - progressTaskDialogFragment?.apply { - updateTitle(progressMessage.titleId) - updateMessage(progressMessage.messageId) - updateWarning(progressMessage.warningId) - setCancellable(progressMessage.cancelable) - } } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt b/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt index f25801ca0..557277ca6 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt @@ -1,13 +1,8 @@ package com.kunzisoft.keepass.database -import androidx.annotation.StringRes - data class ProgressMessage( - @StringRes - var titleId: Int, - @StringRes - var messageId: Int? = null, - @StringRes - var warningId: Int? = null, + var title: String, + var message: String? = null, + var warning: String? = null, var cancelable: (() -> Unit)? = null ) diff --git a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt index f60a5b220..c842644c2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt @@ -33,6 +33,7 @@ import com.kunzisoft.keepass.R import com.kunzisoft.keepass.activities.GroupActivity import com.kunzisoft.keepass.app.database.CipherDatabaseAction import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction +import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.database.MainCredential import com.kunzisoft.keepass.database.ProgressMessage @@ -61,7 +62,6 @@ 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.hardware.HardwareKey -import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity import com.kunzisoft.keepass.model.CipherEncryptDatabase import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.settings.PreferencesUtil @@ -112,7 +112,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress private var mTaskRemovedRequested = false private var mSaveState = false - private var mProgressMessage: ProgressMessage = ProgressMessage(R.string.database_opened) + private lateinit var mProgressMessage: ProgressMessage override fun retrieveChannelId(): String { return CHANNEL_DATABASE_ID @@ -305,6 +305,13 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress mResponseChallengeChannel = null } + override fun onCreate() { + super.onCreate() + mProgressMessage = ProgressMessage( + title = getString(R.string.database_opened) + ) + } + override fun onBind(intent: Intent): IBinder? { super.onBind(intent) return mActionTaskBinder @@ -391,9 +398,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress TimeoutHelper.temporarilyDisableTimeout() sendBroadcast(Intent(DATABASE_START_TASK_ACTION).apply { - putExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.titleId) - putExtra(DATABASE_TASK_MESSAGE_KEY, mProgressMessage.messageId) - putExtra(DATABASE_TASK_WARNING_KEY, mProgressMessage.warningId) + putExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.title) + putExtra(DATABASE_TASK_MESSAGE_KEY, mProgressMessage.message) + putExtra(DATABASE_TASK_WARNING_KEY, mProgressMessage.warning) }) mActionTaskListeners.forEach { actionTaskListener -> @@ -506,8 +513,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress R.drawable.notification_ic_database_action // Title depending on action - mProgressMessage.titleId = - if (intentAction == null) { + mProgressMessage.title = + getString(if (intentAction == null) { R.string.database_opened } else when (intentAction) { ACTION_DATABASE_CREATE_TASK -> R.string.creating_database @@ -522,24 +529,22 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress else R.string.command_execution } - } + }) // Updated later - mProgressMessage.messageId = null + mProgressMessage.message = null // Warning if data is saved - mProgressMessage.warningId = + mProgressMessage.warning = if (mSaveState) - R.string.do_not_kill_app + getString(R.string.do_not_kill_app) else null val notificationBuilder = buildNewNotification().apply { setSmallIcon(iconId) intent?.let { - setContentTitle(getString( - intent.getIntExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.titleId)) - ) + setContentTitle(intent.getStringExtra(DATABASE_TASK_TITLE_KEY)) } setAutoCancel(false) setContentIntent(null) @@ -661,8 +666,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress } } - private fun updateMessage(resId: Int) { - mProgressMessage.messageId = resId + private fun updateMessage(@StringRes resId: Int) { + mProgressMessage.message = getString(resId) notifyProgressMessage() } @@ -708,7 +713,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress initializeChallengeResponse() val previousMessage = mProgressMessage.copy() mProgressMessage.apply { - messageId = R.string.waiting_challenge_request + message = getString(R.string.waiting_challenge_request) cancelable = { cancelChallengeResponse(R.string.error_cancel_by_user) } @@ -723,7 +728,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress ) // Wait the response mProgressMessage.apply { - messageId = R.string.waiting_challenge_response + message = getString(R.string.waiting_challenge_response) } notifyProgressMessage() response = mResponseChallengeChannel?.receive() ?: byteArrayOf() diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt index e9240b73e..705f20faa 100644 --- a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt @@ -27,32 +27,27 @@ import android.view.View import android.widget.Button import android.widget.ProgressBar import android.widget.TextView -import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.kunzisoft.keepass.R import kotlinx.coroutines.launch open class ProgressTaskDialogFragment : DialogFragment() { - @StringRes - private var title = UNDEFINED - @StringRes - private var message = UNDEFINED - @StringRes - private var warning = UNDEFINED - private var cancellable: (() -> Unit)? = null - private var titleView: TextView? = null private var messageView: TextView? = null private var warningView: TextView? = null private var cancelButton: Button? = null private var progressView: ProgressBar? = null - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + private val progressTaskViewModel: ProgressTaskViewModel by activityViewModels() + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { try { activity?.let { val builder = AlertDialog.Builder(it) @@ -71,68 +66,48 @@ open class ProgressTaskDialogFragment : DialogFragment() { cancelButton = root.findViewById(R.id.progress_dialog_cancel) progressView = root.findViewById(R.id.progress_dialog_bar) - updateTitle(title) - updateMessage(message) - updateWarning(warning) - setCancellable(cancellable) - isCancelable = false return builder.create() } } catch (e: Exception) { - Log.e(TAG, "Unable to create progress dialog") + Log.e(TAG, "Unable to create progress dialog", e) } return super.onCreateDialog(savedInstanceState) } - fun setTitle(@StringRes titleId: Int) { - this.title = titleId + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + progressTaskViewModel.progressMessageState.collect { state -> + updateView(titleView, state.title) + updateView(messageView, state.message) + updateView(warningView, state.warning) + activity?.lifecycleScope?.launch { + cancelButton?.isVisible = state.cancelable != null + cancelButton?.setOnClickListener { + state.cancelable?.invoke() + } + } + } + } + } } - private fun updateView(textView: TextView?, @StringRes resId: Int) { + private fun updateView(textView: TextView?, value: String?) { activity?.lifecycleScope?.launch { - if (resId == UNDEFINED) { + if (value == null) { textView?.visibility = View.GONE } else { - textView?.setText(resId) + textView?.text = value textView?.visibility = View.VISIBLE } } } - private fun updateCancelable() { - activity?.lifecycleScope?.launch { - cancelButton?.isVisible = cancellable != null - cancelButton?.setOnClickListener { - cancellable?.invoke() - } - } - } - - fun updateTitle(@StringRes resId: Int?) { - this.title = resId ?: UNDEFINED - updateView(titleView, title) - } - - fun updateMessage(@StringRes resId: Int?) { - this.message = resId ?: UNDEFINED - updateView(messageView, message) - } - - fun updateWarning(@StringRes resId: Int?) { - this.warning = resId ?: UNDEFINED - updateView(warningView, warning) - } - - fun setCancellable(cancellable: (() -> Unit)?) { - this.cancellable = cancellable - updateCancelable() - } - companion object { private val TAG = ProgressTaskDialogFragment::class.java.simpleName const val PROGRESS_TASK_DIALOG_TAG = "progressDialogFragment" - const val UNDEFINED = -1 } } diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt new file mode 100644 index 000000000..63620103c --- /dev/null +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt @@ -0,0 +1,33 @@ +package com.kunzisoft.keepass.tasks + +import androidx.lifecycle.ViewModel +import com.kunzisoft.keepass.database.ProgressMessage +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +class ProgressTaskViewModel: ViewModel() { + + private val mProgressMessageState = MutableStateFlow(ProgressMessage("")) + val progressMessageState: StateFlow = mProgressMessageState + + private val mProgressTaskState = MutableStateFlow(ProgressTaskState.Stop) + val progressTaskState: StateFlow = mProgressTaskState + + fun update(value: ProgressMessage) { + mProgressMessageState.value = value + } + + fun start(value: ProgressMessage) { + mProgressTaskState.value = ProgressTaskState.Start + update(value) + } + + fun stop() { + mProgressTaskState.value = ProgressTaskState.Stop + } + + sealed class ProgressTaskState { + object Start: ProgressTaskState() + object Stop: ProgressTaskState() + } +} \ No newline at end of file From 3039efc67cc5d52aea43c227b9cd900cc575349c Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 14:07:32 +0100 Subject: [PATCH 23/29] fix: Cancelable during save --- .../DatabaseTaskNotificationService.kt | 4 +- .../tasks/ProgressTaskDialogFragment.kt | 51 ++++++++----------- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt index c842644c2..e0feac1a4 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt @@ -735,7 +735,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress // Close channels closeChallengeResponse() // Restore previous message - mProgressMessage = previousMessage + mProgressMessage = previousMessage.apply { + cancelable = null + } notifyProgressMessage() } return response diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt index 705f20faa..70a725f0f 100644 --- a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt @@ -68,6 +68,27 @@ open class ProgressTaskDialogFragment : DialogFragment() { isCancelable = false + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + progressTaskViewModel.progressMessageState.collect { state -> + titleView?.text = state.title + messageView?.text = state.message + warningView?.apply { + state.warning?.let { warning -> + text = warning + visibility = View.VISIBLE + } ?: run { + visibility = View.GONE + } + } + cancelButton?.isVisible = state.cancelable != null + cancelButton?.setOnClickListener { + state.cancelable?.invoke() + } + } + } + } + return builder.create() } } catch (e: Exception) { @@ -76,36 +97,6 @@ open class ProgressTaskDialogFragment : DialogFragment() { return super.onCreateDialog(savedInstanceState) } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.RESUMED) { - progressTaskViewModel.progressMessageState.collect { state -> - updateView(titleView, state.title) - updateView(messageView, state.message) - updateView(warningView, state.warning) - activity?.lifecycleScope?.launch { - cancelButton?.isVisible = state.cancelable != null - cancelButton?.setOnClickListener { - state.cancelable?.invoke() - } - } - } - } - } - } - - private fun updateView(textView: TextView?, value: String?) { - activity?.lifecycleScope?.launch { - if (value == null) { - textView?.visibility = View.GONE - } else { - textView?.text = value - textView?.visibility = View.VISIBLE - } - } - } - companion object { private val TAG = ProgressTaskDialogFragment::class.java.simpleName const val PROGRESS_TASK_DIALOG_TAG = "progressDialogFragment" From 987f3f90470409094208cdd76ca4b9d1a51eddfe Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 14:15:19 +0100 Subject: [PATCH 24/29] fix: Revert fragment view --- .../tasks/ProgressTaskDialogFragment.kt | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt index 70a725f0f..cd764729b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt @@ -71,16 +71,9 @@ open class ProgressTaskDialogFragment : DialogFragment() { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { progressTaskViewModel.progressMessageState.collect { state -> - titleView?.text = state.title - messageView?.text = state.message - warningView?.apply { - state.warning?.let { warning -> - text = warning - visibility = View.VISIBLE - } ?: run { - visibility = View.GONE - } - } + updateView(titleView, state.title) + updateView(messageView, state.message) + updateView(warningView, state.warning) cancelButton?.isVisible = state.cancelable != null cancelButton?.setOnClickListener { state.cancelable?.invoke() @@ -97,6 +90,15 @@ open class ProgressTaskDialogFragment : DialogFragment() { return super.onCreateDialog(savedInstanceState) } + private fun updateView(textView: TextView?, value: String?) { + if (value == null) { + textView?.visibility = View.GONE + } else { + textView?.text = value + textView?.visibility = View.VISIBLE + } + } + companion object { private val TAG = ProgressTaskDialogFragment::class.java.simpleName const val PROGRESS_TASK_DIALOG_TAG = "progressDialogFragment" From 56b7cc911886a0d0c619918329b21feb1286d6fb Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 14:49:10 +0100 Subject: [PATCH 25/29] fix: Progress message --- .../keepass/database/ProgressMessage.kt | 11 +++-- .../DatabaseTaskNotificationService.kt | 44 ++++++++----------- .../tasks/ProgressTaskDialogFragment.kt | 9 ++-- .../keepass/tasks/ProgressTaskViewModel.kt | 2 +- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt b/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt index 557277ca6..6bfe64b6c 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/ProgressMessage.kt @@ -1,8 +1,13 @@ package com.kunzisoft.keepass.database +import androidx.annotation.StringRes + data class ProgressMessage( - var title: String, - var message: String? = null, - var warning: String? = null, + @StringRes + var titleId: Int? = null, + @StringRes + var messageId: Int? = null, + @StringRes + var warningId: Int? = null, var cancelable: (() -> Unit)? = null ) diff --git a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt index e0feac1a4..ed1f2ccce 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt @@ -33,7 +33,6 @@ import com.kunzisoft.keepass.R import com.kunzisoft.keepass.activities.GroupActivity import com.kunzisoft.keepass.app.database.CipherDatabaseAction import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction -import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.database.MainCredential import com.kunzisoft.keepass.database.ProgressMessage @@ -62,6 +61,7 @@ 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.hardware.HardwareKey +import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity import com.kunzisoft.keepass.model.CipherEncryptDatabase import com.kunzisoft.keepass.model.SnapFileDatabaseInfo import com.kunzisoft.keepass.settings.PreferencesUtil @@ -112,7 +112,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress private var mTaskRemovedRequested = false private var mSaveState = false - private lateinit var mProgressMessage: ProgressMessage + private var mProgressMessage: ProgressMessage = ProgressMessage(R.string.database_opened) override fun retrieveChannelId(): String { return CHANNEL_DATABASE_ID @@ -305,13 +305,6 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress mResponseChallengeChannel = null } - override fun onCreate() { - super.onCreate() - mProgressMessage = ProgressMessage( - title = getString(R.string.database_opened) - ) - } - override fun onBind(intent: Intent): IBinder? { super.onBind(intent) return mActionTaskBinder @@ -398,9 +391,9 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress TimeoutHelper.temporarilyDisableTimeout() sendBroadcast(Intent(DATABASE_START_TASK_ACTION).apply { - putExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.title) - putExtra(DATABASE_TASK_MESSAGE_KEY, mProgressMessage.message) - putExtra(DATABASE_TASK_WARNING_KEY, mProgressMessage.warning) + putExtra(DATABASE_TASK_TITLE_KEY, mProgressMessage.titleId) + putExtra(DATABASE_TASK_MESSAGE_KEY, mProgressMessage.messageId) + putExtra(DATABASE_TASK_WARNING_KEY, mProgressMessage.warningId) }) mActionTaskListeners.forEach { actionTaskListener -> @@ -513,8 +506,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress R.drawable.notification_ic_database_action // Title depending on action - mProgressMessage.title = - getString(if (intentAction == null) { + mProgressMessage.titleId = + if (intentAction == null) { R.string.database_opened } else when (intentAction) { ACTION_DATABASE_CREATE_TASK -> R.string.creating_database @@ -529,23 +522,24 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress else R.string.command_execution } - }) + } // Updated later - mProgressMessage.message = null + mProgressMessage.messageId = null // Warning if data is saved - mProgressMessage.warning = + mProgressMessage.warningId = if (mSaveState) - getString(R.string.do_not_kill_app) + R.string.do_not_kill_app else null val notificationBuilder = buildNewNotification().apply { setSmallIcon(iconId) - intent?.let { - setContentTitle(intent.getStringExtra(DATABASE_TASK_TITLE_KEY)) - } + val titleId = mProgressMessage.titleId?.let { + intent?.getIntExtra(DATABASE_TASK_TITLE_KEY, it) + } ?: R.string.app_name + setContentTitle(getString(titleId)) setAutoCancel(false) setContentIntent(null) } @@ -666,8 +660,8 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress } } - private fun updateMessage(@StringRes resId: Int) { - mProgressMessage.message = getString(resId) + private fun updateMessage(resId: Int) { + mProgressMessage.messageId = resId notifyProgressMessage() } @@ -713,7 +707,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress initializeChallengeResponse() val previousMessage = mProgressMessage.copy() mProgressMessage.apply { - message = getString(R.string.waiting_challenge_request) + messageId = R.string.waiting_challenge_request cancelable = { cancelChallengeResponse(R.string.error_cancel_by_user) } @@ -728,7 +722,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress ) // Wait the response mProgressMessage.apply { - message = getString(R.string.waiting_challenge_response) + messageId = R.string.waiting_challenge_response } notifyProgressMessage() response = mResponseChallengeChannel?.receive() ?: byteArrayOf() diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt index cd764729b..bd342976e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskDialogFragment.kt @@ -71,9 +71,12 @@ open class ProgressTaskDialogFragment : DialogFragment() { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { progressTaskViewModel.progressMessageState.collect { state -> - updateView(titleView, state.title) - updateView(messageView, state.message) - updateView(warningView, state.warning) + updateView(titleView, + state.titleId?.let { title -> getString(title) }) + updateView(messageView, + state.messageId?.let { message -> getString(message) }) + updateView(warningView, + state.warningId?.let { warning -> getString(warning) }) cancelButton?.isVisible = state.cancelable != null cancelButton?.setOnClickListener { state.cancelable?.invoke() diff --git a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt index 63620103c..f8812f682 100644 --- a/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt +++ b/app/src/main/java/com/kunzisoft/keepass/tasks/ProgressTaskViewModel.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.StateFlow class ProgressTaskViewModel: ViewModel() { - private val mProgressMessageState = MutableStateFlow(ProgressMessage("")) + private val mProgressMessageState = MutableStateFlow(ProgressMessage()) val progressMessageState: StateFlow = mProgressMessageState private val mProgressTaskState = MutableStateFlow(ProgressTaskState.Stop) From ffaf4a761a93f05b87645430526b8ea58ceb07a1 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 15:48:07 +0100 Subject: [PATCH 26/29] fix: Service stop --- .../services/AttachmentFileNotificationService.kt | 2 +- .../services/ClipboardEntryNotificationService.kt | 2 +- .../services/DatabaseTaskNotificationService.kt | 10 +++++----- .../services/KeyboardEntryNotificationService.kt | 2 +- .../keepass/services/LockNotificationService.kt | 11 ++--------- .../kunzisoft/keepass/services/NotificationService.kt | 7 +++++++ 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt index 00fa14a9e..d9aacb1f9 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/AttachmentFileNotificationService.kt @@ -165,7 +165,7 @@ class AttachmentFileNotificationService: LockNotificationService() { } } if (attachmentNotificationList.isEmpty()) { - stopSelf() + stopService() } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/services/ClipboardEntryNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/ClipboardEntryNotificationService.kt index 98cf199c6..b1068060e 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/ClipboardEntryNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/ClipboardEntryNotificationService.kt @@ -62,7 +62,7 @@ class ClipboardEntryNotificationService : LockNotificationService() { sendBroadcast(Intent(LOCK_ACTION)) } // Stop the service - stopSelf() + stopService() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { diff --git a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt index ed1f2ccce..2bcda248b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/DatabaseTaskNotificationService.kt @@ -339,7 +339,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress val intentAction = intent?.action if (intentAction == null && !database.loaded) { - stopSelf() + stopService() } val actionRunnable: ActionRunnable? = when (intentAction) { @@ -448,10 +448,10 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress TimeoutHelper.releaseTemporarilyDisableTimeout() // Stop service after save if user remove task if (save && mTaskRemovedRequested) { - actionOnLock() + stopService() } else if (TimeoutHelper.checkTimeAndLockIfTimeout(this@DatabaseTaskNotificationService)) { if (!database.loaded) { - stopSelf() + stopService() } else { // Restart the service to open lock notification try { @@ -673,7 +673,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress updateMessage(R.string.decrypting_db) } - override fun actionOnLock() { + override fun stopService() { if (!TimeoutHelper.temporarilyDisableLock) { closeDatabase(mDatabase) // Remove the database during the lock @@ -685,7 +685,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress // Remove the lock timer (no more needed if it exists) TimeoutHelper.cancelLockTimer(this) // Service is stopped after receive the broadcast - super.actionOnLock() + super.stopService() } } diff --git a/app/src/main/java/com/kunzisoft/keepass/services/KeyboardEntryNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/KeyboardEntryNotificationService.kt index 557f00cd7..9a1c555e7 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/KeyboardEntryNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/KeyboardEntryNotificationService.kt @@ -55,7 +55,7 @@ class KeyboardEntryNotificationService : LockNotificationService() { sendBroadcast(Intent(LOCK_ACTION)) } // Stop the service - stopSelf() + stopService() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { diff --git a/app/src/main/java/com/kunzisoft/keepass/services/LockNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/LockNotificationService.kt index 5118fc203..4215f2043 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/LockNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/LockNotificationService.kt @@ -20,7 +20,6 @@ package com.kunzisoft.keepass.services import android.content.Intent -import androidx.core.app.ServiceCompat import com.kunzisoft.keepass.timeout.TimeoutHelper import com.kunzisoft.keepass.utils.LockReceiver import com.kunzisoft.keepass.utils.registerLockReceiver @@ -29,13 +28,7 @@ import com.kunzisoft.keepass.utils.unregisterLockReceiver abstract class LockNotificationService : NotificationService() { private var mLockReceiver: LockReceiver = LockReceiver { - actionOnLock() - } - - protected open fun actionOnLock() { - // Stop the service in all cases - ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE) - stopSelf() + stopService() } override fun onCreate() { @@ -46,7 +39,7 @@ abstract class LockNotificationService : NotificationService() { override fun onTaskRemoved(rootIntent: Intent?) { if (!TimeoutHelper.temporarilyDisableLock) { - actionOnLock() + stopService() } super.onTaskRemoved(rootIntent) } diff --git a/app/src/main/java/com/kunzisoft/keepass/services/NotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/services/NotificationService.kt index 4d7fae28c..ea4abcf4b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/services/NotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/services/NotificationService.kt @@ -17,6 +17,7 @@ import android.util.TypedValue import android.widget.Toast import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat +import androidx.core.app.ServiceCompat import androidx.core.content.ContextCompat import com.kunzisoft.keepass.R import com.kunzisoft.keepass.activities.stylish.Stylish @@ -114,6 +115,12 @@ abstract class NotificationService : Service() { } } + protected open fun stopService() { + // Stop the service in all cases + ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE) + stopSelf() + } + protected fun defineTimerJob(builder: NotificationCompat.Builder, type: NotificationServiceType, timeoutMilliseconds: Long, From 37ce2ab781796af3568de9628db76e41a6b478c8 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 15:59:20 +0100 Subject: [PATCH 27/29] fix: Snackbar error --- .../kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt index 28ed08fe2..ba0a57bc0 100644 --- a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt @@ -252,13 +252,13 @@ class FileDatabaseSelectActivity : DatabaseModeActivity(), database, false ) + coordinatorLayout.showActionErrorIfNeeded(result) } ACTION_DATABASE_LOAD_TASK -> { launchGroupActivityIfLoaded(database) } } } - coordinatorLayout.showActionErrorIfNeeded(result) } /** From 3f1ee6bbeaff4715f2c5dcba2c2ddf6b9939adba Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 17:14:44 +0100 Subject: [PATCH 28/29] fix: Upgrade CHANGELOG --- CHANGELOG | 1 + fastlane/metadata/android/en-US/changelogs/147.txt | 3 ++- fastlane/metadata/android/fr-FR/changelogs/147.txt | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 41a6b2bbf..b296c0875 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ KeePassDX(4.2.2) * Fix database merge algorithm #2223 * Fix save search info #2243 * Fix Play Service as privileged app for Passkey Cross Device Authentication #2244 + * Small fixes KeePassDX(4.2.1) * Fix Magikeyboard autosearch #2233 diff --git a/fastlane/metadata/android/en-US/changelogs/147.txt b/fastlane/metadata/android/en-US/changelogs/147.txt index 4237d6158..e0d5cca13 100644 --- a/fastlane/metadata/android/en-US/changelogs/147.txt +++ b/fastlane/metadata/android/en-US/changelogs/147.txt @@ -1,3 +1,4 @@ * Fix database merge algorithm #2223 * Fix save search info #2243 - * Fix Play Service as privileged app for Passkey Cross Device Authentication #2244 \ No newline at end of file + * Fix Play Service as privileged app for Passkey Cross Device Authentication #2244 + * Small fixes \ No newline at end of file diff --git a/fastlane/metadata/android/fr-FR/changelogs/147.txt b/fastlane/metadata/android/fr-FR/changelogs/147.txt index 34d700275..0b4061647 100644 --- a/fastlane/metadata/android/fr-FR/changelogs/147.txt +++ b/fastlane/metadata/android/fr-FR/changelogs/147.txt @@ -1,3 +1,4 @@ * Correction de l'algorithme de fusion des bases de données #2223 * Correction de la sauvegarde des infos de recherche #2243 - * Correction Play Service comme appli privilégiée pour l'authentification Passkey multi-appareils #2244 \ No newline at end of file + * Correction Play Service comme appli privilégiée pour l'authentification Passkey multi-appareils #2244 + * Small fixes \ No newline at end of file From ab5c859db4ff4afe178545e8b804a9f5a2560f32 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 28 Oct 2025 17:18:41 +0100 Subject: [PATCH 29/29] fix: Tags in translations --- app/src/main/res/values-ko/strings.xml | 2 +- app/src/main/res/values-sq/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index efb562eea..851b0854a 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -46,7 +46,7 @@ 데이터베이스 컨텐츠 암호 해독 중… 기본 데이터베이스로 사용 단위 - KeePassDX © %1$d Kunzisoft는 보증이 적용되지 않습니다; 이것은 자유 소프트웨어이며, 광고가 없습니다. \n이 것은 보증 없이 있는 그대로, GPL 버전 3 라이선스로 제공됩니다. + KeePassDX © %1$d Kunzisoft는 보증이 적용되지 않습니다; 이것은 <strong>자유 소프트웨어</strong>이며, <strong>광고가 없습니다</strong>. \n이 것은 보증 없이 있는 그대로, <strong>GPL 버전 3</strong> 라이선스로 제공됩니다. 접근됨 취소 노트 diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index 01f408af0..0f084f00b 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -623,7 +623,7 @@ Ç’kopjohet te fusha, mund të ngjitet kudo.\n\nPërdorni metodën mbushje formularësh, nëse parapëlqeni. Ndihmoni të shtohet qëndrueshmëria, siguria dhe në shtimin e më tepër veçorive. Ndryshe nga shumë aplikacione administrimi fjalëkalimesh, ky është <strong>pa reklama</strong>, <strong>software i lirë në copylef</strong> dhe s’grumbullon të dhëna personale në shërbyesit e tij, pavarësisht versionit që përdorni. - Duke blerë versionin Pro, do të mund të përdorni këtë stil pamor dhe do të ndihmoni veçanërisht në realizimin e projekteve të bashkësisë. + Duke blerë versionin Pro, do të mund të përdorni këtë <strong>stil pamor</strong> dhe do të ndihmoni veçanërisht në <strong>realizimin e projekteve të bashkësisë.</strong> S’mbulohet shifër “Arcfour stream”. Një bazë të dhënash KeePass supozohet se përmban vetëm kartela të vockla mjetesh (b.f., kartela kyçesh PGP).\n\nMe këtë ngarkim baza juaj e të dhënave mund të bëhet shumë e madhe dhe të ulet funksionimi i saj. Ndryshoni mënyrë hapjeje për këtë sesion. \n \n“Mbrojtur nga shkimi” parandalon ndryshime të paqëllimta te baza e të dhënave. \n“E ndryshueshme” ju lejon të shtoni, fshini ose ndryshoni krejt elementët, sipas dëshirës.