diff --git a/MauiApp1/Platforms/Android/AndroidManifest.xml b/MauiApp1/Platforms/Android/AndroidManifest.xml index ff2d280..561e7f6 100644 --- a/MauiApp1/Platforms/Android/AndroidManifest.xml +++ b/MauiApp1/Platforms/Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + diff --git a/MauiApp1/Platforms/Android/Resources/Layout/floatview.xml b/MauiApp1/Platforms/Android/Resources/Layout/floatview.xml index 33ec7e5..b5d37bf 100644 --- a/MauiApp1/Platforms/Android/Resources/Layout/floatview.xml +++ b/MauiApp1/Platforms/Android/Resources/Layout/floatview.xml @@ -4,20 +4,25 @@ android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@color/abc_hint_foreground_material_dark" + android:id="@+id/rowContainer" + android:background="@color/m3_ref_palette_white" + android:paddingLeft="4dp" + android:paddingBottom="3dp" + android:paddingTop="3dp" + android:paddingRight="2dp" > + > - form + FORM \ No newline at end of file diff --git a/MauiApp1/Platforms/Android/Services/MyAccessibilityService.cs b/MauiApp1/Platforms/Android/Services/MyAccessibilityService.cs index b9cbaca..f2a1c6f 100644 --- a/MauiApp1/Platforms/Android/Services/MyAccessibilityService.cs +++ b/MauiApp1/Platforms/Android/Services/MyAccessibilityService.cs @@ -12,26 +12,29 @@ using MauiApp1.Models; using Microsoft.Maui.Controls; using System.Security.Cryptography; +using System.Text; using System.Text.Json; using static Android.Views.View; +using static MudBlazor.Colors; using Resource = Microsoft.Maui.Resource; [Service(Exported = false, Label = "TextToolsPro", Permission = Manifest.Permission.BindAccessibilityService)] [IntentFilter(new[] { "android.accessibilityservice.AccessibilityService" })] [MetaData("android.accessibilityservice", Resource = "@xml/accessibility_service")] -public class MyAccessibilityService : AccessibilityService +public class MyAccessibilityService : AccessibilityService, Android.Views.View.IOnTouchListener { private Dictionary dict; private List globals; private readonly Bundle CursorArgs = new(); private readonly Bundle TextArgs = new(); private const string CursorStr = "$|$"; - private LinearLayout linearLayout; private WindowManagerLayoutParams layoutParams; private Android.Views.View floatView; private IWindowManager windowManager; private static readonly string[] _separators = [" ", "\n", "\r\n", " ,"]; - private static readonly string[] _formSeparators = [" ", "\n", "\r\n", "|"]; + private static readonly string[] _formSeparators = [" ", "|", "\r\n", "\n"]; + private static readonly string[] _lineSeparators = ["\r\n", "\n"]; + public override void OnCreate() @@ -44,7 +47,7 @@ public override void OnCreate() var item = m.Value.Item2; if (cmd == "Add") { - if (!(string.IsNullOrEmpty(item.Trigger) || string.IsNullOrEmpty(item.Replace))) + if (!string.IsNullOrEmpty(item.Form) || !(string.IsNullOrEmpty(item.Trigger) || string.IsNullOrEmpty(item.Replace))) { //dict.AddOrUpdate(item.Trigger, item, //(key, oldValue) => item); @@ -91,12 +94,6 @@ public override async void OnAccessibilityEvent(AccessibilityEvent e) //EditText editText3 = new EditText(this); //editText3.Hint = "Text 3"; //editText3.Id = GenerateViewId(); // Assign a unique ID - - //// **Add the EditTexts to the FrameLayout after adding it to window manager** - //linearLayout.Post(() => - //{ - // linearLayout.AddView(editText3); - //}); if (e.Source == null) return; if (e.Source.ClassName.Equals("android.widget.EditText")) @@ -104,41 +101,125 @@ public override async void OnAccessibilityEvent(AccessibilityEvent e) var Text = e.Text; if (Text != null) { - string og = Text[0].ToString(); + string expansionStr = Text[0].ToString(); + string og = expansionStr; //quick brown fox - CheckAndUpdateCursorArgs(og, sendIfCursorFound: true, e); - var arr = og.Split(_separators, StringSplitOptions.RemoveEmptyEntries); + CheckAndUpdateCursorArgs(expansionStr, sendIfCursorFound: true, e); + var arr = expansionStr.Split(_separators, StringSplitOptions.RemoveEmptyEntries); bool send = false; - - for (int wNum = 0; wNum < arr.Length; wNum++) + bool storeOg = true; + //for (int wNum = 0; wNum < arr.Length; wNum++) + //{ + var text = arr[^1]; + if (previousOg == og) + { + return; + } + else if (previousExpansion != "" && previousExpansion[..^1] == og) { - var text = arr[wNum]; - if (dict.TryGetValue(text, out var match)) + expansionStr = previousOg; + storeOg = false; + send = true; + } + else if (dict.TryGetValue(text, out var match)) + { + // echo, random, clipboard and date only supported + //if (!string.IsNullOrEmpty(match.Form)) + //{ + // string[] formLines = match.Form.Split(_lineSeparators, StringSplitOptions.RemoveEmptyEntries); + // var replaceDict = new Dictionary(); + // foreach (string line in formLines) + // { + // LinearLayout row = new(BaseContext) + // { + // Orientation = Orientation.Horizontal + // }; + // if (line.Contains("[[")) + // { + // string[] words = line.Split(_formSeparators, StringSplitOptions.RemoveEmptyEntries); + // if (words.Length > 0) + // { + // foreach (string word in words) + // { + // if (word.StartsWith("[[")) + // { + // var endIndex = word.IndexOf(']'); + // var placeholderStr = word[2..endIndex]; + // row.Post(() => + // { + // var et = new EditText(BaseContext) + // { + // Hint = placeholderStr + // }; + + // et.TextChanged += (sender, e) => + // { + // var text = e.Text.ToString(); + // if (!replaceDict.TryAdd(placeholderStr, text)) + // { + // replaceDict[placeholderStr] = text; + // } + // }; + // if (match.Form_Fields is not null) + // et.SetMinLines(match.Form_Fields[placeholderStr].Multiline ? 5 : 1); + // row.AddView(et); + // }); + // } + // else + // { + // AddTextView(row, word); + // } + // } + // } + // } + // else + // { + // AddTextView(row, line); + // } + // rowContainer.Post(() => + // { + // rowContainer.AddView(row); + // }); + // } + // var submitButton = new Android.Widget.Button(BaseContext) + // { + // Text = "Submit", + // }; + // submitButton.Click += (sender, ea) => + // { + // // Replace all occurrences of keys with values + // foreach (var item in replaceDict) + // { + // string key = $"[[{item.Key}]]"; + // match.Form = match.Form.Replace(key, item.Value); + // } + // AccessibilityNodeInfo rootNode = GetRootInActiveWindow(0); + + // }; + // rowContainer.Post(() => + // { + // rowContainer.AddView(submitButton); + // }); + // windowManager.AddView(floatView, layoutParams); + //} + //else { - // echo, random, clipboard and date only supported - if (!string.IsNullOrEmpty(match.Form)) - { - string[] formLines = match.Form.Split(_formSeparators, StringSplitOptions.RemoveEmptyEntries); - } string replace = match.Replace; + var triggerIndex = expansionStr.IndexOf(text); if (match.Word) { - int index = 0; - for (int i = 0; i < wNum; i++) - { - index += arr[0].Length; - } - var start = og.IndexOf(text, index); //check the start - if (start != 0 && !_separators.Contains(og[start - 1].ToString())) + if (triggerIndex == 0) { - break; + if (!_separators.Contains(expansionStr[triggerIndex + text.Length].ToString())) + { + return; + } } - //check the end - var end = start + text.Length; - if ((end) <= og.Length && !_separators.Contains(og[end].ToString())) + //check the start and end + else if (!_separators.Contains(expansionStr[triggerIndex - 1].ToString()) || !_separators.Contains(expansionStr[triggerIndex + text.Length].ToString())) { - break; + return; } } if (globals is not null) @@ -157,27 +238,26 @@ public override async void OnAccessibilityEvent(AccessibilityEvent e) } if (replace is not null) { - int index = 0; - for (int i = 0; i < wNum; i++) - { - index += arr[i].Length; - } - var end = og[index..].Replace(text, replace); - og = og[..index] + end; + var end = expansionStr[triggerIndex..].Replace(text, replace); + expansionStr = expansionStr[..triggerIndex] + end; send = true; } } } + //} if (send) { //og has been modified with our new expansion - TextArgs.Remove(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence); - TextArgs.PutCharSequence(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, og); - e.Source.PerformAction(Android.Views.Accessibility.Action.SetText, TextArgs); - if (e.Source.Refresh()) + DoExpansion(e, expansionStr); + if (storeOg) { - CheckAndUpdateCursorArgs(og, sendIfCursorFound: false, e); - e.Source.PerformAction(Android.Views.Accessibility.Action.SetSelection, CursorArgs); + previousOg = og; + previousExpansion = expansionStr; + } + else + { + previousOg = ""; + previousExpansion = ""; } } } @@ -190,6 +270,29 @@ public override async void OnAccessibilityEvent(AccessibilityEvent e) } } + private void DoExpansion(AccessibilityEvent e, string og) + { + TextArgs.Remove(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence); + TextArgs.PutCharSequence(AccessibilityNodeInfo.ActionArgumentSetTextCharsequence, og); + e.Source.PerformAction(Android.Views.Accessibility.Action.SetText, TextArgs); + if (e.Source.Refresh()) + { + CheckAndUpdateCursorArgs(og, sendIfCursorFound: false, e); + e.Source.PerformAction(Android.Views.Accessibility.Action.SetSelection, CursorArgs); + } + } + + private void AddTextView(LinearLayout row, string word) + { + row.Post(() => + { + row.AddView(new TextView(BaseContext) + { + Text = word, + }); + }); + } + private void CheckAndUpdateCursorArgs(string og, bool sendIfCursorFound, AccessibilityEvent e) { int startIndex = og.IndexOf(CursorStr); @@ -262,37 +365,69 @@ protected override void OnServiceConnected() { base.OnServiceConnected(); WeakReferenceMessenger.Default.Send(new AcServiceMessage(("_", null))); - linearLayout = new LinearLayout(this); - linearLayout.Orientation = Orientation.Vertical; - layoutParams = new WindowManagerLayoutParams(); - layoutParams.Type = WindowManagerTypes.AccessibilityOverlay; - layoutParams.Format = Format.Translucent; - layoutParams.Flags |= WindowManagerFlags.NotFocusable; - layoutParams.Width = ViewGroup.LayoutParams.WrapContent; - layoutParams.Height = ViewGroup.LayoutParams.WrapContent; - layoutParams.Gravity = GravityFlags.Top; - LayoutInflater inflater = LayoutInflater.From(this); - floatView = inflater.Inflate(Resource.Layout.floatview, linearLayout); - var imgButton = floatView.FindViewById(Resource.Id.close_button); - if (imgButton != null) - { - imgButton.Click += (sender, e) => - { - windowManager.RemoveView(linearLayout); - }; - windowManager = GetSystemService(WindowService).JavaCast(); - windowManager.AddView(linearLayout, layoutParams); - } + //var linearLayout = new LinearLayout(this); + //linearLayout.Orientation = Orientation.Vertical; + //layoutParams = new WindowManagerLayoutParams(); + //layoutParams.Type = WindowManagerTypes.AccessibilityOverlay; + //layoutParams.Format = Format.Translucent; + //layoutParams.Width = ViewGroup.LayoutParams.WrapContent; + //layoutParams.Height = ViewGroup.LayoutParams.WrapContent; + //layoutParams.Gravity = GravityFlags.Top; + //LayoutInflater inflater = LayoutInflater.From(this); + //floatView = inflater.Inflate(Resource.Layout.floatview, linearLayout); + //var closeBtn = floatView.FindViewById(Resource.Id.close_button); + //if (closeBtn != null) + //{ + // closeBtn.Click += (sender, e) => + // { + // windowManager.RemoveView(floatView); + // }; + // windowManager = GetSystemService(WindowService).JavaCast(); + // windowManager.AddView(floatView, layoutParams); + // floatView.SetOnTouchListener(this); + // rowContainer = floatView.FindViewById(Resource.Id.rowContainer); + //} } public override bool OnUnbind(Intent intent) { // Remove the overlay when the service is unbound - if (linearLayout != null) + //if (floatView != null) + //{ + // IWindowManager windowManager = (IWindowManager)GetSystemService(Context.WindowService); + // windowManager.RemoveView(floatView); + //} + return base.OnUnbind(intent); + } + private float xDown, yDown; + private LinearLayout rowContainer; + private string previousOg = ""; + private string previousExpansion = ""; + + public bool OnTouch(Android.Views.View v, MotionEvent e) + { + var action = e.Action; + + switch (action) { - IWindowManager windowManager = (IWindowManager)GetSystemService(Context.WindowService); - windowManager.RemoveView(linearLayout); + case MotionEventActions.Down: + xDown = e.RawX; + yDown = e.RawY; + return true; + case MotionEventActions.Move: + float deltaX = e.RawX - xDown; + float deltaY = e.RawY - yDown; + + layoutParams.X += (int)deltaX; + layoutParams.Y += (int)deltaY; + + windowManager.UpdateViewLayout(floatView, layoutParams); + + xDown = e.RawX; + yDown = e.RawY; + return true; + default: + return false; } - return base.OnUnbind(intent); } } diff --git a/MauiApp1/TextComparePro.csproj b/MauiApp1/TextComparePro.csproj index eb1c9f1..f8db179 100644 --- a/MauiApp1/TextComparePro.csproj +++ b/MauiApp1/TextComparePro.csproj @@ -19,8 +19,8 @@ A9E98E65-AE83-5428-9AB1-578DC0552CB8 - 6.9 - 21 + 6.9.1 + 22 14.2 14.0