mirror of
https://github.com/awatertrevi/xamarin-neo4j.git
synced 2026-09-22 09:05:29 +00:00
Android: toolbar colors, action mode, popup menu text fix
- Set colorPrimary/colorPrimaryDark/colorAccent to dark app colors (#31333b) - Fix contextual action bar (CAB) background to match nav bar color - Fix overflow button (3-dot) tint to white via OverflowMenuButton style - Fix white-on-white popup menu text: remove global android:textColorPrimary override; scope white text only to CAB via ActionModeStyle/ActionModeTitleText - Add android:windowLightStatusBar=false so status bar icons are white on dark bg Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,9 +15,11 @@ Global
|
|||||||
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
||||||
AppStore|iPhone = AppStore|iPhone
|
AppStore|iPhone = AppStore|iPhone
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|Android = Debug|Android
|
||||||
Debug|iPhone = Debug|iPhone
|
Debug|iPhone = Debug|iPhone
|
||||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|Android = Release|Android
|
||||||
Release|iPhone = Release|iPhone
|
Release|iPhone = Release|iPhone
|
||||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
@@ -47,6 +49,9 @@ Global
|
|||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Android.ActiveCfg = Debug|Any CPU
|
||||||
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Android.Build.0 = Debug|Any CPU
|
||||||
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|Android.Deploy.0 = Debug|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|iPhone.Build.0 = Debug|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
||||||
@@ -56,6 +61,9 @@ Global
|
|||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Any CPU.Build.0 = Release|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Android.ActiveCfg = Release|Any CPU
|
||||||
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Android.Build.0 = Release|Any CPU
|
||||||
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|Android.Deploy.0 = Release|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|iPhone.ActiveCfg = Release|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|iPhone.Build.0 = Release|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|iPhone.Deploy.0 = Release|Any CPU
|
{24C5C58E-C59D-4621-9BF0-2E3BAC547455}.Release|iPhone.Deploy.0 = Release|Any CPU
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
//
|
||||||
|
// QueryEditorHandler.cs
|
||||||
|
//
|
||||||
|
// © Xamarin.Neo4j.Android
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
|
using Android.Text;
|
||||||
|
using Android.Text.Style;
|
||||||
|
using Android.Views;
|
||||||
|
using Android.Views.InputMethods;
|
||||||
|
using Android.Widget;
|
||||||
|
using Microsoft.Maui.Handlers;
|
||||||
|
using Microsoft.Maui.Platform;
|
||||||
|
using Xamarin.Neo4j.Controls;
|
||||||
|
|
||||||
|
namespace Xamarin.Neo4j.Android.CustomRenderers
|
||||||
|
{
|
||||||
|
public class QueryEditorHandler : EditorHandler
|
||||||
|
{
|
||||||
|
private readonly string[] _keyWords =
|
||||||
|
[
|
||||||
|
// Clauses
|
||||||
|
"CALL", "CREATE", "DELETE", "DETACH", "FOREACH", "LOAD", "MATCH", "MERGE", "OPTIONAL", "REMOVE", "RETURN", "SET", "START", "UNION", "UNWIND", "WITH",
|
||||||
|
|
||||||
|
// Subclauses
|
||||||
|
"LIMIT", "ORDER", "SKIP", "WHERE", "YIELD",
|
||||||
|
|
||||||
|
// Modifiers
|
||||||
|
"ASC", "ASCENDING", "ASSERT", "BY", "CSV", "DESC", "DESCENDING", "ON",
|
||||||
|
|
||||||
|
// Expressions
|
||||||
|
"ALL", "CASE", "COUNT", "ELSE", "END", "EXISTS", "THEN", "WHEN",
|
||||||
|
|
||||||
|
// Operators
|
||||||
|
"AND", "AS", "CONTAINS", "DISTINCT", "ENDS", "IN", "IS", "NOT", "OR", "STARTS", "XOR",
|
||||||
|
|
||||||
|
// Schema
|
||||||
|
"CONSTRAINT", "CREATE", "DROP", "EXISTS", "INDEX", "NODE", "KEY", "UNIQUE",
|
||||||
|
|
||||||
|
// Hints
|
||||||
|
"INDEX", "JOIN", "SCAN", "USING",
|
||||||
|
|
||||||
|
// Literals
|
||||||
|
"FALSE", "NULL", "TRUE"
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override void ConnectHandler(MauiAppCompatEditText platformView)
|
||||||
|
{
|
||||||
|
base.ConnectHandler(platformView);
|
||||||
|
|
||||||
|
// Disable autocorrect, autocapitalize, and spellcheck
|
||||||
|
platformView.InputType = InputTypes.ClassText
|
||||||
|
| InputTypes.TextFlagMultiLine
|
||||||
|
| InputTypes.TextFlagNoSuggestions;
|
||||||
|
|
||||||
|
// Keyboard toolbar with symbol keys and Execute button
|
||||||
|
var toolbar = BuildToolbar(platformView);
|
||||||
|
platformView.FocusChange += (s, e) =>
|
||||||
|
toolbar.Visibility = e.HasFocus ? ViewStates.Visible : ViewStates.Gone;
|
||||||
|
|
||||||
|
// Syntax highlighting
|
||||||
|
platformView.AddTextChangedListener(new CypherTextWatcher(platformView, _keyWords));
|
||||||
|
HighlightSyntax(platformView, _keyWords);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinearLayout BuildToolbar(MauiAppCompatEditText platformView)
|
||||||
|
{
|
||||||
|
var context = platformView.Context;
|
||||||
|
|
||||||
|
var toolbar = new LinearLayout(context)
|
||||||
|
{
|
||||||
|
Orientation = Orientation.Horizontal,
|
||||||
|
LayoutParameters = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MatchParent,
|
||||||
|
ViewGroup.LayoutParams.WrapContent)
|
||||||
|
};
|
||||||
|
toolbar.SetBackgroundColor(Color.ParseColor("#F2F2F7"));
|
||||||
|
toolbar.SetPadding(8, 8, 8, 8);
|
||||||
|
toolbar.Visibility = ViewStates.Gone;
|
||||||
|
|
||||||
|
// Scrollable symbol key strip
|
||||||
|
var scrollView = new HorizontalScrollView(context)
|
||||||
|
{
|
||||||
|
LayoutParameters = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WrapContent, 1f)
|
||||||
|
};
|
||||||
|
scrollView.HorizontalScrollBarEnabled = false;
|
||||||
|
|
||||||
|
var keyRow = new LinearLayout(context) { Orientation = Orientation.Horizontal };
|
||||||
|
foreach (var key in new[] { "(", ")", "[", "]", ":", "-", "->", "<-" })
|
||||||
|
{
|
||||||
|
var captured = key;
|
||||||
|
var btn = CreatePillButton(context, captured);
|
||||||
|
btn.Click += (s, e) =>
|
||||||
|
{
|
||||||
|
var start = Math.Max(platformView.SelectionStart, 0);
|
||||||
|
var end = Math.Max(platformView.SelectionEnd, 0);
|
||||||
|
platformView.EditableText?.Replace(Math.Min(start, end), Math.Max(start, end), captured);
|
||||||
|
};
|
||||||
|
keyRow.AddView(btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollView.AddView(keyRow);
|
||||||
|
toolbar.AddView(scrollView);
|
||||||
|
|
||||||
|
// Execute button
|
||||||
|
var executeBtn = CreatePillButton(context, "Execute");
|
||||||
|
executeBtn.SetTextColor(Color.White);
|
||||||
|
executeBtn.SetBackgroundColor(Color.ParseColor("#007AFF"));
|
||||||
|
executeBtn.Click += (s, e) =>
|
||||||
|
{
|
||||||
|
if (VirtualView is QueryEditor queryEditor)
|
||||||
|
{
|
||||||
|
queryEditor.RaiseExecuteClicked();
|
||||||
|
var imm = (InputMethodManager)context.GetSystemService(Context.InputMethodService);
|
||||||
|
imm?.HideSoftInputFromWindow(platformView.WindowToken, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
toolbar.AddView(executeBtn);
|
||||||
|
|
||||||
|
// Attach toolbar to the parent view hierarchy
|
||||||
|
platformView.ViewTreeObserver.GlobalLayout += (s, e) =>
|
||||||
|
{
|
||||||
|
if (platformView.Parent is ViewGroup parent && toolbar.Parent == null)
|
||||||
|
parent.AddView(toolbar);
|
||||||
|
};
|
||||||
|
|
||||||
|
return toolbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Button CreatePillButton(Context context, string label)
|
||||||
|
{
|
||||||
|
return new Button(context)
|
||||||
|
{
|
||||||
|
Text = label,
|
||||||
|
LayoutParameters = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WrapContent,
|
||||||
|
ViewGroup.LayoutParams.WrapContent)
|
||||||
|
{
|
||||||
|
MarginStart = 4,
|
||||||
|
MarginEnd = 4
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Syntax highlighting ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
internal static void HighlightSyntax(MauiAppCompatEditText platformView, IEnumerable<string> keywords)
|
||||||
|
{
|
||||||
|
var text = PreprocessText(platformView.Text ?? string.Empty);
|
||||||
|
var spannable = new SpannableStringBuilder(text);
|
||||||
|
|
||||||
|
var keywordColor = Color.ParseColor("#899832");
|
||||||
|
var literalColor = Color.ParseColor("#AE8B2D");
|
||||||
|
|
||||||
|
foreach (var word in keywords)
|
||||||
|
{
|
||||||
|
var regex = new Regex("\\b" + Regex.Escape(word) + "\\b", RegexOptions.IgnoreCase);
|
||||||
|
foreach (Match match in regex.Matches(text))
|
||||||
|
spannable.SetSpan(new ForegroundColorSpan(keywordColor),
|
||||||
|
match.Index, match.Index + match.Length,
|
||||||
|
SpanTypes.ExclusiveExclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplyQuoteHighlight(text, spannable, "'(.*?)'", literalColor);
|
||||||
|
ApplyQuoteHighlight(text, spannable, "\"(.*?)\"", literalColor);
|
||||||
|
|
||||||
|
var selStart = platformView.SelectionStart;
|
||||||
|
var selEnd = platformView.SelectionEnd;
|
||||||
|
platformView.SetText(spannable, TextView.BufferType.Spannable);
|
||||||
|
if (selStart >= 0 && selEnd <= spannable.Length())
|
||||||
|
platformView.SetSelection(selStart, selEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyQuoteHighlight(string text, SpannableStringBuilder spannable,
|
||||||
|
string pattern, Color color)
|
||||||
|
{
|
||||||
|
foreach (Match match in new Regex(pattern).Matches(text))
|
||||||
|
spannable.SetSpan(new ForegroundColorSpan(color),
|
||||||
|
match.Index, match.Index + match.Length,
|
||||||
|
SpanTypes.ExclusiveExclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string PreprocessText(string text) =>
|
||||||
|
text.Replace("\u2018", "'").Replace("\u2019", "'")
|
||||||
|
.Replace("\u201c", "\"").Replace("\u201d", "\"");
|
||||||
|
|
||||||
|
// ── Inner helpers ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private sealed class CypherTextWatcher : Java.Lang.Object, ITextWatcher
|
||||||
|
{
|
||||||
|
private readonly MauiAppCompatEditText _view;
|
||||||
|
private readonly string[] _keywords;
|
||||||
|
private bool _updating;
|
||||||
|
|
||||||
|
public CypherTextWatcher(MauiAppCompatEditText view, string[] keywords)
|
||||||
|
{
|
||||||
|
_view = view;
|
||||||
|
_keywords = keywords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BeforeTextChanged(Java.Lang.ICharSequence s, int start, int count, int after) { }
|
||||||
|
public void OnTextChanged(Java.Lang.ICharSequence s, int start, int before, int count) { }
|
||||||
|
|
||||||
|
public void AfterTextChanged(IEditable s)
|
||||||
|
{
|
||||||
|
if (_updating) return;
|
||||||
|
_updating = true;
|
||||||
|
try { HighlightSyntax(_view, _keywords); }
|
||||||
|
finally { _updating = false; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,38 +1,37 @@
|
|||||||
using System;
|
|
||||||
using Acr.UserDialogs;
|
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
using Android.Runtime;
|
using Android.Content.Res;
|
||||||
using Android.Views;
|
using Microsoft.Maui;
|
||||||
using Android.Widget;
|
using Microsoft.Maui.ApplicationModel;
|
||||||
using Android.OS;
|
|
||||||
|
|
||||||
namespace Xamarin.Neo4j.Android
|
namespace Xamarin.Neo4j.Android
|
||||||
{
|
{
|
||||||
[Activity(Label = "Xamarin.Neo4j", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
|
[Activity(
|
||||||
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
Theme = "@style/Maui.SplashTheme",
|
||||||
|
MainLauncher = true,
|
||||||
|
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation |
|
||||||
|
ConfigChanges.UiMode | ConfigChanges.ScreenLayout |
|
||||||
|
ConfigChanges.SmallestScreenSize | ConfigChanges.Density
|
||||||
|
)]
|
||||||
|
public class MainActivity : MauiAppCompatActivity
|
||||||
{
|
{
|
||||||
protected override void OnCreate(Bundle savedInstanceState)
|
protected override void OnResume()
|
||||||
{
|
{
|
||||||
TabLayoutResource = Resource.Layout.Tabbar;
|
base.OnResume();
|
||||||
ToolbarResource = Resource.Layout.Toolbar;
|
|
||||||
|
|
||||||
UserDialogs.Init(this);
|
// Re-apply theme and nav bar colours when returning to the foreground.
|
||||||
|
// ConfigChanges.UiMode prevents Activity recreation on system theme change,
|
||||||
|
// so RequestedThemeChanged may not fire reliably — we re-derive the theme
|
||||||
|
// from the current configuration instead.
|
||||||
|
if (IPlatformApplication.Current?.Application is App app)
|
||||||
|
{
|
||||||
|
var nightMode = Resources.Configuration.UiMode & UiMode.NightMask;
|
||||||
|
var theme = nightMode == UiMode.NightYes
|
||||||
|
? AppTheme.Dark
|
||||||
|
: AppTheme.Light;
|
||||||
|
|
||||||
base.OnCreate(savedInstanceState);
|
MainThread.BeginInvokeOnMainThread(() => app.UpdateTheme(theme));
|
||||||
|
}
|
||||||
Essentials.Platform.Init(this, savedInstanceState);
|
|
||||||
|
|
||||||
Forms.Forms.Init(this, savedInstanceState);
|
|
||||||
|
|
||||||
LoadApplication(new App());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
|
|
||||||
{
|
|
||||||
Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
|
|
||||||
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Runtime;
|
||||||
|
using Microsoft.Maui;
|
||||||
|
using Microsoft.Maui.Hosting;
|
||||||
|
|
||||||
|
namespace Xamarin.Neo4j.Android
|
||||||
|
{
|
||||||
|
[Application]
|
||||||
|
public class MainApplication : MauiApplication
|
||||||
|
{
|
||||||
|
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
|
||||||
|
: base(handle, ownership) { }
|
||||||
|
|
||||||
|
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Maui.Controls.Hosting;
|
||||||
|
using Microsoft.Maui.Hosting;
|
||||||
|
using Xamarin.Neo4j.Android.CustomRenderers;
|
||||||
|
using Xamarin.Neo4j.Android.Services;
|
||||||
|
using Xamarin.Neo4j.Services;
|
||||||
|
using Xamarin.Neo4j.Services.Interfaces;
|
||||||
|
|
||||||
|
namespace Xamarin.Neo4j.Android
|
||||||
|
{
|
||||||
|
public static class MauiProgram
|
||||||
|
{
|
||||||
|
public static MauiApp CreateMauiApp()
|
||||||
|
{
|
||||||
|
var builder = MauiApp.CreateBuilder();
|
||||||
|
builder
|
||||||
|
.UseMauiApp<App>()
|
||||||
|
.ConfigureFonts(fonts =>
|
||||||
|
{
|
||||||
|
fonts.AddFont("iconize-fontawesome-brands.ttf", "FontAwesome5Brands-Regular");
|
||||||
|
fonts.AddFont("iconize-fontawesome-solid.ttf", "FontAwesome5Free-Solid");
|
||||||
|
fonts.AddFont("iconize-fontawesome-regular.ttf", "FontAwesome5Free-Regular");
|
||||||
|
fonts.AddFont("roboto-mono-regular.ttf", "RobotoMono");
|
||||||
|
})
|
||||||
|
.ConfigureMauiHandlers(handlers =>
|
||||||
|
{
|
||||||
|
handlers.AddHandler<Controls.QueryEditor, QueryEditorHandler>();
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<ITrustManagerService, TrustManagerService>();
|
||||||
|
builder.Services.AddSingleton<IVersionService, VersionService>();
|
||||||
|
builder.Services.AddSingleton<IScreenSizeService, ScreenSizeService>();
|
||||||
|
builder.Services.AddSingleton<Neo4jService>();
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.Xamarin.Neo4j">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
|
android:versionCode="1"
|
||||||
<application android:label="Xamarin.Neo4j.Android"></application>
|
android:versionName="1.0"
|
||||||
</manifest>
|
package="nl.resoftware.pocketgraph">
|
||||||
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="36" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<!-- Required on Android 11+ to query for installed email apps -->
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.SENDTO" />
|
||||||
|
<data android:scheme="mailto" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="market" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
|
|
||||||
|
<application android:label="PocketGraph" android:allowBackup="true"></application>
|
||||||
|
</manifest>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="launcher_background">#FFFFFF</color>
|
<color name="launcher_background">#FFFFFF</color>
|
||||||
<color name="colorPrimary">#3F51B5</color>
|
<color name="colorPrimary">#31333b</color>
|
||||||
<color name="colorPrimaryDark">#303F9F</color>
|
<color name="colorPrimaryDark">#1e2026</color>
|
||||||
<color name="colorAccent">#FF4081</color>
|
<color name="colorAccent">#31333b</color>
|
||||||
|
<color name="navBar">#31333b</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,30 +1,44 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="MainTheme" parent="MainTheme.Base">
|
<!-- Splash theme shown while MAUI initialises — must have no action bar -->
|
||||||
</style>
|
<style name="Maui.SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
<!-- Base theme applied no matter what API -->
|
<item name="android:windowBackground">@color/colorPrimary</item>
|
||||||
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
|
<item name="android:windowNoTitle">true</item>
|
||||||
<!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
|
<item name="android:windowActionBar">false</item>
|
||||||
<item name="windowNoTitle">true</item>
|
<item name="android:windowFullscreen">false</item>
|
||||||
<!--We will be using the toolbar so no need to show ActionBar-->
|
<item name="android:windowContentOverlay">@null</item>
|
||||||
<item name="windowActionBar">false</item>
|
<!-- Ensure status bar icons are visible on the splash -->
|
||||||
<!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
|
<item name="android:windowLightStatusBar">false</item>
|
||||||
<!-- colorPrimary is used for the default action bar background -->
|
</style>
|
||||||
<item name="colorPrimary">#2196F3</item>
|
|
||||||
<!-- colorPrimaryDark is used for the status bar -->
|
|
||||||
<item name="colorPrimaryDark">#1976D2</item>
|
|
||||||
<!-- colorAccent is used as the default value for colorControlActivated
|
|
||||||
which is used to tint widgets -->
|
|
||||||
<item name="colorAccent">#FF4081</item>
|
|
||||||
<!-- You can also set colorControlNormal, colorControlActivated
|
|
||||||
colorControlHighlight and colorSwitchThumbNormal. -->
|
|
||||||
<item name="windowActionModeOverlay">true</item>
|
|
||||||
|
|
||||||
<item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
|
<!-- Main app theme — MAUI draws its own toolbar so we use NoActionBar -->
|
||||||
</style>
|
<style name="MainTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:windowActionBar">false</item>
|
||||||
|
<!-- Light status bar = false so status bar icons show white on dark bg -->
|
||||||
|
<item name="android:windowLightStatusBar">false</item>
|
||||||
|
<!-- Context action bar (long-press menu) should match nav bar color -->
|
||||||
|
<item name="actionModeBackground">@color/colorPrimary</item>
|
||||||
|
<!-- Make overflow (3-dot) button icon white -->
|
||||||
|
<item name="actionOverflowButtonStyle">@style/OverflowMenuButton</item>
|
||||||
|
<!-- Make CAB (contextual action bar) title/icon white without affecting popup menus -->
|
||||||
|
<item name="actionModeStyle">@style/ActionModeStyle</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="OverflowMenuButton" parent="Widget.AppCompat.ActionButton.Overflow">
|
||||||
|
<item name="android:tint">@android:color/white</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ActionModeStyle" parent="Widget.AppCompat.ActionMode">
|
||||||
|
<item name="titleTextStyle">@style/ActionModeTitleText</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ActionModeTitleText" parent="TextAppearance.AppCompat.Widget.ActionMode.Title">
|
||||||
|
<item name="android:textColor">@android:color/white</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
|
|
||||||
<item name="colorAccent">#FF4081</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// NativeTrustManager.cs
|
||||||
|
//
|
||||||
|
// © Xamarin.Neo4j.Android
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Java.Security;
|
||||||
|
using Java.Security.Cert;
|
||||||
|
using Javax.Net.Ssl;
|
||||||
|
using Neo4j.Driver;
|
||||||
|
|
||||||
|
namespace Xamarin.Neo4j
|
||||||
|
{
|
||||||
|
public class NativeTrustManager : TrustManager
|
||||||
|
{
|
||||||
|
private readonly IX509TrustManager _androidTrustManager;
|
||||||
|
|
||||||
|
public NativeTrustManager()
|
||||||
|
{
|
||||||
|
var factory = TrustManagerFactory.GetInstance(TrustManagerFactory.DefaultAlgorithm);
|
||||||
|
factory.Init((KeyStore)null);
|
||||||
|
_androidTrustManager = factory.GetTrustManagers()
|
||||||
|
.OfType<IX509TrustManager>()
|
||||||
|
.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ValidateServerCertificate(Uri uri, X509Certificate2 certificate, X509Chain chain,
|
||||||
|
SslPolicyErrors sslPolicyErrors)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// The Xamarin binding of CertificateFactory.GenerateCertificate accepts a System.IO.Stream
|
||||||
|
var certFactory = CertificateFactory.GetInstance("X.509");
|
||||||
|
using var stream = new MemoryStream(certificate.RawData);
|
||||||
|
var javaCert = certFactory.GenerateCertificate(stream) as Java.Security.Cert.X509Certificate;
|
||||||
|
|
||||||
|
_androidTrustManager.CheckServerTrusted(
|
||||||
|
new Java.Security.Cert.X509Certificate[] { javaCert }, "RSA");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"Certificate validation failed for {uri.Host}: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// ScreenSizeService.cs
|
||||||
|
//
|
||||||
|
// © Xamarin.Neo4j.Android
|
||||||
|
//
|
||||||
|
|
||||||
|
using Xamarin.Neo4j.Services.Interfaces;
|
||||||
|
|
||||||
|
namespace Xamarin.Neo4j.Android.Services
|
||||||
|
{
|
||||||
|
public class ScreenSizeService : IScreenSizeService
|
||||||
|
{
|
||||||
|
public int GetScreenHeight()
|
||||||
|
{
|
||||||
|
var metrics = global::Android.App.Application.Context.Resources.DisplayMetrics;
|
||||||
|
return (int)(metrics.HeightPixels / metrics.Density);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetScreenWidth()
|
||||||
|
{
|
||||||
|
var metrics = global::Android.App.Application.Context.Resources.DisplayMetrics;
|
||||||
|
return (int)(metrics.WidthPixels / metrics.Density);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// TrustManagerService.cs
|
||||||
|
//
|
||||||
|
// © Xamarin.Neo4j.Android
|
||||||
|
//
|
||||||
|
|
||||||
|
using Neo4j.Driver;
|
||||||
|
using Xamarin.Neo4j.Services.Interfaces;
|
||||||
|
|
||||||
|
namespace Xamarin.Neo4j.Android.Services
|
||||||
|
{
|
||||||
|
public class TrustManagerService : ITrustManagerService
|
||||||
|
{
|
||||||
|
public TrustManager GetNativeTrustManager()
|
||||||
|
{
|
||||||
|
return new NativeTrustManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// VersionService.cs
|
||||||
|
//
|
||||||
|
// © Xamarin.Neo4j.Android
|
||||||
|
//
|
||||||
|
|
||||||
|
using Android.OS;
|
||||||
|
using Xamarin.Neo4j.Services.Interfaces;
|
||||||
|
|
||||||
|
namespace Xamarin.Neo4j.Android.Services
|
||||||
|
{
|
||||||
|
public class VersionService : IVersionService
|
||||||
|
{
|
||||||
|
public string GetVersion()
|
||||||
|
{
|
||||||
|
var context = global::Android.App.Application.Context;
|
||||||
|
var info = context.PackageManager.GetPackageInfo(context.PackageName, 0);
|
||||||
|
return info.VersionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetBuild()
|
||||||
|
{
|
||||||
|
var context = global::Android.App.Application.Context;
|
||||||
|
var info = context.PackageManager.GetPackageInfo(context.PackageName, 0);
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
return Build.VERSION.SdkInt >= BuildVersionCodes.P
|
||||||
|
? info.LongVersionCode.ToString()
|
||||||
|
: info.VersionCode.ToString();
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,73 +1,50 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFramework>net10.0-android</TargetFramework>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<OutputType>Exe</OutputType>
|
||||||
<ProjectGuid>{24C5C58E-C59D-4621-9BF0-2E3BAC547455}</ProjectGuid>
|
<UseMaui>true</UseMaui>
|
||||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<RootNamespace>Xamarin.Neo4j.Android</RootNamespace>
|
|
||||||
<AssemblyName>Xamarin.Neo4j.Android</AssemblyName>
|
<AssemblyName>Xamarin.Neo4j.Android</AssemblyName>
|
||||||
<AndroidApplication>True</AndroidApplication>
|
<ApplicationId>nl.resoftware.pocketgraph</ApplicationId>
|
||||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
<ApplicationTitle>PocketGraph</ApplicationTitle>
|
||||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
<LangVersion>latest</LangVersion>
|
||||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
<Nullable>disable</Nullable>
|
||||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
<!-- Embed all assemblies in the APK so plain adb install works without Fast Deployment -->
|
||||||
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>portable</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidLinkMode>None</AndroidLinkMode>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Mono.Android" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.20" />
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2196" />
|
<!-- Link font assets from the iOS Resources folder so MAUI can bundle them for Android -->
|
||||||
|
<AndroidAsset Include="..\Xamarin.Neo4j.iOS\Resources\iconize-fontawesome-brands.ttf"
|
||||||
|
Link="Assets\iconize-fontawesome-brands.ttf" />
|
||||||
|
<AndroidAsset Include="..\Xamarin.Neo4j.iOS\Resources\iconize-fontawesome-regular.ttf"
|
||||||
|
Link="Assets\iconize-fontawesome-regular.ttf" />
|
||||||
|
<AndroidAsset Include="..\Xamarin.Neo4j.iOS\Resources\iconize-fontawesome-solid.ttf"
|
||||||
|
Link="Assets\iconize-fontawesome-solid.ttf" />
|
||||||
|
<AndroidAsset Include="..\Xamarin.Neo4j.iOS\Resources\roboto-mono-regular.ttf"
|
||||||
|
Link="Assets\roboto-mono-regular.ttf" />
|
||||||
|
<AndroidAsset Include="..\Xamarin.Neo4j.iOS\Resources\logo.png"
|
||||||
|
Link="Assets\logo.png" />
|
||||||
|
<AndroidAsset Include="..\Xamarin.Neo4j.iOS\Resources\resoftware.png"
|
||||||
|
Link="Assets\resoftware.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="MainActivity.cs" />
|
<!-- Exclude old Xamarin.Forms layout resources not needed by MAUI -->
|
||||||
<Compile Include="Resources\Resource.Designer.cs" />
|
<AndroidResource Remove="Resources\layout\Tabbar.axml" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<AndroidResource Remove="Resources\layout\Toolbar.axml" />
|
||||||
|
<!-- Exclude old AssemblyInfo and Resource.designer — SDK-style generates these -->
|
||||||
|
<Compile Remove="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Remove="Resources\Resource.Designer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Resources\AboutResources.txt" />
|
<ProjectReference Include="..\Xamarin.Neo4j\Xamarin.Neo4j.csproj" />
|
||||||
<None Include="Assets\AboutAssets.txt" />
|
|
||||||
<None Include="Properties\AndroidManifest.xml" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
|
||||||
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
|
||||||
<AndroidResource Include="Resources\values\styles.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\colors.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Xamarin.Neo4j\Xamarin.Neo4j.csproj">
|
|
||||||
<Project>{756232D0-DBB0-4AEB-B1CF-1F5CA12CAC85}</Project>
|
|
||||||
<Name>Xamarin.Neo4j</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user