Compare commits

..

48 Commits

Author SHA1 Message Date
Philipp Crocoll
260bc8adb2 adjust layouts and colors for Edge-to-Edge with transparent status bar as is default in Android 35+ 2025-07-22 15:16:28 +02:00
Philipp Crocoll
87e979635b Merge remote-tracking branch 'origin/master' into update/target-sdk-35 2025-07-22 09:51:25 +02:00
PhilippC
0c9c163755 Merge pull request #2954 from PhilippC/ui-improvement/non-cancelable-dialogs
Make dialogs for SFTP, FTP, Mega, WebDav and Nextcloud not cancelable
2025-07-22 09:05:36 +02:00
Philipp Crocoll
74ceea562b Make dialogs for SFTP, FTP, Mega, WebDav and Nextcloud not "cancelable", i.e. they don't close when tapping outside. 2025-07-22 08:41:01 +02:00
Philipp Crocoll
c6a5362ecb update to target sdk version 35 2025-07-15 17:16:14 +02:00
Philipp Crocoll
f655a89be0 don't run the release workflow when creating a tag 2025-07-15 14:26:12 +02:00
Philipp Crocoll
0d6f837578 manifest and changelog for 1.14-pre0 2025-07-15 14:24:10 +02:00
PhilippC
8c61b028b7 Merge pull request #2789 from PhilippC/feature/82-smb-support
Samba support
2025-07-15 14:17:54 +02:00
Philipp Crocoll
a3d5273285 Merge branch 'master' into feature/82-smb-support 2025-07-15 13:45:01 +02:00
Philipp Crocoll
93cf4f790c change TargetFramework to .net9 2025-07-15 13:41:58 +02:00
PhilippC
cd323c0a22 Merge pull request #2947 from PhilippC/feature/webdav-improvements
Webdav improvements:
 * Add support for chunked uploads (enabled by default)
 * Fix determination of resource type (file vs folder)
 * add support for transactional write
2025-07-15 13:38:08 +02:00
PhilippC
99ca8bf953 Merge pull request #2829 from PhilippC/1617-use-gnu-tls-stream
Use GnuTLS stream for FTPS
2025-07-15 13:23:05 +02:00
Philipp Crocoll
d40b3dc15c fix build issue with NoNet 2025-07-15 13:16:44 +02:00
Philipp Crocoll
057a7e2f7a another nonet fix 2025-07-15 13:12:18 +02:00
PhilippC
1b73c536d5 Merge pull request #2939 from PhilippC/l10n_master3
New Crowdin updates
2025-07-15 12:32:08 +02:00
Philipp Crocoll
2593a8548f Merge branch 'master' into 1617-use-gnu-tls-stream 2025-07-15 12:25:01 +02:00
Philipp Crocoll
13306a9076 fix another build issue in NoNet 2025-07-15 12:20:25 +02:00
Philipp Crocoll
cfb5098b38 add support for transactional upload 2025-07-15 12:18:45 +02:00
Philipp Crocoll
d04d455fbd add missing changelog for 1.13 2025-07-15 12:00:05 +02:00
Philipp Crocoll
b83c4b3772 improve Samba dialog. fix NoNet build 2025-07-15 11:51:15 +02:00
Philipp Crocoll
f03c11381e Merge branch 'master' into feature/82-smb-support 2025-07-15 11:28:49 +02:00
Philipp Crocoll
8a03ddb7f3 always upload files to Github release 2025-07-15 11:08:26 +02:00
Philipp Crocoll
913222d7cb allow chunked uploads, closes https://github.com/PhilippC/keepass2android/issues/2777 2025-07-15 11:07:40 +02:00
Philipp Crocoll
3e6d86c206 correctly check if an item is a folder or file. closes https://github.com/PhilippC/keepass2android/issues/2589 2025-07-15 09:10:41 +02:00
Philipp Crocoll
d6ce2a32e9 allow manually triggering a release workflow run 2025-07-15 08:30:17 +02:00
Philipp Crocoll
21f1c8404c update workflows to not create signed apks during build but only in release. Create releases as drafts. 2025-07-15 08:14:52 +02:00
PhilippC
16ff81cf81 New translations strings.xml (Czech) 2025-07-14 10:57:07 +02:00
PhilippC
0636f687ac New translations strings.xml (Greek) 2025-07-09 13:58:02 +02:00
PhilippC
60d8900473 New translations strings.xml (Greek) 2025-07-09 11:40:00 +02:00
PhilippC
4b2d2ef768 New translations strings.xml (Portuguese, Brazilian) 2025-07-09 02:47:52 +02:00
PhilippC
48899ba9a0 New translations strings.xml (Portuguese, Brazilian) 2025-07-09 01:34:39 +02:00
Philipp Crocoll
092b8689b8 fix build-artifact paths 2025-07-08 21:35:51 +02:00
Philipp Crocoll
3d3ba45cb1 extract keystore for subsequent build step 2025-07-08 18:23:02 +02:00
Philipp Crocoll
b380100307 Manifest and changelog for v1.13 2025-07-08 17:57:52 +02:00
Philipp Crocoll
4c5ddd59d8 build signed apk on every build of master branch 2025-07-08 17:57:37 +02:00
PhilippC
5ed183f318 Merge pull request #2929 from PhilippC/l10n_master3
New Crowdin updates
2025-07-08 17:56:50 +02:00
PhilippC
9c27fd3e78 Merge pull request #2938 from PhilippC/security/audit_suggestions
Security suggestions from Audit
2025-07-08 17:52:16 +02:00
PhilippC
1d85fffb18 New translations strings.xml (Chinese Simplified) 2025-07-07 18:44:26 +02:00
PhilippC
5e2f29e737 New translations strings.xml (Chinese Simplified) 2025-07-07 17:20:28 +02:00
PhilippC
426fbc2510 New translations strings.xml (Polish) 2025-07-04 23:10:33 +02:00
PhilippC
e89a961c02 New translations strings.xml (Polish) 2025-07-04 22:15:11 +02:00
PhilippC
766c29b7a9 New translations strings.xml (Spanish) 2025-07-03 14:39:21 +02:00
PhilippC
c4206e58bf New translations strings.xml (German) 2025-06-24 15:34:08 +02:00
PhilippC
630ededf3b New translations strings.xml (German) 2025-06-24 13:51:08 +02:00
Philipp Crocoll
ba7b02cd1e remove testing credentials 2025-04-08 15:46:38 +02:00
Philipp Crocoll
aec9441de4 update FluentFTP 2025-04-08 15:26:04 +02:00
Philipp Crocoll
5edf42254d this is an experiment to use GnuTlsStream (the ftpcredentials.xml have some hardcoded credentials for a public FTP server for testing). Unfortunately, the app restarts when loading the native libraries for GnuTLS. 2025-04-01 15:10:04 +02:00
Philipp Crocoll
a51bfb102f implements Samba support to close #82 2025-03-05 08:14:02 +01:00
54 changed files with 1484 additions and 146 deletions

View File

@@ -322,18 +322,24 @@ jobs:
- name: Build keepass2android (net)
run: |
make dotnetbuild Flavor=Net
make dotnetbuild Flavor=Net
- name: Build APK (net)
if: github.ref == 'refs/heads/master'
env:
DropboxAppKey: ${{ secrets.DROPBOX_APP_KEY }}
DropboxAppSecret: ${{ secrets.DROPBOX_APP_SECRET }}
DropboxAppFolderAppKey: ${{ secrets.DROPBOX_APP_FOLDER_APP_KEY }}
DropboxAppFolderAppSecret: ${{ secrets.DROPBOX_APP_FOLDER_APP_SECRET }}
run: |
make apk Flavor=Net
make apk Configuration=Release Flavor=Net
- name: Archive production artifacts (net)
uses: actions/upload-artifact@v4
with:
name: signed APK ('net' built on ${{ github.job }})
name: archive APK ('net' built on ${{ github.job }})
path: |
src/keepass2android/bin/*/*-Signed.apk
src/keepass2android-app/bin/Release/net9.0-android/publish/*.apk
- name: Select the manifest
run: |
@@ -357,7 +363,7 @@ jobs:
- name: Archive production artifacts (nonet)
uses: actions/upload-artifact@v4
with:
name: signed APK ('nonet' built on ${{ github.job }})
name: archive APK ('nonet' built on ${{ github.job }})
path: |
src/keepass2android/bin/*/*-Signed.apk
src/keepass2android-app/bin/Release/net9.0-android/publish/*.apk

View File

@@ -3,9 +3,9 @@ env:
NAME: 'Release'
on:
push:
tags:
- "v1.*"
# the workflow is always triggered manually. This allows to test the apks
# before publishing the release and not having a broken tag in the repo if that test fails.
workflow_dispatch:
jobs:
build-release:
@@ -130,8 +130,8 @@ jobs:
name: keepass2android_${{ matrix.target }}_${{ matrix.flavor }}
# the first line is for "apk" target, the second line is for "apk_split" target
path: |
src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk
src/keepass2android-app/bin/Release/net8.0-android/*/publish/*.apk
src/keepass2android-app/bin/Release/net9.0-android/publish/*.apk
src/keepass2android-app/bin/Release/net9.0-android/*/publish/*.apk
- name: List apks
run: find . -type f -name "*.apk"
@@ -139,8 +139,8 @@ jobs:
- name: Upload APK to GitHub Release
uses: softprops/action-gh-release@v2
if: github.ref_type == 'tag'
with:
draft: true
files: |
src/keepass2android-app/bin/Release/net8.0-android/publish/*.apk
src/keepass2android-app/bin/Release/net8.0-android/*/publish/*.apk
src/keepass2android-app/bin/Release/net9.0-android/publish/*.apk
src/keepass2android-app/bin/Release/net9.0-android/*/publish/*.apk

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -140,6 +140,10 @@ namespace keepass2android
#endif
int WebDavChunkedUploadSize
{
get;
}
}
}

View File

@@ -15,7 +15,9 @@ namespace keepass2android.Io
{
get { return false; }
}
}
static public bool IsConfigured => !string.IsNullOrEmpty(AppKey) && !string.IsNullOrEmpty(AppSecret);
}
public partial class DropboxAppFolderFileStorage: JavaFileStorage
{
@@ -29,6 +31,7 @@ namespace keepass2android.Io
get { return false; }
}
static public bool IsConfigured => !string.IsNullOrEmpty(AppKey) && !string.IsNullOrEmpty(AppSecret);
}
}

View File

@@ -123,7 +123,7 @@ namespace keepass2android.Io
}
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
public virtual IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
{
return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, this);
}

View File

@@ -8,6 +8,7 @@ using Android.Content;
using Android.OS;
using FluentFTP;
using FluentFTP.Exceptions;
using FluentFTP.GnuTLS;
using KeePass.Util;
using KeePassLib;
using KeePassLib.Serialization;
@@ -140,6 +141,7 @@ namespace keepass2android.Io
var settings = ConnectionSettings.FromIoc(ioc);
FtpClient client = new FtpClient();
client.Config.CustomStream = typeof(GnuTlsStream);
client.Config.RetryAttempts = 3;
if ((settings.Username.Length > 0) || (settings.Password.Length > 0))
client.Credentials = new NetworkCredential(settings.Username, settings.Password);

View File

@@ -0,0 +1,617 @@
#if !NoNet
using System.Net;
using Android.Content;
using keepass2android;
using keepass2android.Io;
using KeePassLib.Serialization;
using SMBLibrary.Client;
using SMBLibrary;
using FileAttributes = SMBLibrary.FileAttributes;
using KeePassLib.Utility;
using Java.Nio.FileNio;
namespace Kp2aBusinessLogic.Io
{
public class SmbFileStorage : IFileStorage
{
public IEnumerable<string> SupportedProtocols
{
get { yield return "smb"; }
}
public bool UserShouldBackup
{
get { return false; }
}
public void Delete(IOConnectionInfo ioc)
{
throw new NotImplementedException();
}
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
{
return false;
}
public string GetCurrentFileVersionFast(IOConnectionInfo ioc)
{
return null;
}
public struct SmbConnectionInfo
{
public string Host;
public string Username;
public string Password;
public string? Domain;
public string? Share;
public string? LocalPath;
public static SmbConnectionInfo FromUrlAndCredentials(string url, string username, string password, string? domain)
{
string userDomain = username;
if (domain != null)
{
userDomain = domain + "\\" + username;
}
if (url.StartsWith("smb://"))
{
url = url.Substring(6);
}
if (url.StartsWith("\\\\"))
{
url = url.Substring(2);
}
url = url.Replace("\\", "/");
string fullPath = "smb://" + WebUtility.UrlEncode(userDomain) + ":" + WebUtility.UrlEncode(password) + "@" + url;
return new SmbConnectionInfo(new IOConnectionInfo() { Path = fullPath} );
}
public SmbConnectionInfo(IOConnectionInfo ioc)
{
string fullpath = ioc.Path;
if (!fullpath.StartsWith("smb://"))
{
throw new Exception("Invalid smb path!");
}
fullpath = fullpath.Substring(6);
string[] authAndPath = fullpath.Split('@');
if (authAndPath.Length != 2)
{
throw new Exception("Invalid smb path!");
}
string[] userAndPwd = authAndPath[0].Split(':');
if (userAndPwd.Length != 2)
{
throw new Exception("Invalid smb path!");
}
string[] pathParts = authAndPath[1].Split('/');
if (pathParts.Length < 1)
{
throw new Exception("Invalid smb path!");
}
Host = pathParts[0];
if (pathParts.Length > 1)
{
Share = pathParts[1];
}
LocalPath = String.Join("/", pathParts.Skip(2));
if (LocalPath.EndsWith("/"))
{
LocalPath = LocalPath.Substring(0, LocalPath.Length - 1);
}
Username = WebUtility.UrlDecode(userAndPwd[0]);
if (Username.Contains("\\"))
{
string[] domainAndUser = Username.Split('\\');
Domain = domainAndUser[0];
Username = domainAndUser[1];
}
else Domain = null;
Password = WebUtility.UrlDecode(userAndPwd[1]);
}
public string ToPath()
{
string domainUser = Username;
if (Domain != null)
{
domainUser = Domain + "\\" + Username;
}
return "smb://" + WebUtility.UrlEncode(domainUser) + ":" + WebUtility.UrlEncode(Password) + "@" + Host +
"/" + Share + "/" + LocalPath;
}
public string GetPathWithoutCredentials()
{
return "smb://" + Host + "/" + Share + "/" + LocalPath;
}
public string GetLocalSmbPath()
{
return LocalPath?.Replace("/", "\\") ?? "";
}
public SmbConnectionInfo GetParent()
{
SmbConnectionInfo parent = new SmbConnectionInfo
{
Host = Host,
Username = Username,
Password = Password,
Domain = Domain,
Share = Share
};
string[] pathParts = LocalPath?.Split('/') ?? [];
if (pathParts.Length > 0)
{
parent.LocalPath = string.Join("/", pathParts.Take(pathParts.Length - 1));
}
else
{
parent.LocalPath = "";
parent.Share = "";
}
return parent;
}
public string Stem()
{
return LocalPath?.Split('/').Last() ?? "";
}
public SmbConnectionInfo GetChild(string childName)
{
SmbConnectionInfo child = new SmbConnectionInfo();
child.Host = Host;
child.Username = Username;
child.Password = Password;
child.Domain = Domain;
if (string.IsNullOrEmpty(Share))
{
child.Share = childName;
}
else
{
child.Share = Share;
var pathPartsList = LocalPath?.Split('/').Where(p => !string.IsNullOrEmpty(p)).ToList() ?? [];
pathPartsList.Add(childName);
child.LocalPath = string.Join("/", pathPartsList);
}
return child;
}
public string ToDisplayString()
{
return "smb://" + Host + "/" + Share + "/" + LocalPath;
}
}
class SmbConnection: IDisposable
{
public SmbConnection(SmbConnectionInfo info)
{
_isLoggedIn = false;
var isConnected = Client.Connect(info.Host, SMBTransportType.DirectTCPTransport);
if (!isConnected)
{
throw new Exception($"Failed to connect to SMB server {info.Host}");
}
var status = Client.Login(info.Domain ?? string.Empty, info.Username, info.Password);
if (status != NTStatus.STATUS_SUCCESS)
{
throw new Exception($"Failed to login to SMB as {info.Username}");
}
_isLoggedIn = true;
if (!string.IsNullOrEmpty(info.Share))
{
FileStore = Client.TreeConnect(info.Share, out status);
}
}
public readonly SMB2Client Client = new SMB2Client();
public readonly ISMBFileStore? FileStore;
private readonly bool _isLoggedIn;
public void Dispose()
{
FileStore?.Disconnect();
if (_isLoggedIn)
Client.Logoff();
if (!Client.IsConnected) return;
Client.Disconnect();
}
}
public Stream OpenFileForRead(IOConnectionInfo ioc)
{
SmbConnectionInfo info = new SmbConnectionInfo(ioc);
using SmbConnection conn = new SmbConnection(info);
if (conn.FileStore == null)
{
throw new Exception($"Failed to read to {info.GetPathWithoutCredentials()}");
}
NTStatus status = conn.FileStore.CreateFile(out var fileHandle, out _, info.GetLocalSmbPath(),
AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE, FileAttributes.Normal, ShareAccess.Read,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null);
if (status != NTStatus.STATUS_SUCCESS)
{
throw new Exception($"Failed to open file {info.LocalPath}");
}
var stream = new MemoryStream();
long bytesRead = 0;
while (true)
{
status = conn.FileStore.ReadFile(out var data, fileHandle, bytesRead, (int)conn.Client.MaxReadSize);
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE)
{
throw new Exception("Failed to read from file");
}
if (status == NTStatus.STATUS_END_OF_FILE || data.Length == 0)
{
break;
}
bytesRead += data.Length;
stream.Write(data, 0, data.Length);
}
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
class SmbFileStorageWriteTransaction : IWriteTransaction
{
private bool UseFileTransaction { get; }
private readonly string _path;
private readonly string _uploadPath;
private readonly SmbFileStorage _fileStorage;
private MemoryStream? _memoryStream;
public SmbFileStorageWriteTransaction(string path, SmbFileStorage fileStorage, bool useFileTransaction)
{
UseFileTransaction = useFileTransaction;
_path = path;
if (useFileTransaction)
{
_uploadPath = _path + Guid.NewGuid().ToString().Substring(0, 8) + ".tmp";
}
else
{
_uploadPath = _path;
}
_fileStorage = fileStorage;
_memoryStream = null;
}
public void Dispose()
{
_memoryStream?.Dispose();
}
public Stream OpenFile()
{
_memoryStream = new MemoryStream();
return _memoryStream;
}
public void CommitWrite()
{
_fileStorage.UploadData(new MemoryStream(_memoryStream!.ToArray()), new SmbConnectionInfo(new IOConnectionInfo() { Path = _uploadPath}));
if (UseFileTransaction)
{
SmbConnectionInfo uploadPath = new SmbConnectionInfo(new IOConnectionInfo() { Path = _uploadPath });
SmbConnectionInfo finalPath = new SmbConnectionInfo(new IOConnectionInfo() { Path = _path });
_fileStorage.RenameFile(uploadPath, finalPath);
}
}
}
private void RenameFile(SmbConnectionInfo fromPath, SmbConnectionInfo toPath)
{
using var connection = new SmbConnection(fromPath);
// Open existing file
var status = connection.FileStore!.CreateFile(out var handle, out _, fromPath.GetLocalSmbPath(), AccessMask.MAXIMUM_ALLOWED, 0, ShareAccess.Read, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE, null);
if (status != NTStatus.STATUS_SUCCESS)
throw new Exception($"Failed to open {fromPath.LocalPath} for renaming!");
FileRenameInformationType2 renameInfo = new FileRenameInformationType2
{
FileName = toPath.GetLocalSmbPath(),
ReplaceIfExists = true
};
connection.FileStore.SetFileInformation(handle, renameInfo);
connection.FileStore.CloseFile(handle);
}
private void UploadData(Stream data, SmbConnectionInfo uploadPath)
{
using var connection = new SmbConnection(uploadPath);
var status = connection.FileStore!.CreateFile(out var fileHandle, out _, uploadPath.GetLocalSmbPath(), AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE, FileAttributes.Normal, ShareAccess.None, CreateDisposition.FILE_CREATE, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null);
if (status == NTStatus.STATUS_OBJECT_NAME_COLLISION)
status = connection.FileStore!.CreateFile(out fileHandle, out _, uploadPath.GetLocalSmbPath(), AccessMask.GENERIC_WRITE | AccessMask.SYNCHRONIZE, FileAttributes.Normal, ShareAccess.None, CreateDisposition.FILE_OVERWRITE, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null);
if (status != NTStatus.STATUS_SUCCESS)
{
throw new Exception($"Failed to open {uploadPath.LocalPath} for writing!");
}
long writeOffset = 0;
while (data.Position < data.Length)
{
byte[] buffer = new byte[(int)connection.Client.MaxWriteSize];
int bytesRead = data.Read(buffer, 0, buffer.Length);
if (bytesRead < (int)connection.Client.MaxWriteSize)
{
Array.Resize(ref buffer, bytesRead);
}
status = connection.FileStore.WriteFile(out _, fileHandle, writeOffset, buffer);
if (status != NTStatus.STATUS_SUCCESS)
{
throw new Exception("Failed to write to file");
}
writeOffset += bytesRead;
}
}
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
{
return new SmbFileStorageWriteTransaction(ioc.Path, this, useFileTransaction);
}
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{
return UrlUtil.StripExtension(
UrlUtil.GetFileName(ioc.Path));
}
public string GetFileExtension(IOConnectionInfo ioc)
{
return UrlUtil.GetExtension(ioc.Path);
}
public bool RequiresCredentials(IOConnectionInfo ioc)
{
return false;
}
public void CreateDirectory(IOConnectionInfo ioc, string newDirName)
{
throw new NotImplementedException();
}
private static IEnumerable<FileDescription> ListShares(SmbConnection conn, SmbConnectionInfo parent)
{
foreach (string share in conn.Client.ListShares(out _))
{
yield return new FileDescription()
{
CanRead = true,
CanWrite = true,
DisplayName = share,
IsDirectory = true,
Path = parent.GetChild(share).ToPath()
};
}
}
public IEnumerable<FileDescription> ListContents(IOConnectionInfo ioc)
{
List<FileDescription> result = [];
SmbConnectionInfo info = new SmbConnectionInfo(ioc);
using SmbConnection conn = new SmbConnection(info);
if (string.IsNullOrEmpty(info.Share))
{
var shares = ListShares(conn, info).ToList();
return shares;
}
NTStatus status = conn.FileStore!.CreateFile(out var directoryHandle, out _, info.GetLocalSmbPath(), AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
if (status == NTStatus.STATUS_SUCCESS)
{
conn.FileStore.QueryDirectory(out List<QueryDirectoryFileInformation> fileList, directoryHandle, "*", FileInformationClass.FileDirectoryInformation);
foreach (var fi in fileList)
{
var fileDirectoryInformation = fi as FileDirectoryInformation;
if (fileDirectoryInformation == null)
continue;
if (fileDirectoryInformation.FileName is "." or "..")
continue;
var fileDescription = FileDescriptionConvert(ioc, fileDirectoryInformation);
result.Add(fileDescription);
}
conn.FileStore.CloseFile(directoryHandle);
}
return result;
}
private FileDescription FileDescriptionConvert(IOConnectionInfo parentIoc,
FileDirectoryInformation fileDirectoryInformation)
{
FileDescription fileDescription = new FileDescription
{
CanRead = true,
CanWrite = true,
IsDirectory = (fileDirectoryInformation.FileAttributes & FileAttributes.Directory) != 0,
DisplayName = fileDirectoryInformation.FileName
};
fileDescription.Path = CreateFilePath(parentIoc.Path, fileDescription.DisplayName);
fileDescription.LastModified = fileDirectoryInformation.LastWriteTime;
fileDescription.SizeInBytes = fileDirectoryInformation.EndOfFile;
return fileDescription;
}
public FileDescription GetFileDescription(IOConnectionInfo ioc)
{
SmbConnectionInfo info = new SmbConnectionInfo(ioc);
if (string.IsNullOrEmpty(info.Share))
{
return new FileDescription
{
CanRead = true, CanWrite = true,
DisplayName = info.Host,
IsDirectory = true,
Path = info.ToPath()
};
}
using SmbConnection conn = new SmbConnection(info);
NTStatus status = conn.FileStore!.CreateFile(out var directoryHandle, out _, info.GetParent().GetLocalSmbPath(), AccessMask.GENERIC_READ, FileAttributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
if (status != NTStatus.STATUS_SUCCESS) throw new Exception($"Failed to query details for {info.LocalPath}");
conn.FileStore.QueryDirectory(out List<QueryDirectoryFileInformation> fileList, directoryHandle, info.Stem(), FileInformationClass.FileDirectoryInformation);
foreach (var fi in fileList)
{
var fileDirectoryInformation = fi as FileDirectoryInformation;
if (fileDirectoryInformation == null)
continue;
if (fileDirectoryInformation.FileName is "." or "..")
continue;
return FileDescriptionConvert(ioc, fileDirectoryInformation);
}
conn.FileStore.CloseFile(directoryHandle);
throw new Exception($"Failed to query details for {info.LocalPath}");
}
public bool RequiresSetup(IOConnectionInfo ioConnection)
{
return false;
}
public string IocToPath(IOConnectionInfo ioc)
{
return ioc.Path;
}
public void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId)
{
activity.PerformManualFileSelect(isForSave, requestCode, protocolId);
}
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode,
bool alwaysReturnSuccess)
{
Intent intent = new Intent();
activity.IocToIntent(intent, ioc);
activity.OnImmediateResult(requestCode, (int)FileStorageResults.FileUsagePrepared, intent);
}
public void PrepareFileUsage(Context ctx, IOConnectionInfo ioc)
{
}
public void OnCreate(IFileStorageSetupActivity activity, Bundle savedInstanceState)
{
}
public void OnResume(IFileStorageSetupActivity activity)
{
}
public void OnStart(IFileStorageSetupActivity activity)
{
}
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
{
}
public string GetDisplayName(IOConnectionInfo ioc)
{
return new SmbConnectionInfo(ioc).ToDisplayString();
}
public string CreateFilePath(string parent, string newFilename)
{
return new SmbConnectionInfo(new IOConnectionInfo() { Path = parent}).GetChild(newFilename).ToPath();
}
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
{
SmbConnectionInfo connectionInfo = new SmbConnectionInfo(ioc);
return new IOConnectionInfo() { Path = connectionInfo.GetParent().ToPath() };
}
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
{
return new IOConnectionInfo() { Path = CreateFilePath(folderPath.Path, filename)};
}
public bool IsPermanentLocation(IOConnectionInfo ioc)
{
return true;
}
public bool IsReadOnly(IOConnectionInfo ioc, OptionalOut<UiStringKey> reason = null)
{
return false;
}
}
}
#endif

View File

@@ -6,10 +6,12 @@ using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Preferences;
using Android.Runtime;
using Android.Views;
using Android.Widget;
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
using Keepass2android.Javafilestorage;
#endif
using KeePassLib.Serialization;
@@ -19,9 +21,15 @@ namespace keepass2android.Io
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
public class WebDavFileStorage: JavaFileStorage
{
public WebDavFileStorage(IKp2aApp app) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler), app)
{
}
private readonly IKp2aApp _app;
private readonly WebDavStorage baseWebdavStorage;
public WebDavFileStorage(IKp2aApp app, int chunkSize) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler, chunkSize), app)
{
_app = app;
baseWebdavStorage = (WebDavStorage)Jfs;
}
public override IEnumerable<string> SupportedProtocols
{
@@ -75,6 +83,15 @@ namespace keepass2android.Io
}
return base.IocToPath(ioc);
}
}
public override IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
{
baseWebdavStorage.SetUploadChunkSize(_app.WebDavChunkedUploadSize);
return base.OpenWriteTransaction(ioc, useFileTransaction);
}
}
#endif
}

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
@@ -10,10 +10,12 @@
<Folder Include="Resources\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP" Version="51.1.0" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="FluentFTP" Version="52.1.0" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="FluentFTP.GnuTLS" Version="1.0.37" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="MegaApiClient" Version="1.10.4" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="Microsoft.Graph" Version="5.68.0" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.1" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="SMBLibrary" Version="1.5.4" Condition="'$(Flavor)'!='NoNet'"/>
<PackageReference Include="Xamarin.AndroidX.Browser" Version="1.8.0" />
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.13.1.5" />
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.11.0.3" />

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -1,6 +1,7 @@
package keepass2android.javafilestorage;
import android.content.Context;
import java.math.BigInteger;
import android.content.Intent;
import android.net.Uri;
@@ -15,7 +16,10 @@ import com.burgstaller.okhttp.basic.BasicAuthenticator;
import com.burgstaller.okhttp.digest.CachingAuthenticator;
import com.burgstaller.okhttp.digest.DigestAuthenticator;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
@@ -24,6 +28,7 @@ import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@@ -44,23 +49,33 @@ import keepass2android.javafilestorage.webdav.DecoratedTrustManager;
import keepass2android.javafilestorage.webdav.PropfindXmlParser;
import keepass2android.javafilestorage.webdav.WebDavUtil;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.internal.tls.OkHostnameVerifier;
import okio.BufferedSink;
public class WebDavStorage extends JavaFileStorageBase {
private final ICertificateErrorHandler mCertificateErrorHandler;
private Context appContext;
public WebDavStorage(ICertificateErrorHandler certificateErrorHandler)
int chunkSize;
public WebDavStorage(ICertificateErrorHandler certificateErrorHandler, int chunkSize)
{
this.chunkSize = chunkSize;
mCertificateErrorHandler = certificateErrorHandler;
}
public void setUploadChunkSize(int chunkSize)
{
this.chunkSize = chunkSize;
}
public String buildFullPath(String url, String username, String password) throws UnsupportedEncodingException {
String scheme = url.substring(0, url.indexOf("://"));
url = url.substring(scheme.length() + 3);
@@ -181,21 +196,119 @@ public class WebDavStorage extends JavaFileStorageBase {
return client;
}
public void renameOrMoveWebDavResource(String sourcePath, String destinationPath, boolean overwrite) throws Exception {
ConnectionInfo sourceCi = splitStringToConnectionInfo(sourcePath);
ConnectionInfo destinationCi = splitStringToConnectionInfo(destinationPath);
Request.Builder requestBuilder = new Request.Builder()
.url(new URL(sourceCi.URL))
.method("MOVE", null) // "MOVE" is the HTTP method
.header("Destination", destinationCi.URL); // New URI for the resource
// Add Overwrite header
if (overwrite) {
requestBuilder.header("Overwrite", "T"); // 'T' for true
} else {
requestBuilder.header("Overwrite", "F"); // 'F' for false
}
Request request = requestBuilder.build();
Response response = getClient(sourceCi).newCall(request).execute();
// Check the status code
if (response.isSuccessful()) {
// WebDAV MOVE can return 201 (Created) if a new resource was created at dest,
// or 204 (No Content) if moved to a pre-existing destination (e.g., just renamed).
// A 200 OK might also be returned by some servers, though 201/204 are more common.
}
else
{
throw new Exception("Rename/Move failed for " + sourceCi.URL + " to " + destinationCi.URL + ": " + response.code() + " " + response.message());
}
}
public static String generateRandomHexString(int length) {
SecureRandom secureRandom = new SecureRandom();
// Generate enough bytes to ensure we can get the desired number of hex characters.
// Each byte converts to two hex characters.
// For 8 hex characters, we need 4 bytes.
int numBytes = (int) Math.ceil(length / 2.0);
byte[] randomBytes = new byte[numBytes];
secureRandom.nextBytes(randomBytes);
// Convert the byte array to a hexadecimal string
// BigInteger(1, randomBytes) treats the byte array as a positive number.
// toString(16) converts it to a hexadecimal string.
String hexString = new BigInteger(1, randomBytes).toString(16);
// Pad with leading zeros if necessary (e.g., if the generated number is small)
// and then take the first 'length' characters.
// Using String.format to ensure leading zeros if the hexString is shorter.
return String.format("%0" + length + "d", new BigInteger(hexString, 16)).substring(0, length);
}
@Override
public void uploadFile(String path, byte[] data, boolean writeTransactional)
throws Exception {
if (writeTransactional)
{
String randomSuffix = ".tmp." + generateRandomHexString(8);
uploadFile(path + randomSuffix, data, false);
renameOrMoveWebDavResource(path+randomSuffix, path, true);
return;
}
try {
ConnectionInfo ci = splitStringToConnectionInfo(path);
RequestBody requestBody;
if (chunkSize > 0)
{
// use chunked upload
requestBody = new RequestBody() {
@Override
public MediaType contentType() {
return MediaType.parse("application/binary");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
try (InputStream in = new ByteArrayInputStream(data)) {
byte[] buffer = new byte[chunkSize];
int read;
while ((read = in.read(buffer)) != -1) {
sink.write(buffer, 0, read);
sink.flush();
}
}
}
@Override
public long contentLength() {
return -1; // use chunked upload
}
};
}
else
{
requestBody = new MultipartBody.Builder()
.addPart(RequestBody.create(data, MediaType.parse("application/binary")))
.build();
}
Request request = new Request.Builder()
.url(new URL(ci.URL))
.put(RequestBody.create(MediaType.parse("application/binary"), data))
.put(requestBody)
.build();
//TODO consider writeTransactional
//TODO check for error
Response response = getClient(ci).newCall(request).execute();
checkStatus(response);
@@ -290,7 +403,10 @@ public class WebDavStorage extends JavaFileStorageBase {
e.sizeInBytes = -1;
}
}
e.isDirectory = r.href.endsWith("/");
e.isDirectory = r.href.endsWith("/") || okprop.IsCollection;
e.displayName = okprop.DisplayName;
if (e.displayName == null)
@@ -519,3 +635,4 @@ public class WebDavStorage extends JavaFileStorageBase {
}
}

View File

@@ -57,6 +57,8 @@ public class PropfindXmlParser
public String DisplayName;
public String LastModified;
public String ContentLength;
public boolean IsCollection;
}
public String status;
public Prop prop;
@@ -191,6 +193,8 @@ public class PropfindXmlParser
continue;
}
String name = parser.getName();
String namespace = parser.getNamespace();
android.util.Log.d("PARSE", "4name = " + name);
if (name.equals("getcontentlength"))
@@ -200,6 +204,9 @@ public class PropfindXmlParser
prop.LastModified = readText(parser);
} else if (name.equals("displayname")) {
prop.DisplayName = readText(parser);
} else if (name.equals("resourcetype") && namespace.equals(ns)) {
// We found the <d:resourcetype> tag
prop.IsCollection = readResourceType(parser);
} else {
skip(parser);
}
@@ -208,6 +215,37 @@ public class PropfindXmlParser
return prop;
}
private boolean readResourceType(XmlPullParser parser) throws IOException, XmlPullParserException {
boolean isCollection = false;
parser.require(XmlPullParser.START_TAG, ns, "resourcetype");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
String namespace = parser.getNamespace();
if (name.equals("collection") && namespace.equals(ns)) {
// We found <d:collection/>, so it's a folder
isCollection = true;
// Since <d:collection/> is usually an empty tag, just consume it.
// It might contain text if there's whitespace, so consume text then end tag.
if (parser.next() == XmlPullParser.TEXT) {
parser.nextTag(); // Move to the end tag
}
parser.require(XmlPullParser.END_TAG, ns, "collection");
} else {
// Skip any other unexpected tags within <d:resourcetype>
skip(parser);
}
}
// After reading all children of <d:resourcetype>, ensure we are at its END_TAG
parser.require(XmlPullParser.END_TAG, ns, "resourcetype");
return isCollection;
}
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
android.util.Log.d("PARSE", "skipping " + parser.getName());

View File

@@ -548,7 +548,7 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
//storageToTest = new GoogleDriveAppDataFileStorage();
/*storageToTest = new WebDavStorage(new ICertificateErrorHandler() {
storageToTest = new WebDavStorage(new ICertificateErrorHandler() {
@Override
public boolean onValidationError(String error) {
return false;
@@ -558,12 +558,12 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag
public boolean alwaysFailOnValidationError() {
return false;
}
});
*/
}, 64*1024);
//storageToTest = new DropboxV2Storage(ctx,"4ybka4p4a1027n6", "1z5lv528un9nre8", !simulateRestart);
//storageToTest = new DropboxFileStorage(ctx,"4ybka4p4a1027n6", "1z5lv528un9nre8", !simulateRestart);
//storageToTest = new DropboxAppFolderFileStorage(ctx,"ax0268uydp1ya57", "3s86datjhkihwyc", true);
storageToTest = new GoogleDriveFullFileStorage();
// storageToTest = new GoogleDriveFullFileStorage();
return storageToTest;

View File

@@ -31,6 +31,12 @@ namespace keepass2android
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ctx);
builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title));
List<string> changeLog = new List<string>{
#if !NoNet
BuildChangelogString(ctx, new List<int>{Resource.Array.ChangeLog_1_14_net}, "1.14"),
#endif
BuildChangelogString(ctx, new List<int>{Resource.Array.ChangeLog_1_13}, "1.13"),
BuildChangelogString(ctx, new List<int>{Resource.Array.ChangeLog_1_12
#if !NoNet
,Resource.Array.ChangeLog_1_12_net

View File

@@ -4,12 +4,15 @@ using System.Linq;
using System.Net;
#if !NoNet
using FluentFTP;
using static Kp2aBusinessLogic.Io.SmbFileStorage;
#endif
using System.Text;
using Android.App;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Preferences;
using Android.Runtime;
using Android.Views;
using Android.Widget;
@@ -23,6 +26,7 @@ using Keepass2android.Javafilestorage;
using KeePassLib.Serialization;
using KeePassLib.Utility;
namespace keepass2android
{
public class FileSelectHelper
@@ -274,7 +278,8 @@ namespace keepass2android
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
builder.SetTitle(activity.GetString(Resource.String.enter_sftp_login_title));
Dialog dialog = builder.Create();
builder.SetCancelable(false);
Dialog dialog = builder.Create();
dialog.Show();
#endif
@@ -319,7 +324,7 @@ namespace keepass2android
View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.httpcredentials, null);
if (!defaultPath.EndsWith(_schemeSeparator))
{
var webdavStorage = new Keepass2android.Javafilestorage.WebDavStorage(App.Kp2a.CertificateErrorHandler);
var webdavStorage = CreateWebdavStorage(activity);
var connInfo = webdavStorage.SplitStringToConnectionInfo(defaultPath);
dlgContents.FindViewById<EditText>(Resource.Id.http_url).Text = connInfo.Url;
dlgContents.FindViewById<EditText>(Resource.Id.http_user).Text = connInfo.Username;
@@ -339,7 +344,7 @@ namespace keepass2android
string scheme = defaultPath.Substring(0, defaultPath.IndexOf(_schemeSeparator, StringComparison.Ordinal));
if (host.Contains(_schemeSeparator) == false)
host = scheme + _schemeSeparator + host;
string httpPath = new Keepass2android.Javafilestorage.WebDavStorage(null).BuildFullPath(host, user,
string httpPath = CreateWebdavStorage(activity).BuildFullPath(host, user,
password);
onStartBrowse(httpPath);
});
@@ -347,13 +352,61 @@ namespace keepass2android
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
builder.SetTitle(activity.GetString(Resource.String.enter_http_login_title));
Dialog dialog = builder.Create();
builder.SetCancelable(false);
Dialog dialog = builder.Create();
dialog.Show();
#endif
}
private void ShowFtpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
private void ShowSmbDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
{
#if !EXCLUDE_JAVAFILESTORAGE && !NoNet
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
View dlgContents = activity.LayoutInflater.Inflate(Resource.Layout.smbcredentials, null);
if (!defaultPath.EndsWith(_schemeSeparator))
{
SmbConnectionInfo ci = new SmbConnectionInfo(new IOConnectionInfo() { Path = defaultPath });
dlgContents.FindViewById<EditText>(Resource.Id.smb_url).Text = ci.GetPathWithoutCredentials();
dlgContents.FindViewById<EditText>(Resource.Id.smb_domain).Text = ci.Domain;
dlgContents.FindViewById<EditText>(Resource.Id.smb_user).Text = ci.Username;
dlgContents.FindViewById<EditText>(Resource.Id.smb_password).Text = ci.Password;
}
builder.SetView(dlgContents);
builder.SetPositiveButton(Android.Resource.String.Ok,
(sender, args) =>
{
string url = dlgContents.FindViewById<EditText>(Resource.Id.smb_url).Text;
string user = dlgContents.FindViewById<EditText>(Resource.Id.smb_user).Text;
string password = dlgContents.FindViewById<EditText>(Resource.Id.smb_password).Text;
string domain = dlgContents.FindViewById<EditText>(Resource.Id.smb_domain).Text;
string fullPath = SmbConnectionInfo.FromUrlAndCredentials(url, user, password, domain).ToPath();
onStartBrowse(fullPath);
});
builder.SetCancelable(false);
EventHandler<DialogClickEventArgs> evtH = new EventHandler<DialogClickEventArgs>((sender, e) => onCancel());
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
builder.SetTitle(activity.GetString(Resource.String.enter_smb_login_title));
Dialog dialog = builder.Create();
dialog.Show();
#endif
}
#if !NoNet
private static WebDavStorage CreateWebdavStorage(Activity activity)
{
return new WebDavStorage(App.Kp2a.CertificateErrorHandler, App.Kp2a.WebDavChunkedUploadSize);
}
#endif
private void ShowFtpDialog(Activity activity, Util.FileSelectedHandler onStartBrowse, Action onCancel, string defaultPath)
{
#if !NoNet
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
@@ -403,7 +456,8 @@ namespace keepass2android
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
builder.SetTitle(activity.GetString(Resource.String.enter_ftp_login_title));
Dialog dialog = builder.Create();
builder.SetCancelable(false);
Dialog dialog = builder.Create();
dialog.Show();
#endif
@@ -463,7 +517,8 @@ namespace keepass2android
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
builder.SetTitle(activity.GetString(Resource.String.enter_mega_login_title));
Dialog dialog = builder.Create();
builder.SetCancelable(false);
Dialog dialog = builder.Create();
dialog.Show();
#endif
@@ -479,7 +534,9 @@ namespace keepass2android
ShowFtpDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
else if ((defaultPath.StartsWith("http://")) || (defaultPath.StartsWith("https://")))
ShowHttpDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
else if (defaultPath.StartsWith("owncloud://"))
else if ((defaultPath.StartsWith("smb://")))
ShowSmbDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath);
else if (defaultPath.StartsWith("owncloud://"))
ShowOwncloudDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath, "owncloud");
else if (defaultPath.StartsWith("nextcloud://"))
ShowOwncloudDialog(_activity, ReturnFileOrStartFileChooser, ReturnCancel, defaultPath, "nextcloud");
@@ -518,7 +575,7 @@ namespace keepass2android
string scheme = defaultPath.Substring(0,defaultPath.IndexOf(_schemeSeparator, StringComparison.Ordinal));
if (host.Contains(_schemeSeparator) == false)
host = scheme + _schemeSeparator + host;
string httpPath = new Keepass2android.Javafilestorage.WebDavStorage(null).BuildFullPath(WebDavFileStorage.Owncloud2Webdav(host, subtype == "owncloud" ? WebDavFileStorage.owncloudPrefix : WebDavFileStorage.nextcloudPrefix), user,
string httpPath = CreateWebdavStorage(activity).BuildFullPath(WebDavFileStorage.Owncloud2Webdav(host, subtype == "owncloud" ? WebDavFileStorage.owncloudPrefix : WebDavFileStorage.nextcloudPrefix), user,
password);
onStartBrowse(httpPath);
});
@@ -526,7 +583,8 @@ namespace keepass2android
builder.SetNegativeButton(Android.Resource.String.Cancel, evtH);
builder.SetTitle(activity.GetString(subtype == "owncloud" ? Resource.String.enter_owncloud_login_title : Resource.String.enter_nextcloud_login_title));
Dialog dialog = builder.Create();
builder.SetCancelable(false);
Dialog dialog = builder.Create();
dlgContents.FindViewById<EditText>(Resource.Id.owncloud_url).SetHint(subtype == "owncloud" ? Resource.String.hint_owncloud_url : Resource.String.hint_nextcloud_url);
dialog.Show();
#endif

View File

@@ -145,12 +145,14 @@ namespace keepass2android
protected override void OnCreate(Bundle savedInstanceState) {
_design.ApplyTheme();
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.generate_password);
SetResult(KeePass.ExitNormal);
var prefs = GetPreferences(FileCreationMode.Private);
new Util.InsetListener(FindViewById(Resource.Id.main_container)).Apply();
var prefs = GetPreferences(FileCreationMode.Private);

View File

@@ -43,7 +43,7 @@
</queries>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="35" />
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_notify_locked" android:label="KP2A entry search" android:name="keepass2android.keepass2android_debug.permission.KP2aInternalSearch" android:protectionLevel="signature" />
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_debug.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />
<application

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="218"
android:versionName="1.12-r9d"
android:versionCode="223"
android:versionName="1.14-pre0"
package="keepass2android.keepass2android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto">
@@ -42,7 +42,7 @@
<action android:name="android.intent.action.VIEW" />
</intent>
</queries>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="35" />
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher" android:label="KP2A entry search" android:name="keepass2android.keepass2android.permission.KP2aInternalSearch" android:protectionLevel="signature" />
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="218"
android:versionName="1.12-r9d"
android:versionCode="223"
android:versionName="1.14-pre0"
package="keepass2android.keepass2android_nonet"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto">
@@ -42,7 +42,7 @@
<action android:name="android.intent.action.VIEW" />
</intent>
</queries>
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="35" />
<permission android:description="@string/permission_desc2" android:icon="@drawable/ic_launcher_offline" android:label="KP2A entry search" android:name="keepass2android.keepass2android_nonet.permission.KP2aInternalSearch" android:protectionLevel="signature" />
<permission android:description="@string/permission_desc3" android:icon="@drawable/ic_launcher_offline" android:label="KP2A choose autofill dataset" android:name="keepass2android.keepass2android_nonet.permission.Kp2aChooseAutofill" android:protectionLevel="signature" />

View File

@@ -15,6 +15,36 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Database;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Preferences;
using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using AndroidX.AppCompat.App;
using AndroidX.CoordinatorLayout.Widget;
using AndroidX.Core.Content;
using AndroidX.Core.View;
using AndroidX.DrawerLayout.Widget;
using Google.Android.Material.AppBar;
using Google.Android.Material.Dialog;
using Java.Lang;
using Java.Net;
using KeeChallenge;
using keepass2android;
using keepass2android.Io;
using keepass2android.Utils;
using Keepass2android.Pluginsdk;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using OtpKeyProv;
using System;
using System.Collections.Generic;
using System.IO;
@@ -23,49 +53,17 @@ using System.Net;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using keepass2android;
using Android.App;
using Android.Content;
using Android.Database;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Java.Net;
using Android.Preferences;
using Android.Text;
using Android.Content.PM;
using Android.Graphics;
using AndroidX.AppCompat.App;
using AndroidX.CoordinatorLayout.Widget;
using AndroidX.Core.View;
using AndroidX.DrawerLayout.Widget;
using Google.Android.Material.AppBar;
using Google.Android.Material.Dialog;
using Java.Lang;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using Keepass2android.Pluginsdk;
using OtpKeyProv;
using keepass2android.Io;
using keepass2android.Utils;
using File = Java.IO.File;
using FileNotFoundException = Java.IO.FileNotFoundException;
using Object = Java.Lang.Object;
using Process = Android.OS.Process;
using KeeChallenge;
using static Android.Locations.GpsStatus;
using AlertDialog = Android.App.AlertDialog;
using ClipboardManager = Android.Content.ClipboardManager;
using Enum = System.Enum;
using Exception = System.Exception;
using File = Java.IO.File;
using FileNotFoundException = Java.IO.FileNotFoundException;
using Object = Java.Lang.Object;
using Process = Android.OS.Process;
using String = System.String;
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
using AndroidX.Core.Content;
namespace keepass2android
{
@@ -651,7 +649,7 @@ namespace keepass2android
_activityDesign.ApplyTheme();
base.OnCreate(savedInstanceState);
_intentReceiver = new PasswordActivityBroadcastReceiver(this);
_intentReceiver = new PasswordActivityBroadcastReceiver(this);
IntentFilter filter = new IntentFilter();
filter.AddAction(Intent.ActionScreenOff);
ContextCompat.RegisterReceiver(this, _intentReceiver, filter, (int)ReceiverFlags.Exported);
@@ -1165,7 +1163,9 @@ namespace keepass2android
changeDbButton.Click += (sender, args) => GoToFileSelectActivity();
Util.MoveBottomBarButtons(Resource.Id.change_db, Resource.Id.pass_ok, Resource.Id.bottom_bar, this);
}
Util.InsetListener.ForBottomElement(FindViewById(Resource.Id.bottom_bar)).Apply();
Util.InsetListener.ForTopElement(FindViewById(Resource.Id.appbar)).Apply();
}
private void OnOk(bool usedFingerprintUnlock = false)
{

View File

@@ -81,8 +81,11 @@ namespace keepass2android
SetContentView(Resource.Layout.QuickUnlock);
Util.InsetListener.ForBottomElement(FindViewById(Resource.Id.bottom_bar)).Apply();
Util.InsetListener.ForTopElement(FindViewById(Resource.Id.appbar)).Apply();
var collapsingToolbar = FindViewById<CollapsingToolbarLayout>(Resource.Id.collapsing_toolbar);
var collapsingToolbar = FindViewById<CollapsingToolbarLayout>(Resource.Id.collapsing_toolbar);
collapsingToolbar.SetTitle(GetString(Resource.String.QuickUnlock_prefs));
SetSupportActionBar(FindViewById<Toolbar>(Resource.Id.toolbar));

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="false">
<keepass2android.MeasuringLinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@@ -17,7 +17,7 @@ android:fitsSystemWindows="true">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:fitsSystemWindows="true">
android:fitsSystemWindows="false">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
@@ -28,7 +28,7 @@ android:fitsSystemWindows="true">
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true"
android:fitsSystemWindows="false"
app:expandedTitleMarginStart="16dp"
app:expandedTitleMarginEnd="24dp"
app:expandedTitleMarginBottom="20sp">

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_container"
android:layout_width="fill_parent"
android:background="?android:attr/colorBackground"
android:layout_height="fill_parent">
@@ -322,4 +323,3 @@
</ScrollView>
</RelativeLayout>

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<keepass2android.FixedDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="true">
>
<!-- activity view -->
<keepass2android.MeasuringLinearLayout
android:layout_width="fill_parent"
@@ -17,14 +17,13 @@
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:fitsSystemWindows="true">
android:layout_weight="1">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"
android:fitsSystemWindows="true"
android:fitsSystemWindows="false"
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
@@ -32,14 +31,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true"
app:expandedTitleMarginStart="48dp"
android:fitsSystemWindows="false"
app:collapsedTitleGravity="center"
app:expandedTitleGravity="bottom|left"
app:expandedTitleMarginStart="8dp"
app:expandedTitleMarginEnd="24dp"
app:expandedTitleMarginBottom="20sp">
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:fitsSystemWindows="true"
android:fitsSystemWindows="false"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/backdrop"
@@ -52,7 +54,7 @@
android:layout_alignParentBottom="true"
android:layout_marginBottom="0sp"
android:layout_marginLeft="48dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
@@ -446,4 +448,4 @@
</LinearLayout>
</ScrollView>
</com.google.android.material.navigation.NavigationView>
</keepass2android.FixedDrawerLayout>
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:layout_margin="12dip"
>
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hint_smb_credentials" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/smb_url"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_weight="1"
android:text=""
android:inputType="textWebEmailAddress"
android:hint="@string/hint_smb_url" />
</LinearLayout>
<EditText
android:id="@+id/smb_domain"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text=""
android:hint="@string/hint_smb_domain" />
<EditText
android:id="@+id/smb_user"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text=""
android:hint="@string/hint_smb_username" />
<EditText
android:id="@+id/smb_password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:singleLine="true"
android:text=""
android:hint="@string/hint_pass"
android:importantForAccessibility="no"/>
</LinearLayout>

View File

@@ -93,6 +93,8 @@
<string name="disable_fingerprint_unlock">Zakázat Biometrické odemknutí</string>
<string name="enable_fingerprint_unlock">Povolit plné Biometrické odemknutí</string>
<string name="enable_fingerprint_quickunlock">Povolit Biometrické odemknutí pro Rychlé odemknutí</string>
<string name="password_based_quick_unlock_not_available">Rychlé odemknutí pomocí hesla není k dispozici</string>
<string name="password_based_quick_unlock_not_available_text">Funkce Rychlé odemknutí pomocí části hesla je blokována, protože na vašem zařízení není aktivováno zamykání obrazovky. Toto opatření slouží k vaší ochraně pro případ, že by někdo sledoval zadávání klíče pro Rychlé odemknutí.</string>
<string name="fingerprint_unlock_failed">Biometrické odemknutí selhalo. Dešifrovací klíč byl zneplatněn systémem Android. To se obvykle stává, pokud došlo ke změně biometrického ověření nebo bylo změněno bezpečnostní nastavení. </string>
<string name="fingerprint_disabled_wrong_masterkey">Odemknutí databáze se nezdařilo: neplatný složený klíč. Biometrické odemknutí bylo zakázáno z důvodu pravděpodobného vypršení platnosti hlavního hesla. </string>
<string name="fingerprint_reenable">Prosím, povolte znovu Biometrické odemknutí pro nové hlavní heslo.</string>
@@ -319,6 +321,7 @@
<string name="QuickUnlock_label_secure">Vložte kód Rychlého odemknutí:</string>
<string name="QuickUnlock_button">Rychlé odemknutí</string>
<string name="QuickUnlock_lockButton">Zavřít databázi</string>
<string name="enable_screen_lock">Povolit zámek obrazovky</string>
<string name="QuickUnlockDefaultEnabled_title">Ve výchozím nastavení povolit Rychlé odemknutí</string>
<string name="QuickUnlockDefaultEnabled_summary">Určuje, zda je Rychlé odemknutí ve výchozím nastavení povoleno nebo ne.</string>
<string name="ViewDatabaseSecure_title">Chránit zobrazení databáze</string>
@@ -718,6 +721,11 @@
<string name="EntryChannel_desc">Upozornění pro usnadnění přístupu k momentálně zvolené položce.</string>
<string name="CloseDbAfterFailedAttempts">Zavřít databázi po třech neúspěšných pokusech o odemknutí.</string>
<string name="WarnFingerprintInvalidated">Varování! Biometrické ověření může být zneplatněno Androidem, např. po přidání nového otisku prstu do nastavení zařízení. Ujistěte se, že vždy víte, jak odemknout pomocí hlavního hesla!</string>
<string-array name="ChangeLog_1_13">
<item>Vylepšené hodnocení kvality hesel založené na nejčastěji používaných heslech.</item>
<item>Pokud zařízení nemá aktivovaný zámek obrazovky, blokuje se funkce Rychlé odemknutí pomocí hesla (z bezpečnostních důvodů).</item>
<item>Aktualizovat konfiguraci zabezpečení sítě pro vypnutí přenosu textu v nešifrované podobě.</item>
</string-array>
<string-array name="ChangeLog_1_12">
<item>Aktualizováno z Xamarin Android na .net 8</item>
<item>Aktualizováno na Target SDK 34</item>

View File

@@ -176,7 +176,8 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die
<string name="masktotp_title">TOTP-Feld verdecken</string>
<string name="masktotp_summary">TOTP-Feld standardmäßig ausblenden</string>
<string name="NoAutofillDisabling_title">Keine Option, um Autofill zu deaktivieren</string>
<string name="NoAutofillDisabling_summary">Wenn aktiviert, wird die App die Option zum Abschalten von Autofill für bestimmte Einträge nicht anzeigen. </string>
<string name="NoAutofillDisabling_summary">Wenn aktiviert, wird die App die Option zum Abschalten von Autofill für bestimmte Einträge nicht angezeigt.
</string>
<string name="menu_about">Über</string>
<string name="menu_change_key">Hauptschlüssel ändern</string>
<string name="menu_copy_pass">Passwort kopieren</string>
@@ -290,7 +291,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die
<string name="please_note">Bitte beachten</string>
<string name="contributors">Mitwirkende</string>
<string name="regular_expression">Regulärer Ausdruck</string>
<string name="AlwaysMergeOnConflict_title">Bei Konflikt immer vereinigen</string>
<string name="AlwaysMergeOnConflict_title">Bei Konflikt immer zusammenführen</string>
<string name="AlwaysMergeOnConflict_summary">Die lokalen Änderungen immer mit den entfernten Änderungen vereinigen, wenn Keepass2Android erkennt, dass die entfernte Datei verändert wurde.</string>
<string name="TanExpiresOnUse_title">TAN verfällt bei Verwendung</string>
<string name="TanExpiresOnUse_summary">TAN-Einträge als abgelaufen markieren, wenn sie verwendet werden</string>
@@ -332,7 +333,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die
<string name="QuickUnlockLength_summary">Maximale Anzahl von Zeichen, die als QuickUnlock-Passwort verwendet werden.</string>
<string name="QuickUnlockHideLength_title">Länge des QuickUnlock-Codes verstecken</string>
<string name="QuickUnlockHideLength_summary">Wenn aktiviert, wird die Länge des QuickUnlock-Codes nicht auf dem QuickUnlock-Bildschirm angezeigt.</string>
<string name="QuickUnlockKeyFromDatabase_title">QuickUnlock-Taste aus dem Datenbankeintrag.</string>
<string name="QuickUnlockKeyFromDatabase_title">QuickUnlock-Schlüssel aus Datenbankeintrag</string>
<string name="QuickUnlockKeyFromDatabase_summary">Wenn die aktive Datenbank einen Eintrag mit dem Titel „QuickUnlock“ in der Root-Gruppe enthält, wird das Passwort dieses Eintrags als QuickUnlock-Code verwendet.</string>
<string name="QuickUnlock_fail">QuickUnlock fehlgeschlagen: falsches Passwort!</string>
<string name="SaveAttachmentDialog_title">Anhang speichern</string>
@@ -559,7 +560,7 @@ Der Android Robot wird genutzt und wurde modifiziert basierend auf Arbeiten, die
<string name="filestoragename_onedrive2_appfolder">Ordner der Keepass2Android-App</string>
<string name="filestoragename_sftp">SFTP (SSH File Transfer)</string>
<string name="filestoragename_mega">MEGA</string>
<string name="filestoragehelp_mega">Bitte beachte: Keepass2Android muss eineListe aller Dateien des Mega-Kontos herunterladen, um ordnungsgemäß zu funktionieren. Aus diesem Grund ist der Zugriff auf Konten mit vielen Dateien möglicherweise langsam.</string>
<string name="filestoragehelp_mega">Bitte beachte: Keepass2Android muss eine Liste aller Dateien des Mega-Kontos herunterladen, um ordnungsgemäß zu funktionieren. Aus diesem Grund ist der Zugriff auf Konten mit vielen Dateien möglicherweise langsam.</string>
<string name="filestoragename_content">Android-Dateibrowser</string>
<string name="filestorage_setup_title">Dateizugriff initialisieren</string>
<string name="database_location">Speicherort der Datenbank</string>
@@ -759,7 +760,7 @@ Anbei einige Tipps, die bei der Diagnose des Problems helfen können:\n
<string-array name="ChangeLog_1_09d">
<item>Unterstützung für das Ansehen, Entfernen und Wiederherstellen von Eintragssicherungen hinzugefügt</item>
<item>Unterstützung für MEGA-Cloudspeicher hinzugefügt </item>
<item>Unterstützung für Google Drive mit eingeschränktem Anwendungsbereich hinzugefügt</item>
<item>Unterstützung für Google Drive mit eingeschränktem Zugriff hinzugefügt</item>
</string-array>
<string-array name="ChangeLog_1_09c">
<item>Google-Drive-Authentifizierung erneut implementiert, Google-Drive-Unterstützung wieder aktiviert </item>

View File

@@ -93,6 +93,8 @@
<string name="disable_fingerprint_unlock">Απενεργοποίηση βιομετρικού ξεκλειδώματος</string>
<string name="enable_fingerprint_unlock">Ενεργοποίηση πλήρους βιομετρικού ξεκλειδώματος</string>
<string name="enable_fingerprint_quickunlock">Ενεργοποίηση βιομετρικού ξεκλειδώματος για QuickUnlock</string>
<string name="password_based_quick_unlock_not_available">Το QuickUnlock βασισμένο σε συνθηματικό δεν είναι διαθέσιμο.</string>
<string name="password_based_quick_unlock_not_available_text">Το QuickUnlock που χρησιμοποιεί ένα τμήμα του συνθηματικού έχει αποκλειστεί, επειδή το κλείδωμα οθόνης είναι απενεργοποιημένο στη συσκευή σας. Αυτό σας προστατεύει σε περίπτωση που κάποιος σας παρακολουθεί όταν εισάγετε το QuickUnlock.</string>
<string name="fingerprint_unlock_failed">Αποτυχία βιομετρικού ξεκλειδώματος. Το κλειδί αποκρυπτογράφησης ακυρώθηκε από το Android. Αυτό συμβαίνει συνήθως αν αλλάξει η βιομετρική αυθεντικοποίηση ή οι ρυθμίσεις ασφάλειας. </string>
<string name="fingerprint_disabled_wrong_masterkey">Το ξεκλείδωμα της βάσης δεδομένων απέτυχε: άκυρο σύνθετο κλειδί. Το βιομετρικό ξεκλείδωμα απενεργοποιήθηκε επειδή το αποθηκευμένο πρωτεύον συνθηματικό δεν είναι πλέον έγκυρο. </string>
<string name="fingerprint_reenable">Ενεργοποιήστε ξανά το βιομετρικό ξεκλείδωμα για το νέο πρωτεύον συνθηματικό.</string>
@@ -251,7 +253,6 @@
<string name="exclude_lookalike">Εξαίρεση παρόμοιων χαρακτήρων</string>
<string name="password_generation_profile">Προφίλ</string>
<string name="save_password_generation_profile_text">Εισάγετε το όνομα του προφίλ που θα αποθηκευτεί. Εισάγετε ένα υπάρχον όνομα για αντικατάσταση.</string>
<string name="hint_wordcount">Αριθμός λέξεων συνθηματικής φράσης</string>
<string name="hint_wordseparator">Διαχωριστικό λέξεων</string>
<string-array name="PasswordGeneratorModes">
<item>Συνθηματικό</item>
@@ -319,6 +320,7 @@
<string name="QuickUnlock_label_secure">Εισάγετε τον κωδικό QuickUnlock:</string>
<string name="QuickUnlock_button">QuickUnlock!</string>
<string name="QuickUnlock_lockButton">Κλείσιμο βάσης δεδομένων</string>
<string name="enable_screen_lock">Ενεργοποίηση κλειδώματος οθόνης</string>
<string name="QuickUnlockDefaultEnabled_title">Ενεργοποίηση QuickUnlock εξ ορισμού</string>
<string name="QuickUnlockDefaultEnabled_summary">Ορίζει αν το QuickUnlock είναι ενεργό εξ ορισμού ή όχι.</string>
<string name="ViewDatabaseSecure_title">Προστασία προβολής βάσης δεδομένων</string>
@@ -332,7 +334,7 @@
<string name="QuickUnlockHideLength_title">Απόκρυψη μήκους QuickUnlock</string>
<string name="QuickUnlockHideLength_summary">Αν ενεργοποιηθεί, αποκρύπτει το μήκος του κωδικού QuickUnlock στη σχετική οθόνη.</string>
<string name="QuickUnlockKeyFromDatabase_title">Κλειδί QuickUnlock από τη βάση δεδομένων</string>
<string name="QuickUnlockKeyFromDatabase_summary">Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώριση με τίτλο QuickUnlock στην ομάδα ρίζας της, ο κωδικός πρόσβασης αυτής της καταχώρισης χρησιμοποιείται ως κωδικός QuickUnlock.</string>
<string name="QuickUnlockKeyFromDatabase_summary">Εάν η ενεργή βάση δεδομένων περιέχει μια καταχώριση με τίτλο QuickUnlock στην ομάδα ρίζας της, το συνθηματικό αυτής της καταχώρισης χρησιμοποιείται ως κωδικός QuickUnlock.</string>
<string name="QuickUnlock_fail">Αποτυχία QuickUnlock: λανθασμένο συνθηματικό!</string>
<string name="SaveAttachmentDialog_title">Αποθήκευση συνημμένου</string>
<string name="SaveAttachmentDialog_text">Επιλέξτε πού θα αποθηκεύσετε το συνημμένο.</string>
@@ -427,7 +429,7 @@
<string name="IconVisibilityInfo_Android8_btnSettings">Άνοιγμα ρυθμίσεων</string>
<string name="PostNotificationsPermissionInfo_text">Το Keepass2Android μπορεί να εμφανίζει μια ειδοποίηση συστήματος ενόσω η βάση δεδομένων σας παραμένει ξεκλείδωτη. Για να λειτουργήσει αυτό, χορηγήστε την άδεια.</string>
<string name="DontCare">Δεν με νοιάζει</string>
<string name="DocumentAccessRevoked">Το αρχείο δεν είναι πλέον προσπελάσιμο στο Keepass2Android. Είτε διαγράφτηκε ή ανακηθηκαν τα δικαιώματα πρόσβασης. Δοκιμάστε να ξανα-ανοίξετε το αρχείο, πχ με Αλλαγή βάσης δεδομένων.</string>
<string name="DocumentAccessRevoked">Το αρχείο δεν είναι πλέον προσπελάσιμο στο Keepass2Android. Είτε διαγράφτηκε ή ανακλήθηκαν τα δικαιώματα πρόσβασης. Δοκιμάστε να ξανανοίξετε το αρχείο, πχ με Αλλαγή βάσης δεδομένων.</string>
<string name="PreloadDatabaseEnabled_title">Προ-φόρτωση αρχείου βάσης δεδομένων</string>
<string name="PreloadDatabaseEnabled_summary">Ξεκίνημα φόρτωσης στο παρασκήνιο ή λήψη του αρχείου της βάσης δεδομένων κατά την εισαγωγή του συνθηματικού.</string>
<string name="SyncAfterQuickUnlock_title">Συγχρονισμός μετά το QuickUnlock</string>
@@ -714,14 +716,19 @@
<string name="EntryChannel_name">Ειδοποιήσεις</string>
<string name="EntryChannel_desc">Ειδοποίηση για απλοποιημένη πρόσβαση στην τρέχουσα καταχώριση.</string>
<string name="CloseDbAfterFailedAttempts">Κλείσιμο της βάσης δεδομένων μετά από 3 ανεπιτυχείς προσπάθειες βιομετρικού ξεκλειδώματος.</string>
<string name="WarnFingerprintInvalidated">Προσοχή! Ο βιομετρικός έλεγχος ταυτότητας μπορεί να ακυρωθεί από το Android, π.χ. μετά την προσθήκη ενός νέου δακτυλικού αποτυπώματος στις ρυθμίσεις της συσκευής σας. Βεβαιωθείτε ότι ξέρετε πάντα πώς να ξεκλειδώσετε με τον κύριο κωδικό πρόσβασης!</string>
<string name="WarnFingerprintInvalidated">Προσοχή! Ο βιομετρικός έλεγχος ταυτότητας μπορεί να ακυρωθεί από το Android, π.χ. μετά την προσθήκη ενός νέου δακτυλικού αποτυπώματος στις ρυθμίσεις της συσκευής σας. Βεβαιωθείτε ότι ξέρετε πάντα πώς να ξεκλειδώσετε με το κύριο συνθηματικό!</string>
<string-array name="ChangeLog_1_13">
<item>Βελτιωμένη εκτίμηση της ποιότητας του συνθηματικού που λαμβάνει υπόψη τα πιο δημοφιλή συνθηματικά</item>
<item>Αποκλεισμός του QuickUnlock βασισμένου στο συνθηματικό (για λόγους ασφαλείας), εάν η συσκευή δεν έχει ενεργοποιημένο το κλείδωμα οθόνης.</item>
<item>Ενημερώστε τις ρυθμίσεις ασφαλείας δικτύου για να απενεργοποιήσετε τη μεταφορά ορατού κειμένου.</item>
</string-array>
<string-array name="ChangeLog_1_12">
<item>Αναβαθμίστηκε από Xamarin Android σε .ΝΕΤ 8</item>
<item>Αναβαθμίστηκε στοχεύοντας το SDK 34</item>
<item>Αναβαθμίστηκε σε διεπαφή χρήστη Material 3</item>
<item>Βελτιώστε την αυτόματη συμπλήρωση για να εργαστείτε με Compose Apps</item>
<item>Διόρθωση ονόματος host στην αυτόματη συμπλήρωση και αναζήτηση</item>
<item>Διόρθωση προβλήματος με τη γεννήτρια κωδικού πρόσβασης</item>
<item>Διόρθωση προβλήματος με τη γεννήτρια συνθηματικών</item>
</string-array>
<string-array name="ChangeLog_1_12_net">
<item>Αναβαθμίστηκε το OneDrive SDK στην έκδοση 5.68</item>
@@ -747,12 +754,12 @@
<item>Βελτίωση της υλοποίησης FTP και SFTP</item>
<item>Προσθήκη πρόσβασης σε πλήρες pCloud</item>
<item>Επιτρέπει την επιλογή γλώσσας συστήματος στο μενού της γλώσσας</item>
<item>Διόρθωση προβλήματος με την απομνημόνευση Keyfile + ερώτηση για τον τύπο του κωδικού πρόσβασης</item>
<item>Διόρθωση προβλήματος με την απομνημόνευση Keyfile + ερώτηση για το συνθηματικό</item>
</string-array>
<string-array name="ChangeLog_1_09e">
<item>Διόρθωση σφάλματος για απότομα κλεισίματα εφαρμογής και μη αναμενόμενες αποσυνδέσεις</item>
<item>Μετάβαση σε νέα υλοποίηση SFTP, υποστηρίζοντας σύγχρονους αλγόριθμους δημόσιου κλειδιού όπως rsa-sha2-256</item>
<item>Μαρκάρισμα κωδικών πρόσβασης ως ευαίσθητοι κατά την αντιγραφή στο πρόχειρο (Android 13)</item>
<item>Μαρκάρισμα των συνθηματικών ως ευαίσθητα κατά την αντιγραφή στο πρόχειρο (Android 13)</item>
<item>Βελτιώσεις Autofill</item>
</string-array>
<string-array name="ChangeLog_1_09d">
@@ -773,7 +780,7 @@
<string-array name="ChangeLog_1_09a">
<item>Προστέθηκε υποστήριξη για τη μορφή αρχείου KDBX 4.1 που εισήχθη στο KeePass 2.48</item>
<item>Προστέθηκε ο διάλογος ρύθμισης ρυθμίσεων TOTP για τις καταχωρίσεις</item>
<item>Βελτιωμένη γεννήτρια κωδικού πρόσβασης: Προστέθηκε υποστήριξη συνθηματικής φράσης, περισσότερες επιλογές, προφίλ και εκτίμηση ισχύος κωδικού πρόσβασης</item>
<item>Βελτιωμένη γεννήτρια συνθηματικών: Προστέθηκε υποστήριξη συνθηματικής φράσης, περισσότερες επιλογές, προφίλ και εκτίμηση ισχύος κωδικού πρόσβασης</item>
<item>Βελτιώσεις στην αυτόματη συμπλήρωση (σταθερό αναδυόμενο παράθυρο δεν εμφανίζεται στο Chrome, καλύτερη υποστήριξη υποτομέα)</item>
<item>Βελτιώσεις στην υλοποίηση του OneDrive: δεν υπάρχει πλέον όριο μεγέθους, ούτε περιττές αιτήσεις ελέγχου ταυτότητας</item>
<item>Προστέθηκε επιλογή για να επιλέξετε το φωτεινό/σκούρο θέμα από τις ρυθμίσεις του συστήματος, συμπεριλαμβανομένων των νυχτερινών πλάνων, απαιτεί Android 10+</item>
@@ -883,7 +890,7 @@
<string name="invalid_link_association">Δεν σχετίζεται το web domain %1$s με την εφαρμογή %2$s</string>
<string name="enable_fingerprint_hint">Το Keepass2Android ανίχνευσε βιομετρικό εξοπλισμό. Θέλετε να ενεργοποιήσετε βιομετρικό ξεκλείδωμα για αυτή τη βάση δεδομένων;</string>
<string name="post_notifications_dialog_title">Να επιτρέπονται οι ειδοποιήσεις</string>
<string name="post_notifications_dialog_message">Το Keepass2Android μπορεί να εμφανίσει ειδοποιήσεις με κουμπιά για να αντιγράψετε τιμές, όπως κωδικούς πρόσβασης και TOTP στο πρόχειρο, ή για να εμφανιστεί το ενσωματωμένο πληκτρολόγιο. Αυτό είναι χρήσιμο για να μεταφέρετε τιμές σε άλλες εφαρμογές, χωρίς να μεταβείτε σε Keepass2Android επανειλημμένα. Θέλετε να ενεργοποιήσετε αυτές τις ειδοποιήσεις;</string>
<string name="post_notifications_dialog_message">Το Keepass2Android μπορεί να εμφανίσει ειδοποιήσεις με κουμπιά για να αντιγράψετε τιμές, όπως συνθηματικά και TOTP στο πρόχειρο, ή για να εμφανιστεί το ενσωματωμένο πληκτρολόγιο. Αυτό είναι χρήσιμο για να μεταφέρετε τιμές σε άλλες εφαρμογές, χωρίς να μεταβείτε σε Keepass2Android επανειλημμένα. Θέλετε να ενεργοποιήσετε αυτές τις ειδοποιήσεις;</string>
<string name="post_notifications_dialog_allow">Να επιτρέπονται οι ειδοποιήσεις</string>
<string name="post_notifications_dialog_disable">Απενεργοποιήστε αυτό το χαρακτηριστικό</string>
<string name="post_notifications_dialog_notnow">Όχι τώρα</string>
@@ -909,4 +916,8 @@
<string name="kp2a_switch_on_sendgodone_summary">Εναλλαγή πίσω όταν πατήσετε αποστολή / λήψη / ολοκλήρωση</string>
<string name="qr_scanning_error_no_google_play_services">Η σάρωση QR κώδικα απαιτεί Google Play Services. Παρακαλώ εγκαταστήστε ή ενημερώστε τις Google Play Services στη συσκευή σας.</string>
<string name="english_ime_settings">Ρυθμίσεις πληκτρολογίου Android</string>
<string name="autoswitch_enabled_but_not_setup">Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Πρόσβαση στα συνθηματικά - Εναλλαγή πληκτρολογίου - Αυτόματη εναλλαγή πληκτρολογίου, αλλά φαίνεται ότι δεν έχει ρυθμιστεί σωστά.</string>
<string name="switch_keyboard_for_totp_enabled">Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Πρόσβαση στα συνθηματικά - Λειτουργία αυτόματης συμπλήρωσης - Αυτόματη συμπλήρωση για καταχωρίσεις TOTP. Αυτό μπορεί να προκαλέσει την εμφάνιση αυτού του παραθύρου όταν ανοίγετε μια καταχώριση με TOTP.</string>
<string name="switch_keyboard_inside_kp2a_enabled">Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Ασφάλεια - Χρήση του ενσωματωμένου στο Keepass2Android πληκτρολογίου. Αυτό μπορεί να προκαλέσει την εμφάνιση αυτού του παραθύρου όταν ανοίγετε την εφαρμογή ή επεξεργάζεστε μια καταχώριση.</string>
<string name="switch_keyboard_on_search_enabled">Σημείωση: Έχετε ενεργοποιήσει στις Ρυθμίσεις - Εφαρμογή - Πρόσβαση στα συνθηματικά - Εναλλαγή πληκτρολογίου - Εναλλαγή πληκτρολογίου. Αυτό μπορεί να προκαλέσει την εμφάνιση αυτού του παραθύρου κατά την αναζήτηση μιας καταχώρισης από το πρόγραμμα περιήγησης.</string>
</resources>

View File

@@ -719,6 +719,14 @@
<string name="EntryChannel_desc">Notificación para simplificar el acceso a la entrada seleccionada actualmente.</string>
<string name="CloseDbAfterFailedAttempts">Cierre la base de datos después de tres intentos fallidos de desbloqueo biométrico.</string>
<string name="WarnFingerprintInvalidated">¡Atención! La autenticación biométrica puede ser invalidada por Android, p. ej. después de añadir una nueva huella dactilar en los ajustes de su dispositivo. ¡Esté seguro de conocer siempre cómo desbloquear con su contraseña maestra!</string>
<string-array name="ChangeLog_1_12">
<item>Actualizado desde Xamarin Android a .net 8</item>
<item>Upgraded to Target SDK 34</item>
<item>Upgraded to Material 3 user interface</item>
<item>Improve autofill to work with Compose apps</item>
<item>Fix hostname matching in autofill and search</item>
<item>Fix issue with password generator</item>
</string-array>
<string-array name="ChangeLog_1_11">
<item>Añadidos botones de acción flotante para la búsqueda y vista general de TOTP (si las entradas TOTP están presentes).</item>
<item>Se ha mejorado la visualización de los campos TOTP añadiendo un indicador de tiempo de espera y mostrándolo de forma más destacada.</item>

View File

@@ -0,0 +1,22 @@
<resources>
<style name="Kp2aTheme_ActionBar" parent="AppTheme.Primary">
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="Kp2aTheme_BlueActionBar" parent="AppTheme.Secondary">
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="Kp2aTheme_NoActionBar" parent="AppTheme.Primary.NoActionBar">
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="Kp2aTheme_BlueNoActionBar" parent="AppTheme.Secondary.NoActionBar">
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>

View File

@@ -546,6 +546,7 @@
<string name="filestoragename_dropboxKP2A">Dropbox (folder KP2A)</string>
<string name="filestoragehelp_dropboxKP2A">Jeżeli nie chcesz dać KP2A pełnego dostępu do wszystkich folderów Dropbox, możesz wybrać tę opcję. Aplikacja zażąda dostępu jedynie do folderu Aplikacje/Keepass2Android. Jest to szczególnie przydatne podczas tworzenia nowej bazy danych. Jeżeli już posiadasz bazę danych, kliknij w tę opcję, aby utworzyć folder, następnie umieść swój plik w folderze (ze swojego PC) i wybierz tę opcję ponownie, aby otworzyć plik.</string>
<string name="filestoragename_gdrive">Google Drive</string>
<string name="filestoragehelp_gdrive">Uwaga: Google ogranicza dostęp do Dysku Google dla coraz większej liczby użytkowników. Jeśli wbudowana obsługa Dysku Google nie działa, skorzystaj z systemowego wybierania plików i wybierz Dysk Google stamtąd!</string>
<string name="filestoragename_gdriveKP2A">Dysk Google (pliki KP2A)</string>
<string name="filestoragehelp_gdriveKP2A">Jeśli nie chcesz dać KP2A dostępu do pełnego Dysku Google, możesz wybrać tę opcję. Pamiętaj, że najpierw musisz utworzyć plik bazy danych, istniejące pliki nie są widoczne dla aplikacji. Wybierz tę opcję z ekranu tworzenia bazy danych lub, jeśli już otworzyłeś bazę danych, eksportując bazę danych wybierając tę opcję.</string>
<string name="filestoragename_pcloud">PCloud (KP2A folder)</string>
@@ -718,16 +719,33 @@
<string name="EntryChannel_desc">Powiadomienie ułatwiające dostęp do aktualnie wybranego wpisu.</string>
<string name="CloseDbAfterFailedAttempts">Zamknij bazę danych po trzech nieudanych próbach odblokowania biometrycznego.</string>
<string name="WarnFingerprintInvalidated">Uwaga! Uwierzytelnienie biometryczne może zostać unieważnione przez Androida, np. po dodaniu nowego odcisku palca w ustawieniach urządzenia. Upewnij się, że zawsze wiesz, jak odblokować przy użyciu hasła głównego!</string>
<string-array name="ChangeLog_1_12">
<item>Zaktualizowano z Xamarin Android do .net 8</item>
<item>Zaktualizowano Target SDK do 34</item>
<item>Zaktualizowano interfejs użytkownika do Material Design 3</item>
<item>Ulepszono autouzupełnianie, aby działało z aplikacjami opartymi na Compose</item>
<item>Naprawiono dopasowywanie hostów w autouzupełnianiu i wyszukiwaniu</item>
<item>Naprawiono problem związany z generatorem haseł</item>
</string-array>
<string-array name="ChangeLog_1_12_net">
<item>Zaktualizowano SDK OneDrive do wersji 5.68</item>
<item>Zaktualizowano SDK DropBox do wersji 7.0.0</item>
<item>Zaktualizowano Gradle, NewtonsoftJson, FluentFTP, MegaApiClient i okhttp</item>
<item>Naprawiono błąd w wybieraniu plików WebDAV</item>
</string-array>
<string-array name="ChangeLog_1_11">
<item>Dodano pływające przyciski szukania i podglądu TOTP (jeśli są wpisy TOTP).</item>
<item>Poprawa wyświetlania pól TOTP na wyraźniejsze i ze wskaźnikiem czasu.</item>
<item>TOTP są widoczne teraz w widoku grupy.</item>
<item>Skopiuj tekst do schowka po długim naciśnięciu w widoku wpisu.</item>
<item>TOTP łatwiej dostępne we wbudowanej klawiaturze.</item>
<item>Show entry notification when autofilling a TOTP entry. This allows to copy the TOTP to clipboard. See preferences to configure the behavior.</item>
<item>Updated TOTP implementation to resolve compatibility issues with KeePass2 and TrayTOTP</item>
<item>Pokaż powiadomienie przy automatycznym wypełnianiu wpisu TOTP. Pozwala to na skopiowanie TOTP do schowka. W ustawieniach możesz skonfigurować to zachowanie.</item>
<item>Zaktualizowano implementację TOTP, aby rozwiązać problemy związane z kompatybilnością z KeePass2 i TrayTOTP</item>
<item>Małe poprawki</item>
</string-array>
<string-array name="ChangeLog_1_11_net">
<item>Zaktualizuj SDK pCloud, aby zapewnić dostęp do udostępnionych folderów</item>
</string-array>
<string-array name="ChangeLog_1_10">
<item>Dodaj wsparcie dla uprawnień do powiadomień na Androidzie 13+</item>
<item>Poprawia wdrażania FTP i SFTP</item>
@@ -809,7 +827,189 @@
* Nowa implementacja dla OneDrive: zawiera wsparcie dla OneDrive for Business, plików współdzielonych, wybranych zakresów dostępu, wielu kont i naprawia problemy z dostępem offline\n
* Poprawki błędów
</string>
<string name="ChangeLog_1_07"> Wersja 1.07\n
* Naprawiono błędy na urządzeniach Samsunga z Androidem 9\n
* Pozwól na otwarcie więcej niż jednej bazy danych, kompatybilnej z KeeAutoExec\n
* SFTP: Możliwość na uwierzytelnianie kluczem publicznym, sprawdzanie zmiany klucza hosta\n
* Wprowadzono wsparcie dla pCloud - dzięki gilbsgilbs!\n
* Jawne wsparcie dla Nextcloud\n
* Ulepszono zapisywanie i aktualizację załączników do wpisów\n
* Więcej opcji dostosowania zachowania do preferencji użytkownika\n
* SSL: Zaufanie certyfikatom użytkownika\n
* Ulepszono autouzupełnianie (działa teraz w FireFox, umożliwia zredukowanie popupów)\n
* Poprawki błędów\n
</string>
<string name="ChangeLog_1_06">Wersja 1.06\n
* Zmieniono aplikację do obsługi Yubikey Challenge-Response z YubiChallenge na ykDroid.\n
* Dodano wsparcie dla Challenge-Response w formacie KeepassXC. Uwaga: Baza danych musi być w formacie KDBX4!\n
* Dodano opcję odrzucania ładowania plików z kosza w Google Drive\n
* Zmieniono implementację TLS dla FTPS, dodano obejście do błędu JSch z serwerami obsługującymi gssapi-with-mic\n
* Poprawki błędów\n
</string>
<string name="ChangeLog_1_05">Wersja 1.05\n
* Użyj kanału powiadomień w Androidzie 8 do konfiguracji, poprzez ustawienia systemu\n
* Ikona wpisu jest pokazywana w powiadomieniu\n
* Użyto adaptacyjnej ikony aplikacji dla Androida 8, używaj okrągłej ikony dla Androida 7\n
* Możliwość aktywnego wyszukiwania po odblokowaniu (zobacz w ustawieniach)\n
* Zmieniono sposób w jaki pliki są zapisywane przez Storage Access Framework, rozwiązano problemy z aktualizowaniem plików na Dysku Google otwieranych przez systemowy menadżer plików\n
* Dodano kilka tekstów informacyjnych, aby uniknąć częstych nieporozumień\n
* Tworzone są lokalne kopie zapasowe pomyślnie otwartych baz danych, aby zmniejszyć ryzyko utraty danych\n
* Zaktualizowano JSch do obsługi nowszych szyfrów SSH\n
* Zezwolono na edycję ustawień połączeń, na przykład kiedy hasło do WebDav zostanie zmienione\n
* Dodano wsparcie dla Yubikey Neo w trybie hasła statycznego\n
* Dodano możliwość wyłączenia sugestii autouzupełniania\n
* Naprawiono wyciek danych do logcat\n
* Poprawki błędów\n
</string>
<string name="ChangeLog_1_04b"> Wersja 1.04b\n
* Naprawienie crasha, gdy użytkownik próbuje włączyć autouzupełnianie na urządzeniach Huawei.\n
</string>
<string name="ChangeLog_1_04">Wersja 1.0.4 \n
* Dodano serwis autouzupełniania dla Androida 8.0 i dalej. \n
* Zaktualizowano biblioteki, narzędzia budownicze oraz wersję Target SDK \n</string>
<string name="ChangeLog_1_03">Wersja 1.03\n
* Usunięto usługę dostępności autouzupełniania, zgodnie z żądaniem Google. Proszę zobaczyć ustawienia dostępu do hasła, gdzie można znaleźć plugin replikujący poprzednią funkcjonalność.\n
* Dodano ponownie aplikacje firm trzecich jako opcję przechowywania plików\n
* Zintegrowano przeglądarkę obrazów do przeglądania zdjęć bez przesyłania ich do innej aplikacji\n
* Uaktualnienie OkHttp rozwiązuje problemy z niektórymi połączeniami\n
* Wsparcie dla wpisów KeeTrayTOTP, teraz obsługuje wpisy Steam\n
</string>
<string name="ChangeLog_1_02">Wersja 1.02\n
* Kilka ulepszeń zabezpieczeń. Dzięki raportowi bezpieczeństwa jean-baptiste.cayrou@thalesgroup.com i vincent.fargues@thalesgroup.com oraz ich współpracy!\n
* Wsparcie dla KeyboardSwapPlugin (zobacz Opcje dostępu do hasła): pozwala przełączać metody wprowadzania automatycznie na urządzeniach bez root-a. Podziękowania dla Mishaal Rahman z XDA-Developers za uczynienie tego możliwym.\n
* Poprawki dl ausługi ułatwień dostępu w ostatnich wersjach Chrome\n
* Naprawiono niepotrzebne czyszczenie danych linii papilarnych\n
* Poprawki drobnych awarii\n
* Zaktualizowano SDK Dropbox do zapewnienia przyszłej kompatybilności\n
* Usunięto raportowanie błędów za pośrednictwem Xamarin Insights\n
* Aktualizacja narzędzi kompilacji\n
</string>
<string name="ChangeLog_1_01g">Wersja 1.01-g\n
* Naprawiono awarię podczas próby pracy offline\n
* Naprawiono nieprawidłowe kodowanie poświadczeń FTP(S)\n
* Naprawiono awarię podczas korzystania z usługi OneDrive na starszych wersjach Androida\n
* Wyświetlanie czasu jako czas lokalny na ekranie wpisu\n
</string>
<string name="ChangeLog_1_01d">Wersja 1.01-d\n
* Poprawiono wyświetlanie listy plików OneDrive\n
* Zezwolono na ignorowanie błędy certyfikatu również kiedy weryfikacji nazwy hosta się nie powiedzie (niezalecane w wersji komercyjnej)\n
* Poprawka do okazjonalnych problemów z szybkim odblokoweaniem pomimo prawidłowego kodu\n </string>
<string name="ChangeLog_0_9_8c">Wersja 0.9.8c\n
* Poprawka luki bezpieczeństwa protokołu SSL w Microsoft Live SDK (używany podczas uzyskiwania dostępu do plików za pośrednictwem OneDrive)\n
* Poprawka błędu: Poprzednia wersja zawierała dwie metody wprowadzania (jedną niedziałającą poprawnie)\n </string>
<string name="ChangeLog_1_01"> Wersja 1.01\n
* dodano wsparcie dla nowego formatu KDBX-4 (kompatybilne z Keepass 2.35) włącznie z generowaniem kluczy Argon2 i szyfrowaniem ChaCha20.\n
* Przepisano przechowywanie plików WebDav, umożliwiając przeglądanie plików z wsparciem nowoczesnego szyfrowania.\n
* Przepisano przechowywanie plików FTP,, umożliwiając przechowywanie plików i z wsparciem szyfrowania (FTPS).\n
* Zaktualizowano SDK OneDrive (poprzednio używane Live SDK nie jest już aktualizowane)\n
* Zaktualizowano SDK Dropbox do wersji 2 (poprzednio używana wersja 1 SDK jest oznaczona jako przestarzała).\n
* Dodano wsparcie dla OwnCloud.\n
* Dodano prośbę o pozwolenie na dostęp do pamięci przed otwieraniem lokalnych plików
</string>
<string name="ChangeLog_1_0_0e"> Wersja 1.0.0e\n
* Naprawiono odblokowywanie odciskiem palca na starszych urządzeniach Samsung z Androidem 6\n
* Dodane natywne wsparcie dla urządzeń x86\n
* Zezwolono na chowanie klawiaturę programowej podczas skanowania odcisku palca\n
* Aktualizacja systemu budowania
</string>
<string name="ChangeLog_1_0_0">Wersja 1.0.0\n
* Odblokowywanie odciskiem palca (Android 6.0+ lub urządzenie Samsung)\n
* Dodano usługę autouzupełniania (Android 5.0+)\n
* Dodano wsparcie dla szablonów wiadomości\n
* Dodano tryb \"pracy offline\"\n
* Umożliwiono kopiowanie wpisów\n
* Tryb autouzupełniania dla nazw pól\n
* Umożliwiono usuwanie wpisów na liście ostatnich plików\n
* Prośba o uprawnienia w trakcie działania aplikacji w Androidzie 6.0\n
* Poprawki błędów (we wbudowanej klawiaturze, podczas wybierania ikon)\n
* Dodano opcję wysyłania raportów o błędach\n
* Dodano wskazówki dotyczące obsługi w kilku miejscach\n
</string>
<string name="ChangeLog_0_9_9"> Wersja 0.9.9\n
* Kompletnie przeprojektowany interfejs użytkownika. Wielkie podziękowania dla Stefano Pignataro (http://www.spstudio.at) za jego pomoc!\n
* Umożliwiono dodawanie własnych ikon\n
* Wsparcie dla trybu Multi Window na urządzeniach Samsung\n
* Zwiększono domyślną liczbę rund szyfrowania dla nowych baz danych\n
* Sprawdzanie czy nie duplikatów kluczy w dodatkowych polach w celu uniknięcia utraty danych\n
</string>
<string name="ChangeLog_0_9_9c"> Wersja 0.9.9c\n
* Powrócił ciemny motyw\n
* Możesz zainstalować inne paczki ikon (ikony w klasycznym stylu Windowsa są dostępne w sklepie Play)\n
* Dodano pytanie o potwierdzenie podczas usuwania elementów z pominięciem kosza\n
* Poprawki błędów (złe wyświetlanie kodowania tajnego klucza OTP, niewłaściwa ikona aplikacji w niektórych miejscach)\n
</string>
<string name="ChangeLog_0_9_8b"> Wersja 0.9.8b\n
* Poprawki błędów (Zapisywanie nie udawało się dla niektórych baz danych, nie działało eksportowanie do lokalnego urządzenia, wybieranie niektórych opcji wysypywało aplikację)\n
</string>
<string name="ChangeLog_0_9_8"> Wersja 0.9.8\n
* Wsparcie dla Storage Access Framework (umożliwia zapis na kartę SD i Google Drive w KP2A Offline)\n
* Próba wykrywania błędnych danych wprowadzanych przez użytkownika podczas wpisywania WebDAV URLs (katalog zamiast pliku)\n
* Zmieniono czcionkę hasła\n
* Umożliwiono zmianę konta Dropbox\n
* Poprawka błędu: Teraz hasło OTP jest zapamiętywane\n</string>
<string name="ChangeLog_0_9_7b"> Wersja 0.9.7b\n
* Zaktualizowano tłumaczenia\n
* Poprawki błędów: brakowało czcionki do haseł w wersji 0.9.7, sortowanie po nazwie nie sortowało grup\n
</string>
<string name="ChangeLog_0_9_7"> Wersja 0.9.7\n
* Dodano wsparcie dla zapisu bazy danych (kdb) dla Keepass 1 (beta!)\n
* Lepsze przełączanie do poprzedniej klawiatury (działa także na nie-zrootowanych urządzeniach)\n
* Wsparcie dla KeeChallenge ze zmienną długością wyzwań\n
* Zabezpieczono przed możliwością zrobienia zrzutów ekranu dla ekranów QuickUnlock i hasła\n
* Odwrócono kolejność sortowania dla Sortuj według daty modyfikacji (teraz malejąco)\n
* Poprawki błędów: Widok notatek jest teraz poprawnie aktualizowany po zmianach. Widoki haseł teraz chowają hasła poprawnie na (miejmy nadzieję) wszystkich urządzeniach; naprawiono błąd, który powodował, że można było dwukrotnie dodać ten sam wpis; naprawiono problem z pokazywaniem ostrzeżenia o zduplikowanych UUID nawet po naprawieniu bazy danych\n
</string>
<string name="ChangeLog_0_9_3_r5"> <b>Wersja 0.9.3 r5</b>\n
* Zawarto poprawki z Xamarin: Keepass2Android jest teraz kompatybilny z ART na Androidzie 4.4.2. Nareszcie!\n
* Poprawki błędów: błędy w synchronizacji (odswieżanie widoku, poprawne sprawdzanie zmian na http), błędy na urządzeniach z Androidem 2.x, błędy w implementacji Google Drive i SkyDrive, czyszczenie schowka przy zamykaniu bazy danych, błąd otwierania załączników, problemy z wyświetlaniem klawiatury\n
</string>
<string name="ChangeLog_0_9_3"><b>Wersja 0.9.3</b>\n
* Nowa klawiatura z wieloma usprawnieniami. Sprawdź ustawienia, aby dostosować.\n
* Wsparcie tylko do odczytu dla kdb (pliki Keepass 1). Eksperymentalne!\n
* Dodano wsparcie protokołu SFTP\n
* Dodano obejście błędu w ART (Android 4.4.2)\n
* Poprawki błędów\n</string>
<string name="ChangeLog_0_9_2"><b>Wersja 0.9.2</b>\n
* Dodano obsługę haseł jednorazowych (kompatybilne z wtyczką OtpKeyProv)\n
* Zintegrowano wparcie NFC dla haseł jednorazowych z YubiKey NEO \n
* Kilka usprawnień interfejsu\n
* Zintegrowano bibliotekę Keepass 2.24\n
* Dodano opcję do zabijania procesu aplikacji (sprawdź ustawienia)\n
* Usprawniona weryfikacja certyfikatów SSL\n
* Poprawki błędów\n</string>
<string name="ChangeLog_0_9_1"><b>Wersja 0.9.1</b>\n
* Dodano integrację ze SkyDrive (Tylko zwyczajna edycja Keepass2Android)\n
* Poprawiono problemy z integracją z Google Drive\n
* Dodano wsparcie dla NTLM
</string>
<string name="ChangeLog_0_8_1"><b>Wersja 0.8.1</b>\n
* KP2A w trybie Offline i \"Online\" może być zainstalowany równocześnie\n
* Dodane nowe tłumaczenia (Dziękujemy wszystkim tłumaczom!)</string>
<string name="ChangeLog_0_8"><b>Wersja 0.8</b>\n
* Ulepszono interfejs użytkownika, szczególnie na urządzeniach z Androidem 4.x\n
* Możliwość używania innych menedżerów plików w celu wyboru plików\n
* Dodano bezpieczniejszy sposób otwierania załączników (z pamięci podręcznej)\n
* Naprawiono błędy podczas \"Edycji\"\n
* Prawdopodobnie wprowadzono nowe błędy :-)</string>
<string name="ChangeLog_keptDonate">Rozszerzone możliwości darowania piwa lub czegoś innego</string>
<string name="ChangeLog_0_7"> <b>Wersja 0.7</b> \n * Zwiększono szybkość ładowania: transformacje kluczy teraz 10 razy szybsze\n
* Dodano wirtualną klawiaturę Keepass2Android: przełącz się na nią podczas wprowadzania danych logowania. Chroni przed podsłuchiwaniem haseł z użyciem schowka (wyłącz stare powiadomienia o schowku w ustawieniach).
* Dodano opcję postawienia mi piwa lub czegoś innego (zobacz w menu)
</string>
<string name="ChangeLog"> <b>Wersja 0.6.2</b>\n
* Integracja Google Drive/Dropbox/(...): Otworzenie pliku .kdbx w Google Drive lub Dropbox uruchomi teraz KP2A.\n
* Poprawiono okno wyszukiwania \n
* Ulepszono wyniki wyszukiwania dla udostępnionych adresów URL z subdomenami\n
* Dodano opcje przesyłania opinii, oceniania i tłumaczenia aplikacji w menu\n
\n
<b>Wersja 0.6.1</b>\n
* Wykrywanie zmian w bazie danych w tle (np. spowodowanych działaniem aplikacji synchronizującej)\n
* Ulepszone wyszukiwanie adresów URL z przeglądarki\n
* Potwierdzenie przed porzuceniem zmian\n
\n
<b>Wersja 0.6</b>\n
Pierwsze publiczne wydanie
</string>
<string-array name="clipboard_timeout_options">
<item>30 sekund</item>
<item>1 minuta</item>
@@ -900,5 +1100,9 @@
<string name="AutofillWarning_Intro">Zamierzasz wstawić poświadczenia dla domeny \"%1$s\" do aplikacji \"%2$s\".</string>
<string name="AutofillWarning_FillDomainInUntrustedApp">Jeśli ufasz \"%2$s\" należącym do \"%1$s\" lub ufasz aplikacji \"%2$s\", aby nie używać danych logowania (np. ponieważ jest to zaufana aplikacja przeglądarki), jest w porządku, aby kontynuować. Jeśli nie, proszę anulować.</string>
<string name="AutofillWarning_trustAsBrowser">Akceptuj zawsze w \"%1$s\"</string>
<string name="kp2a_switch_on_sendgodone">Przełącz klawiaturę po zakończeniu</string>
<string name="kp2a_switch_on_sendgodone_summary">Przełącz po naciśnięciu wyślij/idź/wykonaj</string>
<string name="qr_scanning_error_no_google_play_services">Skanowanie kodów QR wymaga usług Google Play. Zainstaluj lub zaktualizuj usługi Google Play na swoim urządzeniu.</string>
<string name="english_ime_settings">Ustawienia klawiatury Keepass2Android</string>
<string name="switch_keyboard_inside_kp2a_enabled">Uwaga: Włączono w ustawieniach Aplikacja -> Bezpieczeństwo, opcję „Używaj wbudowanej klawiatury w Keepass2Android”. Może to powodować pojawianie się tego okna przy otwieraniu aplikacji lub edycji wpisu.</string>
</resources>

View File

@@ -93,6 +93,8 @@
<string name="disable_fingerprint_unlock">Desabilitar o Desbloqueio Biométrico </string>
<string name="enable_fingerprint_unlock">Habilitar o Desbloqueio de Biométrico completo</string>
<string name="enable_fingerprint_quickunlock">Habilitar o Desbloqueio de Biométrico para o QuickUnlock</string>
<string name="password_based_quick_unlock_not_available">Desbloqueio rápido baseado em senha não disponível</string>
<string name="password_based_quick_unlock_not_available_text">O desbloqueio rápido usando uma parte da sua senha está bloqueado porque o bloqueio da tela não está ativado no seu dispositivo. Esse comportamento é para protegê -lo caso alguém o veja entrando na sua chave de desbloqueio rápido.</string>
<string name="fingerprint_unlock_failed">Desbloqueio por impressão digital falhou: Chave para desencriptação foi invalidada pelo sistema Android. Isto costuma acontecer se for adicionada uma nova impressão digital ao sistema ou se os parâmetros de segurança forem alterados. </string>
<string name="fingerprint_disabled_wrong_masterkey">Desbloqueio da base de dados falhado: Chave composta inválida. O desbloqueio por impressão digital foi desativado porque aparentemente a chave mestra arquivada não é válida. </string>
<string name="fingerprint_reenable">Por favor, reative o Desbloquear com Impressão Digital para a nova senha mestre.</string>
@@ -321,6 +323,7 @@
<string name="QuickUnlock_label_secure">Digite o código QuickUnlock:</string>
<string name="QuickUnlock_button">Desbloqueio Rápido!</string>
<string name="QuickUnlock_lockButton">Fechar banco de dados</string>
<string name="enable_screen_lock">Ativar bloqueio de tela</string>
<string name="QuickUnlockDefaultEnabled_title">Habilitar Desbloqueio Rápido por padrão</string>
<string name="QuickUnlockDefaultEnabled_summary">Define se o Desbloqueio Rápido está habilitado por padrão ou não.</string>
<string name="ViewDatabaseSecure_title">Proteger a exibição da base de dados</string>
@@ -722,6 +725,11 @@
<string name="EntryChannel_desc">Notificação para simplificar o acesso à entrada selecionada.</string>
<string name="CloseDbAfterFailedAttempts">Fechar banco de dados após três tentativas de desbloqueio biométrico falhadas.</string>
<string name="WarnFingerprintInvalidated">Alerta! Autenticação biométrica pode ser invalidada pelo Android, por exemplo: depois de adicionar uma nova digital nas configurações do seu dispositivo. Esteja certo de sempre saber como desbloquear com sua senha mestra!</string>
<string-array name="ChangeLog_1_13">
<item>Estimativa aprimorada da qualidade da senha, considerando a maioria das senhas populares.</item>
<item>Bloqueia o desbloqueio rápido baseado em senha (por motivos de segurança) se o dispositivo não tiver uma trava de tela ativada.</item>
<item>Atualize a configuração de segurança de rede para desativar a transferência de texto não criptografado.</item>
</string-array>
<string-array name="ChangeLog_1_12">
<item>Atualizado de Xamarin Android para .NET 8</item>
<item>Atualizado para o Target SDK 34</item>

View File

@@ -0,0 +1,22 @@
<resources>
<style name="Kp2aTheme_ActionBar" parent="AppTheme.Primary">
<item name="android:windowLightStatusBar">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="Kp2aTheme_BlueActionBar" parent="AppTheme.Secondary">
<item name="android:windowLightStatusBar">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="Kp2aTheme_NoActionBar" parent="AppTheme.Primary.NoActionBar">
<item name="android:windowLightStatusBar">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="Kp2aTheme_BlueNoActionBar" parent="AppTheme.Secondary.NoActionBar">
<item name="android:windowLightStatusBar">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about_feedback">反馈</string>
<string name="AboutText">Keepass2Android 是一款支持 Keepass 2.x 数据库读写的密码管理应用。</string>
<string name="AboutText">Keepass2Android 是一款支持 Keepass 2.x 数据库读写的Android平台的密码管理应用。</string>
<string name="CreditsText">用户界面基于 Brian Pellin 开发的 KeepassDroid 项目。数据库操作代码基于 Dominik Reichl 开发的 KeePass 项目。Android 机器人图案根据 Google 创建和共享的作品进行复制或修改,并依照知识共享署名 3.0 协议进行使用。</string>
<string name="CreditsTextSFTP">SFTP 支持由 JCraft, Inc. 创建的 JSch 库(基于 BSD 许可证)实现</string>
<string name="CreditsIcons">锤子图标是由 John Caserta 通过 Noun Project 创建的。企鹅图标是由 Adriano Emerick 通过 Noun Project 创建的。羽毛图标是由 Jon Testa 通过 Noun Project 创建的。苹果图标是由 Ava Rowell 通过 Noun Project 创建的。图片图标来自 https://icons8.com/icon/5570/Picture 。</string>
@@ -725,9 +725,15 @@
<item></item>
<item>Upgraded to Material 3 user interface</item>
<item>Improve autofill to work with Compose apps</item>
<item>Fix hostname matching in autofill and search</item>
<item>修复在自动填充和搜索时主机名的匹配问题</item>
<item>Fix issue with password generator</item>
</string-array>
<string-array name="ChangeLog_1_12_net">
<item>Upgraded OneDrive SDK to version 5.68</item>
<item>Upgraded Dropbox SDK to version 7.0.0</item>
<item>Upgraded Gradle, NewtonsoftJson, FluentFTP, MegaApiClient and okhttp</item>
<item>修复WebDav中文件选择的错误</item>
</string-array>
<string-array name="ChangeLog_1_11">
<item>添加了用于搜索和概览 TOTP 的浮动按钮如果存在TOTP条目</item>
<item>通过添加超时指示器并突出显示,改进 TOTP 字段的显示效果</item>

View File

@@ -209,6 +209,7 @@
<string name="ShowUnlockedNotification_key">ShowUnlockedNotification</string>
<bool name="ShowUnlockedNotification_default">true</bool>
<integer name="WebDavChunkedUploadSize_default">65536</integer>
<string name="PreloadDatabaseEnabled_key">PreloadDatabaseEnabled</string>
<bool name="PreloadDatabaseEnabled_default">true</bool>

View File

@@ -4,7 +4,7 @@
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="detail_backdrop_height">200dp</dimen>
<dimen name="detail_backdrop_height">250dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="splash_logo_width">79dp</dimen>

View File

@@ -507,7 +507,12 @@
<string name="ok_donate">Tell me more!</string>
<string name="no_thanks">No, I don\'t like it that much</string>
<string name="enter_http_login_title">Enter WebDav login data:</string>
<string name="enter_smb_login_title">Enter Samba login data:</string>
<string name="hint_http_url">URL of folder or file (ex: mycloud.me.com/webdav/)</string>
<string name="hint_smb_url">URL of folder or file (ex: 192.168.1.10/share/folder/)</string>
<string name="hint_smb_domain">Samba user\'s domain</string>
<string name="hint_smb_username">Samba username</string>
<string name="enter_owncloud_login_title">Enter OwnCloud login data:</string>
<string name="hint_owncloud_url">OwnCloud URL (ex: owncloud.me.com)</string>
<string name="enter_nextcloud_login_title">Enter Nextcloud login data:</string>
@@ -545,6 +550,7 @@
<string name="filestoragename_ftp">FTP</string>
<string name="filestoragename_http">HTTP (WebDav)</string>
<string name="filestoragename_https">HTTPS (WebDav)</string>
<string name="filestoragename_smb">Samba (Windows Share)</string>
<string name="filestoragename_owncloud">OwnCloud</string>
<string name="filestoragename_nextcloud">Nextcloud</string>
<string name="filestoragename_dropbox">Dropbox</string>
@@ -728,7 +734,24 @@
<string name="EntryChannel_name">Entry notifications</string>
<string name="EntryChannel_desc">Notification to simplify access to the currently selected entry.</string>
<string name="CloseDbAfterFailedAttempts">Close database after three failed biometric unlock attempts.</string>
<string name="hint_smb_credentials">If you want to access files from your personal Windows computer, use the computer name or local IP address as host URL; enter the computer name as domain and the Windows login (often the same as your Microsoft account) as username and password.</string>
<string name="WarnFingerprintInvalidated">Warning! Biometric authentication can be invalidated by Android, e.g. after adding a new fingerprint in your device settings. Make sure you always know how to unlock with your master password!</string>
<string name="webdav_chunked_upload_size_title">Chunk size for WebDav upload</string>
<string name="webdav_chunked_upload_size_summary">Size of chunks when uploading to WebDav servers in bytes. Use 0 to disable chunked upload.</string>
<string-array name="ChangeLog_1_14_net">
<item>WebDav improvements: Bug fix for listing folders; support for chunked uploads and transactions</item>
<item>Added support for Samba/Windows network shares</item>
<item>Updated FluentFTP and enabled support for GnuTLS stream, supporting TLS 1.3 and solving other FTPS issues</item>
</string-array>
<string-array name="ChangeLog_1_13">
<item>Improved password quality estimation by considering most popular passwords.</item>
<item>Block password-based QuickUnlock (for security reasons) if the device does not have a screen lock activated.</item>
<item>Update network security configuration to disable clear-text transfer.</item>
</string-array>
<string-array name="ChangeLog_1_12">
<item>Upgraded from Xamarin Android to .net 8</item>

View File

@@ -253,12 +253,12 @@
<item name="android:statusBarColor">@color/statusbar_color_green</item></style>
<style name="Kp2aTheme_BlueActionBar" parent="AppTheme.Secondary"></style>
<style name="Kp2aTheme_NoActionBar" parent="AppTheme.Primary.NoActionBar">
<style name="Kp2aTheme_NoActionBar" parent="AppTheme.Primary.NoActionBar">
<item name="android:statusBarColor">@color/statusbar_color_green</item>
</style>
<style name="Kp2aTheme_BlueNoActionBar" parent="AppTheme.Secondary.NoActionBar">
</style>
</style>
<style name="Widget.Kp2a.Toolbar" parent="Widget.Material3.Toolbar.OnSurface" />

View File

@@ -45,6 +45,14 @@
android:title="@string/UseFileTransactions_title"
android:key="@string/UseFileTransactions_key" />
<EditTextPreference
android:key="WebDavChunkedUploadSize_str"
android:title="@string/webdav_chunked_upload_size_title"
android:summary="@string/webdav_chunked_upload_size_title"
android:defaultValue="@integer/WebDavChunkedUploadSize_default"
android:inputType="number"
/>
<CheckBoxPreference
android:enabled="true"
android:persistent="true"
@@ -80,5 +88,6 @@
android:defaultValue="true"
android:title="@string/CheckForDuplicateUuids_title"
android:key="@string/CheckForDuplicateUuids_key" />
</PreferenceScreen>

View File

@@ -35,7 +35,9 @@ using Android.Graphics.Drawables;
using Android.Hardware.Display;
using Android.Util;
using Android.Views.InputMethods;
using AndroidX.Core.View;
using AndroidX.Core.View.InputMethod;
using AndroidX.ViewPager2.Widget;
using Google.Android.Material.Dialog;
using KeePass.Util;
using keepass2android;
@@ -738,7 +740,73 @@ namespace keepass2android
public class InsetListener: Java.Lang.Object, IOnApplyWindowInsetsListener
{
private View _targetView;
private readonly int _insetsType;
private int _initialPaddingLeft;
private int _initialPaddingTop;
private int _initialPaddingRight;
private int _initialPaddingBottom;
public bool EnabledPaddingLeft { get; set; } = true;
public bool EnablePaddingTop { get; set; } = true;
public bool EnablePaddingRight { get; set; } = true;
public bool EnablePaddingBottom { get; set; } = true;
public InsetListener(View targetView, int insetsType)
{
_targetView = targetView;
_insetsType = insetsType;
_initialPaddingLeft = targetView.PaddingLeft;
_initialPaddingTop = targetView.PaddingTop;
_initialPaddingRight = targetView.PaddingRight;
_initialPaddingBottom = targetView.PaddingBottom;
}
public InsetListener(View targetView): this(targetView, WindowInsetsCompat.Type.SystemBars())
{
}
public WindowInsetsCompat OnApplyWindowInsets(View v, WindowInsetsCompat insets)
{
var systemBarsInsets = insets.GetInsets(_insetsType);
_targetView.SetPadding(
_initialPaddingLeft + (EnabledPaddingLeft ? systemBarsInsets.Left : 0),
_initialPaddingTop + (EnablePaddingTop ? systemBarsInsets.Top : 0),
_initialPaddingRight + (EnablePaddingRight ? systemBarsInsets.Right : 0),
_initialPaddingBottom + (EnablePaddingBottom ? systemBarsInsets.Bottom : 0)
);
return insets;
}
public static InsetListener ForBottomElement(View view)
{
return new InsetListener(view, WindowInsetsCompat.Type.Ime() | WindowInsetsCompat.Type.SystemBars() | WindowInsetsCompat.Type.DisplayCutout())
{
EnablePaddingTop = false
};
}
public static InsetListener ForTopElement(View view)
{
return new InsetListener(view, WindowInsetsCompat.Type.SystemBars() | WindowInsetsCompat.Type.DisplayCutout())
{
EnablePaddingBottom = false
};
}
public void Apply()
{
ViewCompat.SetOnApplyWindowInsetsListener(_targetView, this);
}
}
public static void MoveBottomBarButtons(int btn1Id, int btn2Id, int bottomBarId, Activity context)
{

View File

@@ -46,9 +46,11 @@ using keepass2android;
using keepass2android.Utils;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
using Message = keepass2android.Utils.Message;
#if !NoNet
#if !EXCLUDE_JAVAFILESTORAGE
using Kp2aBusinessLogic.Io;
using Android.Gms.Common;
using Keepass2android.Javafilestorage;
using GoogleDriveFileStorage = keepass2android.Io.GoogleDriveFileStorage;
@@ -836,8 +838,8 @@ namespace keepass2android
new AndroidContentStorage(LocaleManager.LocalizedAppContext),
#if !EXCLUDE_JAVAFILESTORAGE
#if !NoNet
new DropboxFileStorage(LocaleManager.LocalizedAppContext, this),
new DropboxAppFolderFileStorage(LocaleManager.LocalizedAppContext, this),
DropboxFileStorage.IsConfigured ? new DropboxFileStorage(LocaleManager.LocalizedAppContext, this) : null,
DropboxAppFolderFileStorage.IsConfigured ? new DropboxAppFolderFileStorage(LocaleManager.LocalizedAppContext, this): null,
GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(LocaleManager.LocalizedAppContext)==ConnectionResult.Success ? new GoogleDriveFileStorage(LocaleManager.LocalizedAppContext, this) : null,
GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(LocaleManager.LocalizedAppContext)==ConnectionResult.Success ? new GoogleDriveAppDataFileStorage(LocaleManager.LocalizedAppContext, this) : null,
new OneDriveFileStorage(this),
@@ -846,8 +848,9 @@ namespace keepass2android
new OneDrive2AppFolderFileStorage(),
new SftpFileStorage(LocaleManager.LocalizedAppContext, this, IsFtpDebugEnabled()),
new NetFtpFileStorage(LocaleManager.LocalizedAppContext, this, IsFtpDebugEnabled),
new WebDavFileStorage(this),
new PCloudFileStorage(LocaleManager.LocalizedAppContext, this),
new WebDavFileStorage(this, WebDavChunkedUploadSize),
new SmbFileStorage(),
new PCloudFileStorage(LocaleManager.LocalizedAppContext, this),
new PCloudFileStorageAll(LocaleManager.LocalizedAppContext, this),
new MegaFileStorage(App.Context),
//new LegacyWebDavStorage(this),
@@ -1333,6 +1336,18 @@ namespace keepass2android
}
}
public int WebDavChunkedUploadSize
{
get
{
return int.Parse(PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext)
.GetString("WebDavChunkedUploadSize_str",
LocaleManager.LocalizedAppContext.Resources
.GetInteger(Resource.Integer.WebDavChunkedUploadSize_default).ToString()));
}
}
}
@@ -1458,8 +1473,7 @@ namespace keepass2android
{
Kp2aLog.LogUnexpectedError(e.Exception);
}
}
}
}

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<TargetFramework>net9.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<RootNamespace>keepass2android</RootNamespace>
<OutputType>Exe</OutputType>

View File

@@ -1217,7 +1217,7 @@ namespace keepass2android
{
_design.ApplyTheme();
base.OnCreate(savedInstanceState);
new Util.InsetListener(FindViewById(Resource.Id.settings)).Apply();
}

View File

@@ -163,6 +163,7 @@ namespace keepass2android
{
_design.ApplyTheme();
base.OnCreate(savedInstanceState);
new Util.InsetListener(FindViewById(Resource.Id.settings)).Apply();
}