Compare commits

...

8 commits

Author SHA1 Message Date
7cf24025b6 Updated MainWindow.axaml
Set the icon to the default program icon.
2025-08-01 22:14:17 -05:00
7ad03d2c17 Updated CSProj
Updated Assets from using old AvaloniaXaml tag, to using
AvaloniaResource tag.  Added awaiting and complete icons.
2025-08-01 22:14:01 -05:00
480474c343 Updated App.axaml.cs
Added fields for Normal icon, Waiting to Sync Icon, and Syncing Complete
icons to let user know of changes in the state of the Syncer.
Added function to ensure that we are changing the Icon and Tooltip on
the UI Thread, instead of some other thread.
Updated SyncMonitor to check for any dirty syncers, and if so, we update
our SysTray icon.
Added update to show we are syncing the data (Tooltip only)
Added update to show we have compeleted sync.
Added timer for 3 seconds before resetting SysTray and tooltip back to
normal status.
2025-08-01 22:13:17 -05:00
358539bfd5 Updated App.axaml
Added Models to XML Namespace.
Set DataType to be AppViewModel
Changed from static tooltip and icon, to using Bindings.
2025-08-01 22:08:32 -05:00
14fae4b246 Updated Syncer
Removed un-nesscary Close() as using should automatically close, and
dispose of the file handler.
Added a 100ms wait after we finish writing the file, before we unlock
the watcher, so we don't generate un-nesscary events.
2025-08-01 22:07:33 -05:00
4c400c03b8 Created AppViewModel
Created AppViewModel to handle System Tray Icon, and Tooltip.
2025-08-01 22:06:16 -05:00
c9c88358c3 Updated DBSyncWatcher
Changed from Doing a for loop, to just returning, as we don't want to
propogate the signal if we are syncing.
2025-08-01 22:05:36 -05:00
b63f32dd06 Updated Icons
Updated Icons to create our variant of branding.
2025-08-01 22:04:50 -05:00
10 changed files with 58 additions and 9 deletions

View file

@ -1,7 +1,9 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sukiUi="clr-namespace:SukiUI;assembly=SukiUI"
xmlns:vm="clr-namespace:FreeTubeSyncer.Models"
x:Class="FreeTubeSyncer.App"
x:DataType="vm:AppViewModel"
RequestedThemeVariant="Dark">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
@ -11,8 +13,8 @@
<TrayIcon.Icons>
<TrayIcons>
<TrayIcon Icon="/Assets/freetube.png"
ToolTipText="FreeTube Syncer"
<TrayIcon Icon="{Binding AppIcon}"
ToolTipText="{Binding HintTooltip, Mode=TwoWay}"
Clicked="TrayIcon_OnClicked">
<TrayIcon.Menu>
<NativeMenu>

View file

@ -8,8 +8,11 @@ using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using Avalonia.Threading;
using FreeTubeSyncer.Library;
using FreeTubeSyncer.Models;
using FreeTubeSyncer.Models.DatabaseModels;
@ -39,13 +42,23 @@ public partial class App : Application
private TimeSpan _checkInterval;
private DateTime _lastUpdated;
private WindowIcon? _normalTrayIcon;
private WindowIcon? _waitingTrayIcon;
private WindowIcon? _completeTrayIcon;
public event EventHandler? SettingsChanged;
public static App GetApp() => (App)App.Current!;
public static ClassicDesktopStyleApplicationLifetime GetDesktop() => (ClassicDesktopStyleApplicationLifetime)App.Current!.ApplicationLifetime!;
public override void Initialize()
{
_normalTrayIcon = new WindowIcon(AssetLoader.Open(new Uri("avares://FreeTubeSyncer/Assets/freetubesyncer.64.png")));
_waitingTrayIcon = new WindowIcon(AssetLoader.Open(new Uri("avares://FreeTubeSyncer/Assets/awaiting_sync.png")));
_completeTrayIcon = new WindowIcon(AssetLoader.Open(new Uri("avares://FreeTubeSyncer/Assets/sync_complete.png")));
var vm = new AppViewModel();
vm.AppIcon = _normalTrayIcon;
AvaloniaXamlLoader.Load(this);
DataContext = vm;
}
public override void OnFrameworkInitializationCompleted()
@ -159,6 +172,18 @@ public partial class App : Application
Log.Information("Log Started.");
}
private async Task UpdateSTIconHint(WindowIcon icon, string? hint = null)
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
await _semaphoreSlim.WaitAsync();
((AppViewModel)DataContext!).AppIcon = icon;
if (hint != null) ((AppViewModel)DataContext).HintTooltip = hint;
_semaphoreSlim.Release();
});
}
private async Task SyncMonitor()
{
Log.Information("Sync Monitor Starting Up.");
@ -191,6 +216,11 @@ public partial class App : Application
while (_isRunning)
{
await Task.Delay(100);
if (_syncers.Any(x => x.IsDirty()))
{
await UpdateSTIconHint(_waitingTrayIcon!, "FreeTube Syncer - Changes waiting to be written...");
}
var sinceLastCheck = DateTime.Now - lastCheck;
if (sinceLastCheck.TotalSeconds > _checkInterval.TotalSeconds)
@ -219,6 +249,7 @@ public partial class App : Application
if (procs.Length > 0) continue;
Log.Information("FreeTube instance closed, and we have writes to make...");
await Task.Delay(1500);
await UpdateSTIconHint(_waitingTrayIcon, "FreeTube Syncer - Syncing data...");
await _semaphoreSlim.WaitAsync();
var syncStart = DateTime.Now;
@ -227,6 +258,12 @@ public partial class App : Application
var syncEnd = DateTime.Now - syncStart;
_semaphoreSlim.Release();
Log.Information("Sync Completed. Total Time: {EndTime}", syncEnd);
await UpdateSTIconHint(_completeTrayIcon, "FreeTube Syncer - Sync completed.");
Task.Run(async () =>
{
await Task.Delay(3000);
await UpdateSTIconHint(_normalTrayIcon, "FreeTube Syncer - Watching files...");
});
}
Log.Information("Filesystem Sync Monitor shutdown.");

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

View file

@ -34,7 +34,8 @@
</ItemGroup>
<ItemGroup>
<None Remove="Assets\freetube.png" />
<AvaloniaXaml Include="Assets\freetube.png" />
<AvaloniaResource Include="Assets\freetubesyncer.64.png"/>
<AvaloniaResource Include="Assets\awaiting_sync.png"/>
<AvaloniaResource Include="Assets\sync_complete.png"/>
</ItemGroup>
</Project>

View file

@ -36,10 +36,7 @@ public class DBSyncWatcher
{
if (e.ChangeType != WatcherChangeTypes.Changed) return;
while (Locked)
{
Thread.Sleep(100);
}
if (Locked) return;
var dbName = Path.GetFileName(e.FullPath);

View file

@ -8,6 +8,7 @@
Width="400" Height="345"
x:Class="FreeTubeSyncer.MainWindow"
x:DataType="vm:AppSettings"
Icon="/Assets/freetubesyncer.64.png"
BackgroundStyle="GradientDarker"
CanResize="False"
CanMaximize="False"

View file

@ -0,0 +1,10 @@
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
namespace FreeTubeSyncer.Models;
public partial class AppViewModel : ObservableObject
{
[ObservableProperty] private WindowIcon? _appIcon;
[ObservableProperty] private string _hintTooltip = "FreeTube Syncer";
}

View file

@ -218,8 +218,9 @@ public class Syncer<T> : ISyncer where T : class, IDataModel, new()
foreach (var line in json)
fh.Write(Encoding.UTF8.GetBytes(line + "\n"));
fh.Flush();
fh.Close();
}
Task.Delay(100).Wait();
_watcher.Locked = false;
Log.Information("Updated {DbName}, completed in {TimeSpan}", _dbName, DateTime.Now - start);
_isDirty = false;