Skip to content

Commit 028620b

Browse files
committed
fix: OneNote sync perf, cloud cache, color sync, batch rendering
- Fix OneNote sync hanging: pull only from Outlook, skip NoteUI section (100 pages) - Guard against double sync calls with IsSyncing check - Cloud cache: load cached notes instantly at startup before re-sync - Sticky Notes colors: cross-reference with local SQLite database - Batch rendering: load notes in batches of 30 via DispatcherQueue - Clear notes on provider switch to prevent mixing - Note count moved to status bar next to title - Storage menu: separator between profiles and custom folder - Import Sticky Notes button under OneNote in storage menu - Storage menu order: WebDAV > Firebase > OneNote - Remove dead MAPI/categories/HTML color extraction code - Version bump to 0.5.1
1 parent 5201f60 commit 028620b

7 files changed

Lines changed: 190 additions & 128 deletions

File tree

‎ActionPanel.cs‎

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ public static Flyout CreateSettings(string currentTheme, string currentBackdropT
198198
Action<string, Action>? onRenameProfile = null, Action<string>? onDeleteProfile = null,
199199
Func<string>? getActiveProfile = null, Func<List<string>>? getProfiles = null,
200200
Action? onConfigureOneNote = null, Action? onDisconnectOneNote = null, Action? onSyncOneNote = null,
201+
Action? onImportStickyNotes = null,
201202
Action<Flyout>? onShowVoiceModels = null,
202203
Action<Flyout>? onShowShortcuts = null,
203204
string? currentLanguage = null, bool slashEnabled = true,
@@ -317,9 +318,10 @@ static string FindLabel((string key, string label)[] items, string current)
317318
onResetFolder, onChangeFolder,
318319
onSwitchProfile ?? (_ => { }), onCreateProfile ?? (() => { }),
319320
onRenameProfile ?? ((_, _) => { }), onDeleteProfile ?? (_ => { }),
320-
onConfigureFirebase, onDisconnectFirebase, onSyncFirebase,
321321
onConfigureWebDav, onDisconnectWebDav, onSyncWebDav,
322+
onConfigureFirebase, onDisconnectFirebase, onSyncFirebase,
322323
onConfigureOneNote ?? (() => { }), onDisconnectOneNote ?? (() => { }), onSyncOneNote ?? (() => { }),
324+
onImportStickyNotes,
323325
getActiveProfile ?? (() => activeProfile ?? ""),
324326
getProfiles ?? (() => profiles ?? []),
325327
() => flyout.Hide());
@@ -499,9 +501,10 @@ private static Flyout CreateStorageSubMenu(
499501
Action onResetFolder, Action onChangeFolder,
500502
Action<string> onSwitchProfile, Action onCreateProfile,
501503
Action<string, Action> onRenameProfile, Action<string> onDeleteProfile,
502-
Action onConfigureFirebase, Action onDisconnectFirebase, Action onSyncFirebase,
503504
Action onConfigureWebDav, Action onDisconnectWebDav, Action onSyncWebDav,
505+
Action onConfigureFirebase, Action onDisconnectFirebase, Action onSyncFirebase,
504506
Action onConfigureOneNote, Action onDisconnectOneNote, Action onSyncOneNote,
507+
Action? onImportStickyNotes,
505508
Func<string> getActiveProfile, Func<List<string>> getProfiles,
506509
Action onDone)
507510
{
@@ -594,18 +597,6 @@ void RebuildPanel()
594597

595598
panel.Children.Add(CreateSeparator());
596599

597-
// ── Firebase ──
598-
if (isFirebaseConnected)
599-
{
600-
var fbLabel = !string.IsNullOrEmpty(firebaseEmail) ? $"Firebase — {firebaseEmail}" : "Firebase";
601-
panel.Children.Add(CreateCheckItem(fbLabel, true, () => { onSyncFirebase(); onDone(); }));
602-
panel.Children.Add(CreateActionItem(Lang.T("disconnect"), () => { onDisconnectFirebase(); onDone(); }));
603-
}
604-
else
605-
{
606-
panel.Children.Add(CreateCheckItem("Firebase", false, () => { onConfigureFirebase(); onDone(); }));
607-
}
608-
609600
// ── WebDAV ──
610601
if (isWebDavConnected)
611602
{
@@ -618,6 +609,18 @@ void RebuildPanel()
618609
panel.Children.Add(CreateCheckItem("WebDAV", false, () => { onConfigureWebDav(); onDone(); }));
619610
}
620611

612+
// ── Firebase ──
613+
if (isFirebaseConnected)
614+
{
615+
var fbLabel = !string.IsNullOrEmpty(firebaseEmail) ? $"Firebase — {firebaseEmail}" : "Firebase";
616+
panel.Children.Add(CreateCheckItem(fbLabel, true, () => { onSyncFirebase(); onDone(); }));
617+
panel.Children.Add(CreateActionItem(Lang.T("disconnect"), () => { onDisconnectFirebase(); onDone(); }));
618+
}
619+
else
620+
{
621+
panel.Children.Add(CreateCheckItem("Firebase", false, () => { onConfigureFirebase(); onDone(); }));
622+
}
623+
621624
// ── OneNote ──
622625
if (isOneNoteConnected)
623626
{
@@ -629,6 +632,12 @@ void RebuildPanel()
629632
{
630633
panel.Children.Add(CreateCheckItem("OneNote", false, () => { onConfigureOneNote(); onDone(); }));
631634
}
635+
636+
// ── Import Sticky Notes (under OneNote) ──
637+
if (onImportStickyNotes != null)
638+
{
639+
panel.Children.Add(CreateActionItem(Lang.T("import_sticky_notes"), () => { onImportStickyNotes(); }));
640+
}
632641
}
633642

634643
RebuildPanel();

‎MainWindow.xaml‎

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,13 @@
2323
PointerMoved="DragBar_PointerMoved"
2424
PointerReleased="DragBar_PointerReleased"/>
2525

26-
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left"
27-
VerticalAlignment="Center" Spacing="0">
28-
<Button x:Name="AddButton"
29-
Background="Transparent" BorderThickness="0"
30-
Padding="10,6" Click="AddButton_Click"
31-
PointerEntered="AnimatedButton_PointerEntered"
32-
PointerExited="AnimatedButton_PointerExited">
33-
<FontIcon Glyph="&#xE710;" FontSize="16"/>
34-
</Button>
35-
<TextBlock x:Name="NoteCountText" VerticalAlignment="Center"
36-
FontSize="11" Opacity="0.4" Margin="2,0,0,0"/>
37-
</StackPanel>
26+
<Button x:Name="AddButton" HorizontalAlignment="Left" VerticalAlignment="Center"
27+
Background="Transparent" BorderThickness="0"
28+
Padding="10,6" Click="AddButton_Click"
29+
PointerEntered="AnimatedButton_PointerEntered"
30+
PointerExited="AnimatedButton_PointerExited">
31+
<FontIcon Glyph="&#xE710;" FontSize="16"/>
32+
</Button>
3833

3934
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
4035
VerticalAlignment="Center" Spacing="0">
@@ -75,6 +70,8 @@
7570
<TextBlock x:Name="TitleLabel" Text="Notes"
7671
FontSize="22" FontWeight="Bold"
7772
Tapped="TitleLabel_Tapped"/>
73+
<TextBlock x:Name="NoteCountText" VerticalAlignment="Bottom"
74+
FontSize="12" Opacity="0.35" Margin="0,0,0,2"/>
7875
</StackPanel>
7976
<crimson:GlowLine Width="340" Height="2" HorizontalAlignment="Left"/>
8077
</StackPanel>

‎MainWindow.xaml.cs‎

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ private void ApplyLocalization()
232232

233233
private async Task InitCloudSync()
234234
{
235+
// Load cloud cache first so UI shows notes immediately
236+
_notes.LoadCloudCache();
237+
if (_notes.Notes.Count > 0)
238+
RefreshCurrentView();
239+
235240
await _notes.InitFirebaseFromSettings();
236241
await _notes.InitWebDavFromSettings();
237242
await _notes.InitOneNoteFromSettings();
@@ -342,6 +347,7 @@ private void DisconnectAllCloudProviders()
342347
_notes.DisconnectWebDav();
343348
if (_notes.OneNote is { IsConnected: true })
344349
_notes.DisconnectOneNote();
350+
_notes.ClearNotes();
345351
UpdateSyncButtonVisibility();
346352
}
347353

@@ -457,8 +463,14 @@ private void SaveNotePositions()
457463
_notes.Save();
458464
}
459465

466+
private CancellationTokenSource? _refreshCts;
467+
460468
private void RefreshNotesList(string? search = null)
461469
{
470+
_refreshCts?.Cancel();
471+
_refreshCts = new CancellationTokenSource();
472+
var ct = _refreshCts.Token;
473+
462474
ResetExpandedState();
463475
NotesList.Children.Clear();
464476
var notes = _notes.GetSorted(AppSettings.LoadSortPreference()).Where(n => !n.IsArchived).ToList();
@@ -471,14 +483,25 @@ private void RefreshNotesList(string? search = null)
471483
).ToList();
472484
}
473485

486+
const int batchSize = 30;
474487
var index = 0;
475-
foreach (var note in notes)
488+
489+
void LoadBatch()
476490
{
477-
var card = CreateNoteCard(note);
478-
NotesList.Children.Add(card);
479-
AnimationHelper.FadeSlideIn(card, delayMs: index * 30, durationMs: 250);
480-
index++;
491+
if (ct.IsCancellationRequested) return;
492+
var end = Math.Min(index + batchSize, notes.Count);
493+
for (; index < end; index++)
494+
{
495+
var card = CreateNoteCard(notes[index]);
496+
NotesList.Children.Add(card);
497+
if (index < batchSize)
498+
AnimationHelper.FadeSlideIn(card, delayMs: index * 20, durationMs: 200);
499+
}
500+
if (index < notes.Count)
501+
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Low, LoadBatch);
481502
}
503+
504+
LoadBatch();
482505
}
483506

484507
private void SaveMainWindowPosition()
@@ -2139,6 +2162,11 @@ private void Settings_Click(object sender, RoutedEventArgs e)
21392162
RefreshOpenNoteWindows();
21402163
RefreshCurrentView();
21412164
},
2165+
onImportStickyNotes: StickyNotesReader.IsAvailable ? () =>
2166+
{
2167+
var count = _notes.ImportStickyNotes();
2168+
if (count > 0) RefreshCurrentView();
2169+
} : null,
21422170
onShowVoiceModels: f => ShowVoiceModelsInSettings(f),
21432171
onShowShortcuts: f => ShowShortcutsInSettings(f),
21442172
currentLanguage: Lang.Current,
@@ -2534,11 +2562,8 @@ private async Task ShowWebDavConfigDialog()
25342562
var (success, error) = await _notes.ConnectWebDav(url, user, pass);
25352563
if (success)
25362564
{
2537-
_notes.ClearNotes();
2538-
RefreshCurrentView();
25392565
await _notes.SyncFromWebDav();
25402566
RefreshCurrentView();
2541-
RestorePersistedWindows();
25422567
break;
25432568
}
25442569

@@ -2715,25 +2740,16 @@ private async Task ShowOneNoteConfigDialog()
27152740
var (success, error) = await _notes.SignInOneNote(clientId);
27162741
if (success)
27172742
{
2718-
// Clear notes immediately so user sees empty list + spinner
2719-
_notes.ClearNotes();
2720-
RefreshCurrentView();
27212743
UpdateSyncButtonVisibility();
27222744
StartSyncAnimation();
2723-
var syncOk = false;
27242745
try
27252746
{
2726-
syncOk = await _notes.SyncFromOneNote();
2747+
await _notes.SyncFromOneNote();
27272748
}
27282749
finally
27292750
{
27302751
StopSyncAnimation();
2731-
}
2732-
// Only refresh if sync succeeded (not cancelled by disconnect)
2733-
if (syncOk && _notes.OneNote is { IsConnected: true })
2734-
{
27352752
RefreshCurrentView();
2736-
RestorePersistedWindows();
27372753
}
27382754
}
27392755
else
@@ -2835,18 +2851,12 @@ private async Task ShowFirebaseConfigDialog()
28352851
var (success, error) = await _notes.SignInFirebaseWithGoogle(firebaseUrl, apiKey);
28362852
if (success)
28372853
{
2838-
_notes.ClearNotes();
2839-
RefreshCurrentView();
28402854
UpdateSyncButtonVisibility();
28412855
StartSyncAnimation();
2842-
var ok = await _notes.SyncFromFirebase();
2856+
await _notes.SyncFromFirebase();
28432857
StopSyncAnimation();
2844-
if (ok && _notes.Firebase is { IsConnected: true })
2845-
{
2846-
RefreshCurrentView();
2847-
RestorePersistedWindows();
2848-
StartFirebaseListener();
2849-
}
2858+
RefreshCurrentView();
2859+
StartFirebaseListener();
28502860
googleSignInDone = true;
28512861
}
28522862
else
@@ -2879,18 +2889,12 @@ private async Task ShowFirebaseConfigDialog()
28792889

28802890
if (success)
28812891
{
2882-
_notes.ClearNotes();
2883-
RefreshCurrentView();
28842892
UpdateSyncButtonVisibility();
28852893
StartSyncAnimation();
2886-
var ok = await _notes.SyncFromFirebase();
2894+
await _notes.SyncFromFirebase();
28872895
StopSyncAnimation();
2888-
if (ok && _notes.Firebase is { IsConnected: true })
2889-
{
2890-
RefreshCurrentView();
2891-
RestorePersistedWindows();
2892-
StartFirebaseListener();
2893-
}
2896+
RefreshCurrentView();
2897+
StartFirebaseListener();
28942898
break;
28952899
}
28962900

0 commit comments

Comments
 (0)