Skip to content

Commit

Permalink
asd
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyrrrz committed Mar 28, 2024
1 parent c7803f5 commit ae91076
Show file tree
Hide file tree
Showing 36 changed files with 295 additions and 304 deletions.
13 changes: 7 additions & 6 deletions LightBulb.Core/SolarTimes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace LightBulb.Core;

// Times are presented in the current timezone, which is a flimsy convention
public readonly record struct SolarTimes(TimeOnly Sunrise, TimeOnly Sunset)
{
private static double DegreesToRadians(double degree) => degree * (Math.PI / 180);
Expand All @@ -11,7 +12,7 @@ public readonly record struct SolarTimes(TimeOnly Sunrise, TimeOnly Sunset)

private static TimeOnly CalculateSolarTime(
GeoLocation location,
DateTimeOffset date,
DateTimeOffset instant,
double zenith,
bool isSunrise
)
Expand All @@ -21,7 +22,7 @@ bool isSunrise
// Convert longitude to hour value and calculate an approximate time
var lngHours = location.Longitude / 15;
var timeApproxHours = isSunrise ? 6 : 18;
var timeApproxDays = date.DayOfYear + (timeApproxHours - lngHours) / 24;
var timeApproxDays = instant.DayOfYear + (timeApproxHours - lngHours) / 24;

// Calculate Sun's mean anomaly
var sunMeanAnomaly = 0.9856 * timeApproxDays - 3.289;
Expand Down Expand Up @@ -75,14 +76,14 @@ bool isSunrise

// Adjust UTC time to local time
// (we use the provided offset because it's impossible to calculate timezone from coordinates)
var localHours = (utcHours + date.Offset.TotalHours).Wrap(0, 24);
var localHours = (utcHours + instant.Offset.TotalHours).Wrap(0, 24);

return TimeOnly.FromTimeSpan(TimeSpan.FromHours(localHours));
}

public static SolarTimes Calculate(GeoLocation location, DateTimeOffset date) =>
public static SolarTimes Calculate(GeoLocation location, DateTimeOffset instant) =>
new(
CalculateSolarTime(location, date, 90.83, true),
CalculateSolarTime(location, date, 90.83, false)
CalculateSolarTime(location, instant, 90.83, true),
CalculateSolarTime(location, instant, 90.83, false)
);
}
2 changes: 1 addition & 1 deletion LightBulb.WindowsApi/DeviceContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public partial class DeviceContext(nint handle) : NativeResource(handle)
private void SetGammaRamp(GammaRamp ramp)
{
if (!NativeMethods.SetDeviceGammaRamp(Handle, ref ramp))
Debug.WriteLine($"Failed to set gamma ramp on device context #${Handle}).");
Debug.WriteLine($"Failed to set gamma ramp on device context #{Handle}).");
}

public void SetGamma(double redMultiplier, double greenMultiplier, double blueMultiplier)
Expand Down
3 changes: 2 additions & 1 deletion LightBulb/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:materialStyles="clr-namespace:Material.Styles.Themes;assembly=Material.Styles">
<Application.DataTemplates>
<framework:ViewBinder />
<framework:ViewManager />
</Application.DataTemplates>

<Application.Styles>
Expand Down Expand Up @@ -98,6 +98,7 @@
</Style>
</Application.Styles>

<!-- Tray icon -->
<TrayIcon.Icons>
<TrayIcons>
<TrayIcon
Expand Down
12 changes: 6 additions & 6 deletions LightBulb/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public App()

// View model framework
services.AddSingleton<DialogManager>();
services.AddSingleton<ViewModelProvider>();
services.AddSingleton<ViewModelManager>();

// View models
services.AddTransient<MainViewModel>();
Expand All @@ -48,10 +48,10 @@ public App()
services.AddTransient<SettingsTabViewModelBase, LocationSettingsTabViewModel>();

// View framework
services.AddSingleton<ViewBinder>();
services.AddSingleton<ViewManager>();

_services = services.BuildServiceProvider(true);
_mainViewModel = _services.GetRequiredService<MainViewModel>();
_mainViewModel = _services.GetRequiredService<ViewModelManager>().CreateMainViewModel();
}

public override void Initialize() => AvaloniaXamlLoader.Load(this);
Expand Down Expand Up @@ -101,9 +101,6 @@ private void ToggleMenuItem_OnClick(object? sender, EventArgs args) =>
private void DisableUntilSunriseMenuItem_OnClick(object? sender, EventArgs args) =>
_mainViewModel.Dashboard.DisableUntilSunriseCommand.Execute(null);

private void ExitMenuItem_OnClick(object? sender, EventArgs args) =>
ApplicationLifetime?.TryShutdown();

private void DisableTemporarily1DayMenuItem_OnClick(object? sender, EventArgs args) =>
_mainViewModel.Dashboard.DisableTemporarilyCommand.Execute(TimeSpan.FromDays(1));

Expand All @@ -128,5 +125,8 @@ private void DisableTemporarily5MinutesMenuItem_OnClick(object? sender, EventArg
private void DisableTemporarily1MinuteMenuItem_OnClick(object? sender, EventArgs args) =>
_mainViewModel.Dashboard.DisableTemporarilyCommand.Execute(TimeSpan.FromMinutes(1));

private void ExitMenuItem_OnClick(object? sender, EventArgs args) =>
ApplicationLifetime?.TryShutdown();

public void Dispose() => _services.Dispose();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

namespace LightBulb.Converters;

public class SettingsTabViewModelToMaterialIconKindConverter : IValueConverter
public class SettingsTabToMaterialIconKindConverter : IValueConverter
{
public static SettingsTabViewModelToMaterialIconKindConverter Instance { get; } = new();
public static SettingsTabToMaterialIconKindConverter Instance { get; } = new();

public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) =>
value switch
Expand Down
37 changes: 13 additions & 24 deletions LightBulb/Framework/DialogManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,31 @@

namespace LightBulb.Framework;

public class DialogManager(ViewBinder viewBinder) : IDisposable
public class DialogManager : IDisposable
{
private readonly SemaphoreSlim _dialogLock = new(1, 1);

public async Task<T?> ShowDialogAsync<T>(DialogViewModelBase<T> dialog)
{
var view = viewBinder.TryBindView(dialog);
if (view is null)
{
throw new InvalidOperationException(
$"View not found for dialog view model '{dialog.GetType()}'."
);
}

await _dialogLock.WaitAsync();
try
{
await DialogHost.Show(
view,
(object openSender, DialogOpenedEventArgs openArgs) =>
dialog,
// It's fine to await in a void method here because it's an event handler
// ReSharper disable once AsyncVoidLambda
async (object _, DialogOpenedEventArgs args) =>
{
void OnClosed(object? closedSender, EventArgs closedArgs)
{
try
{
openArgs.Session.Close();
}
catch (InvalidOperationException)
{
// Race condition: dialog is already being closed
}
await dialog.WaitForCloseAsync();

dialog.Closed -= OnClosed;
try
{
args.Session.Close();
}
catch (InvalidOperationException)
{
// Dialog host is already processing a close operation
}

dialog.Closed += OnClosed;
}
);

Expand Down
11 changes: 7 additions & 4 deletions LightBulb/Framework/DialogViewModelBase.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace LightBulb.Framework;

public abstract partial class DialogViewModelBase<T> : ViewModelBase
{
private readonly TaskCompletionSource<T> _closeTcs =
new(TaskCreationOptions.RunContinuationsAsynchronously);

[ObservableProperty]
private T? _dialogResult;

public event EventHandler? Closed;

[RelayCommand]
protected void Close(T dialogResult)
{
DialogResult = dialogResult;
Closed?.Invoke(this, EventArgs.Empty);
_closeTcs.TrySetResult(dialogResult);
}

public async Task<T> WaitForCloseAsync() => await _closeTcs.Task;
}

public abstract class DialogViewModelBase : DialogViewModelBase<bool?>;
8 changes: 5 additions & 3 deletions LightBulb/Framework/UserControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ public class UserControl<TDataContext> : UserControl
public new TDataContext DataContext
{
get =>
(TDataContext)(
base.DataContext ?? throw new InvalidOperationException("DataContext is null.")
);
base.DataContext is TDataContext dataContext
? dataContext
: throw new InvalidCastException(
$"DataContext is null or not of the expected type '{typeof(TDataContext).FullName}'."
);
set => base.DataContext = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace LightBulb.Framework;

public partial class ViewBinder
public partial class ViewManager
{
public Control? TryBindView(ViewModelBase viewModel)
{
Expand All @@ -20,8 +20,7 @@ public partial class ViewBinder
if (type is null)
return null;

var view = Activator.CreateInstance(type) as Control;
if (view is null)
if (Activator.CreateInstance(type) is not Control view)
return null;

view.DataContext ??= viewModel;
Expand All @@ -30,7 +29,7 @@ public partial class ViewBinder
}
}

public partial class ViewBinder : IDataTemplate
public partial class ViewManager : IDataTemplate
{
bool IDataTemplate.Match(object? data) => data is ViewModelBase;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

namespace LightBulb.Framework;

public class ViewModelProvider(IServiceProvider services)
public class ViewModelManager(IServiceProvider services)
{
public MainViewModel GetMainViewModel() => services.GetRequiredService<MainViewModel>();
public MainViewModel CreateMainViewModel() => services.GetRequiredService<MainViewModel>();

public DashboardViewModel GetDashboardViewModel() =>
public DashboardViewModel CreateDashboardViewModel() =>
services.GetRequiredService<DashboardViewModel>();

public MessageBoxViewModel GetMessageBoxViewModel(
public MessageBoxViewModel CreateMessageBoxViewModel(
string title,
string message,
string? okButtonText,
Expand All @@ -30,6 +30,6 @@ public MessageBoxViewModel GetMessageBoxViewModel(
return viewModel;
}

public SettingsViewModel GetSettingsViewModel() =>
public SettingsViewModel CreateSettingsViewModel() =>
services.GetRequiredService<SettingsViewModel>();
}
8 changes: 5 additions & 3 deletions LightBulb/Framework/Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ public class Window<TDataContext> : Window
public new TDataContext DataContext
{
get =>
(TDataContext)(
base.DataContext ?? throw new InvalidOperationException("DataContext is null.")
);
base.DataContext is TDataContext dataContext
? dataContext
: throw new InvalidCastException(
$"DataContext is null or not of the expected type '{typeof(TDataContext).FullName}'."
);
set => base.DataContext = value;
}
}
2 changes: 1 addition & 1 deletion LightBulb/LightBulb.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<PackageReference Include="Material.Avalonia" Version="3.4.2" />
<PackageReference Include="Material.Icons.Avalonia" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Onova" Version="2.6.10" Condition="$([MSBuild]::IsOsPlatform('Windows'))" />
<PackageReference Include="Onova" Version="2.6.10" />
</ItemGroup>

</Project>
11 changes: 6 additions & 5 deletions LightBulb/Models/ExternalApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace LightBulb.Models;

public partial class ExternalApplication(string executableFilePath)
{
public string ExecutableFilePath { get; } = executableFilePath;
public string ExecutableFilePath { get; } = NormalizeFilePath(executableFilePath);

public string Name => Path.GetFileNameWithoutExtension(ExecutableFilePath);

Expand All @@ -14,7 +14,7 @@ public partial class ExternalApplication(string executableFilePath)

public partial class ExternalApplication
{
private static string? NormalizeFilePath(string? filePath) =>
private static string NormalizeFilePath(string filePath) =>
!string.IsNullOrWhiteSpace(filePath) ? Path.GetFullPath(filePath) : filePath;
}

Expand All @@ -28,8 +28,8 @@ public bool Equals(ExternalApplication? other)
return true;

return string.Equals(
NormalizeFilePath(ExecutableFilePath),
NormalizeFilePath(other.ExecutableFilePath),
ExecutableFilePath,
other.ExecutableFilePath,
StringComparison.OrdinalIgnoreCase
);
}
Expand All @@ -44,7 +44,8 @@ public override bool Equals(object? obj)
return obj.GetType() == GetType() && Equals((ExternalApplication)obj);
}

public override int GetHashCode() => HashCode.Combine(NormalizeFilePath(ExecutableFilePath));
public override int GetHashCode() =>
StringComparer.OrdinalIgnoreCase.GetHashCode(ExecutableFilePath);

public static bool operator ==(ExternalApplication? a, ExternalApplication? b) =>
a?.Equals(b) ?? false;
Expand Down
Loading

0 comments on commit ae91076

Please sign in to comment.