Updated App
Updated App.xaml to use SukiUI. Added Event Handlers for System Tray. Updated App.xaml.cs code behind file to implement Logic that was in Program.cs, into the core of the UI App. Implemented Async Tasks, to allow for UI to remain responsive, while doing long running tasks. Added Loading, Saving and Updating settings from UI updates.
This commit is contained in:
parent
e6236b8a5a
commit
7099e31ff5
2 changed files with 212 additions and 16 deletions
|
|
@ -1,22 +1,24 @@
|
|||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sukiUi="clr-namespace:SukiUI;assembly=SukiUI"
|
||||
x:Class="FreeTubeSyncer.App"
|
||||
RequestedThemeVariant="Default">
|
||||
RequestedThemeVariant="Dark">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
<sukiUi:SukiTheme ThemeColor="Blue" />
|
||||
</Application.Styles>
|
||||
|
||||
<TrayIcon.Icons>
|
||||
<TrayIcons>
|
||||
<TrayIcon Icon="/Assets/freetube.png"
|
||||
ToolTipText="FreeTube Syncer">
|
||||
ToolTipText="FreeTube Syncer"
|
||||
Clicked="TrayIcon_OnClicked">
|
||||
<TrayIcon.Menu>
|
||||
<NativeMenu>
|
||||
<NativeMenuItem Header="Show Settings"/>
|
||||
<NativeMenuItem Header="Show Settings" Click="ShowSettings_OnClick"/>
|
||||
<NativeMenuItemSeparator/>
|
||||
<NativeMenuItem Header="Quit"/>
|
||||
<NativeMenuItem Header="Quit" Click="Quit_OnClick"/>
|
||||
</NativeMenu>
|
||||
</TrayIcon.Menu>
|
||||
</TrayIcon>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
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 FreeTubeSyncer.Library;
|
||||
using FreeTubeSyncer.Models;
|
||||
using FreeTubeSyncer.Models.DatabaseModels;
|
||||
using FreeTubeSyncer.REST;
|
||||
|
||||
namespace FreeTubeSyncer;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
private DBSyncWatcher _watcher;
|
||||
private DBSyncWatcher? _watcher;
|
||||
private List<ISyncer>? _syncers;
|
||||
private Syncer<History>? _historySyncer;
|
||||
private Syncer<Playlist>? _playlistSyncer;
|
||||
private Syncer<Profile>? _profileSyncer;
|
||||
private Syncer<SearchHistory>? _searchHistorySyncer;
|
||||
private Syncer<Setting>? _settingSyncer;
|
||||
private bool _isRunning = true;
|
||||
private Task? _watcherTask;
|
||||
private DateTime _lastClick = DateTime.MinValue;
|
||||
private AppSettings? _settings;
|
||||
private string? _oldSettings;
|
||||
private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
private TimeSpan _checkInterval;
|
||||
|
||||
public event EventHandler? SettingsChanged;
|
||||
|
||||
public static App GetApp() => (App)App.Current!;
|
||||
public static ClassicDesktopStyleApplicationLifetime GetDesktop() => (ClassicDesktopStyleApplicationLifetime)App.Current!.ApplicationLifetime!;
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
|
|
@ -21,9 +46,8 @@ public partial class App : Application
|
|||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
//desktop.MainWindow = new MainWindow();
|
||||
var path = "";
|
||||
if (OperatingSystem.IsWindows())
|
||||
if (OperatingSystem.IsWindows() || OperatingSystem.IsMacOS())
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTube");
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
|
|
@ -37,17 +61,187 @@ public partial class App : Application
|
|||
Console.WriteLine("Failed to find Path for FreeTube!");
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTube");
|
||||
|
||||
LoadSettings();
|
||||
_checkInterval = TimeSpan.FromSeconds(_settings!.CheckInterval);
|
||||
|
||||
_watcher = new DBSyncWatcher(path);
|
||||
_watcher.WatchFiles.Add("history.db", typeof(History));
|
||||
_watcher.WatchFiles.Add("playlist.db", typeof(Playlist));
|
||||
_watcher.WatchFiles.Add("profiles.db", typeof(Profile));
|
||||
_watcher.WatchFiles.Add("search-history.db", typeof(SearchHistory));
|
||||
_watcher.WatchFiles.Add("settings.db", typeof(Setting));
|
||||
_historySyncer = new Syncer<History>(_watcher, Path.Join(path, "history.db"), "history.db", _settings.RestBaseUrl, "/history");
|
||||
_playlistSyncer = new Syncer<Playlist>(_watcher, Path.Join(path, "playlists.db"), "playlists.db", _settings.RestBaseUrl, "/playlist");
|
||||
_profileSyncer = new Syncer<Profile>(_watcher, Path.Join(path, "profiles.db"), "profiles.db", _settings.RestBaseUrl, "/profile");
|
||||
_searchHistorySyncer = new Syncer<SearchHistory>(_watcher, Path.Join(path, "search-history.db"), "search-history.db", _settings.RestBaseUrl, "/searchHistory");
|
||||
_settingSyncer = new Syncer<Setting>(_watcher, Path.Join(path, "settings.db"), "settings.db", _settings.RestBaseUrl, "/settings");
|
||||
_syncers =
|
||||
[
|
||||
_historySyncer,
|
||||
_playlistSyncer,
|
||||
_profileSyncer,
|
||||
_searchHistorySyncer,
|
||||
_settingSyncer
|
||||
];
|
||||
SettingsChanged += HandleSettingsChanged;
|
||||
_watcherTask = Task.Run(SyncMonitor);
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
public void StampSettings() => _oldSettings = JsonSerializer.Serialize(_settings);
|
||||
|
||||
public void ResetSettings()
|
||||
{
|
||||
var @new = JsonSerializer.Deserialize<AppSettings>(_oldSettings!);
|
||||
_settings!.RestBaseUrl = @new!.RestBaseUrl;
|
||||
_settings.CheckInterval = @new.CheckInterval;
|
||||
_settings.SyncHistory = @new.SyncHistory;
|
||||
_settings.SyncPlaylist = @new.SyncPlaylist;
|
||||
_settings.SyncProfile = @new.SyncProfile;
|
||||
_settings.SyncSearchHistory = @new.SyncSearchHistory;
|
||||
_settings.SyncSettings = @new.SyncSettings;
|
||||
}
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
var path = GetSettingsPath();
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
var dir = Path.GetDirectoryName(path);
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(_settings));
|
||||
SettingsChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void LoadSettings()
|
||||
{
|
||||
var path = GetSettingsPath();
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
_settings = new AppSettings();
|
||||
return;
|
||||
}
|
||||
var data = File.ReadAllText(path);
|
||||
_settings = JsonSerializer.Deserialize<AppSettings>(data);
|
||||
}
|
||||
|
||||
private string GetSettingsPath() => OperatingSystem.IsLinux()
|
||||
? Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FreeTubeSyncer", "settings.json")
|
||||
: Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "FreeTubeSyncer", "settings.json");
|
||||
|
||||
private async Task SyncMonitor()
|
||||
{
|
||||
while (_isRunning)
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
if (!await _syncers![0].PingApi())
|
||||
{
|
||||
_semaphoreSlim.Release();
|
||||
await Task.Delay(5000);
|
||||
continue;
|
||||
}
|
||||
foreach (var syncer in _syncers!)
|
||||
{
|
||||
await syncer.FetchDatabase();
|
||||
}
|
||||
|
||||
_semaphoreSlim.Release();
|
||||
break;
|
||||
}
|
||||
|
||||
var lastCheck = DateTime.Now;
|
||||
while (_isRunning)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
|
||||
var sinceLastCheck = DateTime.Now - lastCheck;
|
||||
if (sinceLastCheck.TotalSeconds > _checkInterval.TotalSeconds)
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
var start = DateTime.Now;
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine("Checking for updates...");
|
||||
foreach (var syncer in _syncers)
|
||||
await syncer.FetchDatabase();
|
||||
lastCheck = DateTime.Now;
|
||||
var end = DateTime.Now - start;
|
||||
_semaphoreSlim.Release();
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine($"Check Completed. Total Time: {end}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_syncers.Any(x => x.IsDirty())) continue;
|
||||
|
||||
var procs = Process.GetProcessesByName("FreeTube");
|
||||
if (procs.Length > 0) continue;
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine("FreeTube closed, and we have writes to make...");
|
||||
await Task.Delay(1500);
|
||||
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
var syncStart = DateTime.Now;
|
||||
foreach (var syncer in _syncers)
|
||||
syncer.Sync();
|
||||
var syncEnd = DateTime.Now - syncStart;
|
||||
_semaphoreSlim.Release();
|
||||
// TODO: Replace with Logger
|
||||
Console.WriteLine($"Sync completed in {syncEnd}.");
|
||||
}
|
||||
}
|
||||
|
||||
private async void HandleSettingsChanged(object? sender, EventArgs e)
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync();
|
||||
var old = JsonSerializer.Deserialize<AppSettings>(_oldSettings!);
|
||||
if (_settings!.RestBaseUrl != old!.RestBaseUrl)
|
||||
{
|
||||
foreach (var syncer in _syncers!)
|
||||
syncer.UpdateBaseUrl(_settings.RestBaseUrl);
|
||||
}
|
||||
|
||||
if (old.CheckInterval != _settings.CheckInterval) _checkInterval = TimeSpan.FromSeconds(_settings.CheckInterval);
|
||||
if (old.SyncHistory != _settings.SyncHistory) _historySyncer!.SetEnabled(_settings.SyncHistory);
|
||||
if (old.SyncPlaylist != _settings.SyncPlaylist) _playlistSyncer!.SetEnabled(_settings.SyncPlaylist);
|
||||
if (old.SyncProfile != _settings.SyncProfile) _profileSyncer!.SetEnabled(_settings.SyncProfile);
|
||||
if (old.SyncSearchHistory != _settings.SyncSearchHistory) _searchHistorySyncer!.SetEnabled(_settings.SyncSearchHistory);
|
||||
if (old.SyncSettings != _settings.SyncSettings) _settingSyncer!.SetEnabled(_settings.SyncSettings);
|
||||
_semaphoreSlim.Release();
|
||||
}
|
||||
|
||||
private void ShowSettings_OnClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (App.Current!.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return;
|
||||
if (desktop.MainWindow is null)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow()
|
||||
{
|
||||
DataContext = _settings
|
||||
};
|
||||
}
|
||||
StampSettings();
|
||||
desktop.MainWindow!.Show();
|
||||
}
|
||||
|
||||
private void Quit_OnClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (App.Current!.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return;
|
||||
_semaphoreSlim.Wait();
|
||||
_isRunning = false;
|
||||
_semaphoreSlim.Release();
|
||||
_watcherTask?.Wait();
|
||||
desktop.Shutdown();
|
||||
}
|
||||
|
||||
private void TrayIcon_OnClicked(object? sender, EventArgs e)
|
||||
{
|
||||
var clicked = DateTime.Now;
|
||||
if (_lastClick == DateTime.MinValue || (clicked - _lastClick).TotalMilliseconds > TimeSpan.FromMilliseconds(500).TotalMilliseconds)
|
||||
_lastClick = clicked;
|
||||
else
|
||||
{
|
||||
_lastClick = DateTime.MinValue;
|
||||
ShowSettings_OnClick(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue