Compare commits

...

7 Commits

Author SHA1 Message Date
Philipp Crocoll
a00267a0ac Manifest for 1.14-pre3 2025-08-19 18:04:45 +02:00
Philipp Crocoll
7fccb6cb16 Merge branch 'master' of https://github.com/PhilippC/keepass2android 2025-08-19 18:04:01 +02:00
PhilippC
319f5d3113 Merge pull request #2983 from PhilippC/2893-bug-onedrive-sync-integration-no-longer-working-after-112-r5
attempt to fix app folder issue by creating it by an upload
2025-08-19 18:01:18 +02:00
Philipp Crocoll
b7276d1364 remove no-longer-sensible comment 2025-08-19 18:00:38 +02:00
Philipp Crocoll
58429ce0c4 attempt to fix app folder issue by creating it by an upload 2025-08-19 17:40:22 +02:00
Philipp Crocoll
72a72975e0 stability improvements 2025-08-19 12:25:38 +02:00
Philipp Crocoll
57be7af031 extend changelog for 1.14 2025-08-19 12:19:06 +02:00
8 changed files with 151 additions and 25 deletions

View File

@@ -1125,9 +1125,57 @@ namespace keepass2android.Io
}
}
public static async Task<DriveItem> GetOrCreateAppRootAsync(GraphServiceClient client, string dummyFileName = "welcome_at_kp2a.txt")
{
private async Task<List<FileDescription>> ListShares(OneDrive2ItemLocation<OneDrive2PrefixContainerType> parentPath, GraphServiceClient client)
try
{
return await client.RequestAdapter.SendAsync(
new Microsoft.Graph.Drives.Item.Items.Item.DriveItemItemRequestBuilder(
new Dictionary<string, object> {
{ "drive%2Did", "me" },
{ "driveItem%2Did", "special/approot" }
},
client.RequestAdapter
).ToGetRequestInformation(),
static (p) => DriveItem.CreateFromDiscriminatorValue(p)
);
}
catch (Microsoft.Kiota.Abstractions.ApiException ex) when (ex.ResponseStatusCode == 404)
{
// App folder doesnt exist yet → create it by uploading a dummy file
using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("init"));
var uploadRequest = new RequestInformation
{
HttpMethod = Method.PUT,
UrlTemplate = "{+baseurl}/me/drive/special/approot:/{filename}:/content",
PathParameters = new Dictionary<string, object>
{
{ "baseurl", client.RequestAdapter.BaseUrl },
{ "filename", dummyFileName }
},
Content = stream
};
var uploadedItem = await client.RequestAdapter.SendAsync<DriveItem>(
uploadRequest,
DriveItem.CreateFromDiscriminatorValue
);
var parentId = uploadedItem.ParentReference.Id;
var parentItemRequest = new DriveItemRequestBuilder(
$"{client.RequestAdapter.BaseUrl}/me/drive/items/{parentId}",
client.RequestAdapter
);
return await parentItemRequest.GetAsync();
}
}
protected virtual async Task<List<FileDescription>> ListShares(OneDrive2ItemLocation<OneDrive2PrefixContainerType> parentPath, GraphServiceClient client)
{
List<FileDescription> result = [];
@@ -1345,6 +1393,8 @@ namespace keepass2android.Io
}
}
protected override async Task<string?> GetSpecialFolder(
OneDrive2ItemLocation<OneDrive2AppFolderPrefixContainer> itemLocation, GraphServiceClient client)
@@ -1363,7 +1413,7 @@ namespace keepass2android.Io
Console.WriteLine(e);
throw;
}
}
return _specialFolderIdByDriveId[itemLocation.DriveId];
@@ -1378,8 +1428,55 @@ namespace keepass2android.Io
{
return drive.Name ?? MyOneDriveDisplayName;
}
public static async Task GetOrCreateAppRootAsync(GraphServiceClient client, string dummyFileName = "welcome_at_kp2a_app_folder.txt")
{
try
{
await client.RequestAdapter.SendAsync(
new Microsoft.Graph.Drives.Item.Items.Item.DriveItemItemRequestBuilder(
new Dictionary<string, object> {
{ "drive%2Did", "me" },
{ "driveItem%2Did", "special/approot" }
},
client.RequestAdapter
).ToGetRequestInformation(),
static (p) => DriveItem.CreateFromDiscriminatorValue(p)
);
//if this is successful, approot seems to exist
}
catch (Microsoft.Kiota.Abstractions.ApiException ex) when (ex.ResponseStatusCode == 404)
{
// App folder doesnt exist yet → create it by uploading a dummy file
using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("init"));
var uploadRequest = new RequestInformation
{
HttpMethod = Method.PUT,
UrlTemplate = "{+baseurl}/me/drive/special/approot:/{filename}:/content",
PathParameters = new Dictionary<string, object>
{
{ "baseurl", client.RequestAdapter.BaseUrl },
{ "filename", dummyFileName }
},
Content = stream
};
await client.RequestAdapter.SendAsync<DriveItem>(
uploadRequest,
DriveItem.CreateFromDiscriminatorValue
);
}
}
protected override async Task<List<FileDescription>> ListShares(OneDrive2ItemLocation<OneDrive2AppFolderPrefixContainer> parentPath, GraphServiceClient client)
{
await GetOrCreateAppRootAsync(client);
return await base.ListShares(parentPath, client);
}
public override bool CanListShares { get { return false; } }
protected override string MyOneDriveDisplayName => "Keepass2Android App Folder";
}

View File

@@ -12,20 +12,21 @@ namespace KeePass.Util
public static string GetErrorMessage(Exception e)
{
string errorMessage = e.Message;
if (e is Java.Lang.Exception javaException)
try
{
try
string errorMessage = e.Message;
if (e is Java.Lang.Exception javaException)
{
errorMessage = javaException.LocalizedMessage ?? javaException.Message ?? errorMessage;
}
finally
{
}
return errorMessage;
}
catch
{
return "";
}
return errorMessage;
}
}

View File

@@ -31,9 +31,15 @@ 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_14,
#if !NoNet
Resource.Array.ChangeLog_1_14_net
#endif
}, "1.14"),
BuildChangelogString(ctx, new List<int>{Resource.Array.ChangeLog_1_13}, "1.13"),

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="225"
android:versionName="1.14-pre2"
android:versionCode="236"
android:versionName="1.14-pre3"
package="keepass2android.keepass2android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto">

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="225"
android:versionName="1.14-pre2"
android:versionCode="236"
android:versionName="1.14-pre3"
package="keepass2android.keepass2android_nonet"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto">

View File

@@ -741,6 +741,11 @@
<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">
<item>Update to .net 9 and Target SDK version 35. This comes with transparent status bar on Android 15 because edge-to-edge is now the default.</item>
<item>Minor UI improvements</item>
</string-array>
<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>

View File

@@ -131,7 +131,15 @@ namespace keepass2android.view
ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Visible;
ev.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;
_db = App.Kp2a.FindDatabaseForElement(_entry);
_db = App.Kp2a.TryFindDatabaseForElement(_entry);
if (_db == null)
{
ev.FindViewById(Resource.Id.icon).Visibility = ViewStates.Gone;
_textView.TextFormatted = new SpannableString("(no data)");
_textviewDetails.Visibility = ViewStates.Gone;
_textgroupFullPath.Visibility = ViewStates.Gone;
return;
}
ImageView iv = (ImageView)ev.FindViewById(Resource.Id.icon);
bool isExpired = pw.Expires && pw.ExpiryTime < DateTime.Now;
@@ -209,11 +217,6 @@ namespace keepass2android.view
UpdateTotp();
}
public void ConvertView(PwEntry pw, int pos)

View File

@@ -15,14 +15,15 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Widget;
using keepass2android;
using KeePassLib;
using System;
using Object = Java.Lang.Object;
namespace keepass2android.view
@@ -64,7 +65,20 @@ namespace keepass2android.view
_label = (TextView) gv.FindViewById(Resource.Id.group_label);
_label.TextSize = size-8;
Database db = App.Kp2a.FindDatabaseForElement(pw);
Database db = App.Kp2a.TryFindDatabaseForElement(pw);
if (db == null)
{
gv.FindViewById(Resource.Id.group_icon_bkg).Visibility = ViewStates.Gone;
gv.FindViewById(Resource.Id.icon).Visibility = ViewStates.Gone;
gv.FindViewById(Resource.Id.check_mark).Visibility = ViewStates.Invisible;
_textview.Text = "(no data)";
_label.Text = "";
return;
}
gv.FindViewById(Resource.Id.group_icon_bkg).Visibility = db.DrawableFactory.IsWhiteIconSet ? ViewStates.Visible : ViewStates.Gone;