22using Avalonia ;
33using Avalonia . Controls ;
44using Avalonia . Data ;
5- using Avalonia . Input ;
6- using Avalonia . Interactivity ;
75using Avalonia . Platform ;
86using AvaloniaEdit ;
97using AvaloniaEdit . Document ;
@@ -15,13 +13,9 @@ public class SoraEditorControl: NativeControlHost
1513{
1614 private IPlatformHandle ? _impl ;
1715 private string _initialText = string . Empty ;
18- private bool _isSyncingDocument ;
19- private bool _isSyncingFocus ;
20-
2116
2217 public SoraEditorControl ( )
2318 {
24- Focusable = true ;
2519 }
2620
2721 public string Text
@@ -39,8 +33,8 @@ public string Text
3933 public static readonly StyledProperty < TextDocument > DocumentProperty = TextView . DocumentProperty . AddOwner < SoraEditorControl > ( ) ;
4034 public TextDocument Document
4135 {
42- get => this . GetValue < TextDocument > ( SoraEditorControl . DocumentProperty ) ;
43- set => this . SetValue ( SoraEditorControl . DocumentProperty , value ) ;
36+ get => this . GetValue < TextDocument > ( SoraEditorControl . DocumentProperty ) ;
37+ set => this . SetValue ( SoraEditorControl . DocumentProperty , value ) ;
4438 }
4539
4640 /// <summary>
@@ -53,69 +47,14 @@ public static ISoraEditorAndroid? Factory
5347 get => ISoraEditorAndroid . Implementation ;
5448 }
5549
56- public new bool Focus ( )
57- {
58- // Delegate focus to the native Android editor
59- if ( _impl is not null && Factory is not null )
60- {
61- Factory . RequestFocus ( _impl ) ;
62- return true ;
63- }
64- return base . Focus ( ) ;
65- }
66-
67- protected override void OnGotFocus ( GotFocusEventArgs e )
68- {
69- base . OnGotFocus ( e ) ;
70-
71- // When Avalonia sets focus to this control, delegate to the native editor
72- if ( ! _isSyncingFocus && _impl is not null && Factory is not null )
73- {
74- _isSyncingFocus = true ;
75- try
76- {
77- Factory . RequestFocus ( _impl ) ;
78- }
79- finally
80- {
81- _isSyncingFocus = false ;
82- }
83- }
84- }
85-
86- /// <summary>
87- /// Called when the native Android editor gains or loses focus.
88- /// When the native control gains focus (e.g. from a user tap), we claim
89- /// Avalonia focus so that the framework does not redirect it elsewhere.
90- /// </summary>
91- private void OnNativeFocusChanged ( bool hasFocus )
92- {
93- if ( _isSyncingFocus )
94- return ;
95-
96- if ( hasFocus )
97- {
98- _isSyncingFocus = true ;
99- try
100- {
101- // Claim Avalonia focus so the framework knows this control is active
102- base . Focus ( ) ;
103- }
104- finally
105- {
106- _isSyncingFocus = false ;
107- }
108- }
109- }
110-
11150 protected override IPlatformHandle CreateNativeControlCore ( IPlatformHandle parent )
11251 {
11352 if ( Factory is null )
11453 return base . CreateNativeControlCore ( parent ) ;
11554
11655 _impl = Factory . CreateControl ( parent , ( ) => base . CreateNativeControlCore ( parent ) ) ;
11756
118- // Set initial text if it was set before the control was created
57+ // Set initial text if it was set before the control was created
11958 if ( ! string . IsNullOrEmpty ( _initialText ) )
12059 {
12160 Factory . SetText ( _impl , _initialText ) ;
@@ -131,13 +70,10 @@ protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle paren
13170 // Hook up native text changed callback
13271 Factory . SetOnTextChanged ( _impl , OnNativeTextChanged ) ;
13372
134- // Hook up native focus changed callback for bidirectional focus sync
135- Factory . SetOnFocusChanged ( _impl , OnNativeFocusChanged ) ;
136-
13773 return _impl ;
13874 }
13975
140- protected override void DestroyNativeControlCore ( IPlatformHandle control )
76+ protected override void DestroyNativeControlCore ( IPlatformHandle control )
14177 {
14278 _impl = null ;
14379 base . DestroyNativeControlCore ( control ) ;
@@ -149,84 +85,13 @@ protected override void DestroyNativeControlCore(IPlatformHandle control)
14985 private void OnNativeTextChanged ( string newText )
15086 {
15187 // Sync back to Document if bound
152- _isSyncingDocument = true ;
153- try
154- {
155- var doc = Document ;
156- if ( doc != null && doc . Text != newText )
157- {
158- doc . Text = newText ;
159- }
160- }
161- finally
88+ var doc = Document ;
89+ if ( doc != null && doc . Text != newText )
16290 {
163- _isSyncingDocument = false ;
91+ doc . Text = newText ;
16492 }
16593
16694 // Raise TextChanged event
16795 TextChanged ? . Invoke ( this , EventArgs . Empty ) ;
16896 }
169-
170- protected override void OnPropertyChanged ( AvaloniaPropertyChangedEventArgs change )
171- {
172- base . OnPropertyChanged ( change ) ;
173-
174- if ( change . Property == DocumentProperty )
175- {
176- if ( change . NewValue is TextDocument newDoc )
177- {
178- // Sync document text to native editor
179- if ( _impl is not null && Factory is not null )
180- {
181- try
182- {
183- Factory . SetText ( _impl , newDoc . Text ) ;
184- }
185- catch ( ObjectDisposedException )
186- {
187- // Native control disposed, will be recreated when tab is re-selected
188- }
189- }
190- else
191- {
192- _initialText = newDoc . Text ;
193- }
194-
195- // Listen for document text changes
196- newDoc . TextChanged += OnDocumentTextChanged ;
197- }
198-
199- if ( change . OldValue is TextDocument oldDoc )
200- {
201- oldDoc . TextChanged -= OnDocumentTextChanged ;
202- }
203- }
204- else if ( change . Property == IsVisibleProperty )
205- {
206- // Propagate visibility changes to the native Android view so it doesn't
207- // render on top of overlay dialogs
208- if ( _impl is not null && Factory is not null )
209- {
210- Factory . SetVisible ( _impl , IsVisible ) ;
211- }
212- }
213- }
214-
215- private void OnDocumentTextChanged ( object ? sender , EventArgs e )
216- {
217- if ( _isSyncingDocument || _impl is null )
218- return ;
219-
220- try
221- {
222- if ( Factory is not null && sender is TextDocument doc )
223- {
224- Factory . SetText ( _impl , doc . Text ) ;
225- }
226- }
227- catch ( ObjectDisposedException )
228- {
229- // Native control has been disposed (e.g. tab switched away), ignore
230- }
231- }
232- }
97+ }
0 commit comments