Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add mock UI for file syncing listing #60

Merged
merged 5 commits into from
Mar 25, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions App/App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.1" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.6.250108002" />
<PackageReference Include="WinUIEx" Version="2.5.1" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 7 additions & 1 deletion App/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
<Application
x:Class="Coder.Desktop.App.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:Coder.Desktop.App.Converters">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</ResourceDictionary.MergedDictionaries>

<converters:InverseBoolConverter x:Key="InverseBoolConverter" />
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converters:InverseBoolToVisibilityConverter x:Key="InverseBoolToVisibilityConverter" />
<converters:FriendlyByteConverter x:Key="FriendlyByteConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
5 changes: 2 additions & 3 deletions App/Controls/SizedFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ public class SizedFrameEventArgs : EventArgs

/// <summary>
/// SizedFrame extends Frame by adding a SizeChanged event, which will be triggered when:
/// - The contained Page's content's size changes
/// - We switch to a different page.
///
/// - The contained Page's content's size changes
/// - We switch to a different page.
/// Sadly this is necessary because Window.Content.SizeChanged doesn't trigger when the Page's content changes.
/// </summary>
public class SizedFrame : Frame
Expand Down
33 changes: 0 additions & 33 deletions App/Converters/AgentStatusToColorConverter.cs

This file was deleted.

155 changes: 155 additions & 0 deletions App/Converters/DependencyObjectSelector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
using System;
using System.Linq;
using Windows.Foundation.Collections;
using Windows.UI.Xaml.Markup;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;

namespace Coder.Desktop.App.Converters;

// This file uses manual DependencyProperty properties rather than
// DependencyPropertyGenerator since it doesn't seem to work properly with
// generics.

public class DependencyObjectSelectorItem<TK, TV> : DependencyObject
where TK : IEquatable<TK>
{
public static readonly DependencyProperty KeyProperty =
DependencyProperty.Register(nameof(Key),
typeof(TK?),
typeof(DependencyObjectSelectorItem<TK, TV>),
new PropertyMetadata(null));

public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value),
typeof(TV?),
typeof(DependencyObjectSelectorItem<TK, TV>),
new PropertyMetadata(null));

public TK? Key
{
get => (TK?)GetValue(KeyProperty);
set => SetValue(KeyProperty, value);
}

public TV? Value
{
get => (TV?)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
}

[ContentProperty(Name = nameof(References))]
public class DependencyObjectSelector<TK, TV> : DependencyObject
where TK : IEquatable<TK>
{
public static readonly DependencyProperty ReferencesProperty =
DependencyProperty.Register(nameof(References),
typeof(DependencyObjectCollection),
typeof(DependencyObjectSelector<TK, TV>),
new PropertyMetadata(null, ReferencesPropertyChanged));

public static readonly DependencyProperty SelectedKeyProperty =
DependencyProperty.Register(nameof(SelectedKey),
typeof(TK?),
typeof(DependencyObjectSelector<TK, TV>),
new PropertyMetadata(null, SelectedPropertyChanged));

public static readonly DependencyProperty SelectedObjectProperty =
DependencyProperty.Register(nameof(SelectedObject),
typeof(TV?),
typeof(DependencyObjectSelector<TK, TV>),
new PropertyMetadata(null));

public DependencyObjectCollection? References
{
get => (DependencyObjectCollection?)GetValue(ReferencesProperty);
set
{
// Ensure unique keys and that the values are DependencyObjectSelectorItem<K, V>.
if (value != null)
{
var items = value.OfType<DependencyObjectSelectorItem<TK, TV>>().ToArray();
var keys = items.Select(i => i.Key).Distinct().ToArray();
if (keys.Length != value.Count)
throw new ArgumentException("ObservableCollection Keys must be unique.");
}

SetValue(ReferencesProperty, value);
}
}

public TK? SelectedKey
{
get => (TK?)GetValue(SelectedKeyProperty);
set => SetValue(SelectedKeyProperty, value);
}

public TV? SelectedObject
{
get => (TV?)GetValue(SelectedObjectProperty);
set => SetValue(SelectedObjectProperty, value);
}

public DependencyObjectSelector()
{
References = [];
}

private void OnVectorChangedReferences(IObservableVector<DependencyObject> sender, IVectorChangedEventArgs args)
{
UpdateSelectedObject();
}

private void UpdateSelectedObject()
{
if (References != null)
{
var references = References.OfType<DependencyObjectSelectorItem<TK, TV>>().ToArray();
var item = references
.FirstOrDefault(i =>
(i.Key == null && SelectedKey == null) ||
(i.Key != null && SelectedKey != null && i.Key!.Equals(SelectedKey!)))
?? references.FirstOrDefault(i => i.Key == null);
if (item is not null)
{
BindingOperations.SetBinding
(
this,
SelectedObjectProperty,
new Binding
{
Source = item,
Path = new PropertyPath(nameof(DependencyObjectSelectorItem<TK, TV>.Value)),
}
);
return;
}
}

ClearValue(SelectedObjectProperty);
}

private static void ReferencesPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var self = obj as DependencyObjectSelector<TK, TV>;
if (self == null) return;
var oldValue = args.OldValue as DependencyObjectCollection;
if (oldValue != null)
oldValue.VectorChanged -= self.OnVectorChangedReferences;
var newValue = args.NewValue as DependencyObjectCollection;
if (newValue != null)
newValue.VectorChanged += self.OnVectorChangedReferences;
}

private static void SelectedPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var self = obj as DependencyObjectSelector<TK, TV>;
self?.UpdateSelectedObject();
}
}

public sealed class StringToBrushSelectorItem : DependencyObjectSelectorItem<string, Brush>;

public sealed class StringToBrushSelector : DependencyObjectSelector<string, Brush>;
43 changes: 43 additions & 0 deletions App/Converters/FriendlyByteConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using Microsoft.UI.Xaml.Data;

namespace Coder.Desktop.App.Converters;

public class FriendlyByteConverter : IValueConverter
{
private static readonly string[] Suffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];

public object Convert(object value, Type targetType, object parameter, string language)
{
switch (value)
{
case int i:
if (i < 0) i = 0;
return FriendlyBytes((ulong)i);
case uint ui:
return FriendlyBytes(ui);
case long l:
if (l < 0) l = 0;
return FriendlyBytes((ulong)l);
case ulong ul:
return FriendlyBytes(ul);
default:
return FriendlyBytes(0);
}
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}

public static string FriendlyBytes(ulong bytes)
{
if (bytes == 0)
return $"0 {Suffixes[0]}";

var place = System.Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
var num = Math.Round(bytes / Math.Pow(1024, place), 1);
return $"{num} {Suffixes[place]}";
}
}
17 changes: 17 additions & 0 deletions App/Converters/InverseBoolConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using Microsoft.UI.Xaml.Data;

namespace Coder.Desktop.App.Converters;

public class InverseBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value is false;
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
12 changes: 12 additions & 0 deletions App/Converters/InverseBoolToVisibilityConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.UI.Xaml;

namespace Coder.Desktop.App.Converters;

public partial class InverseBoolToVisibilityConverter : BoolToObjectConverter
{
public InverseBoolToVisibilityConverter()
{
TrueValue = Visibility.Collapsed;
FalseValue = Visibility.Visible;
}
}
Loading
Loading