Skip to content

Commit

Permalink
refactor(Notification::Menu): Implement property updated for the Data…
Browse files Browse the repository at this point in the history
…Container of the menu item
  • Loading branch information
Belphemur committed Aug 24, 2021
1 parent 5741cfd commit ee77ecb
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 54 deletions.
8 changes: 4 additions & 4 deletions SoundSwitch/Framework/Audio/Lister/CachedAudioDeviceLister.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ namespace SoundSwitch.Framework.Audio.Lister
public class CachedAudioDeviceLister : IAudioDeviceLister
{
/// <inheritdoc />
public DeviceReadOnlyCollection<DeviceFullInfo> PlaybackDevices { get; private set; } = new(Enumerable.Empty<DeviceFullInfo>());
public DeviceReadOnlyCollection<DeviceFullInfo> PlaybackDevices { get; private set; } = new(Enumerable.Empty<DeviceFullInfo>(), DataFlow.Render);

/// <inheritdoc />
public DeviceReadOnlyCollection<DeviceFullInfo> RecordingDevices { get; private set; } = new(Enumerable.Empty<DeviceFullInfo>());
public DeviceReadOnlyCollection<DeviceFullInfo> RecordingDevices { get; private set; } = new(Enumerable.Empty<DeviceFullInfo>(), DataFlow.Capture);

private readonly DeviceState _state;
private readonly DebounceDispatcher _dispatcher = new();
Expand Down Expand Up @@ -87,8 +87,8 @@ public void Refresh()
}
}

PlaybackDevices = new DeviceReadOnlyCollection<DeviceFullInfo>(playbackDevices.Values);
RecordingDevices = new DeviceReadOnlyCollection<DeviceFullInfo>(recordingDevices.Values);
PlaybackDevices = new DeviceReadOnlyCollection<DeviceFullInfo>(playbackDevices.Values, DataFlow.Render);
RecordingDevices = new DeviceReadOnlyCollection<DeviceFullInfo>(recordingDevices.Values, DataFlow.Capture);


Log.Information("[{@State}] Refreshed all devices. {@Recording}/rec, {@Playback}/play", _state, recordingDevices.Count, playbackDevices.Count);
Expand Down
2 changes: 1 addition & 1 deletion SoundSwitch/Framework/Banner/BannerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void ShowNotification(BannerData data)
menu.Disposed += (sender, args) => menu = null;
}

menu.SetData(AppModel.Instance.AvailablePlaybackDevices.Select(info => new AudioDeviceBox.Data(info.LargeIcon.ToBitmap(), info.NameClean, defaultDevice.Id == info.Id)));
menu.SetData(AppModel.Instance.AvailablePlaybackDevices.Select(info => new IconMenuItem.DataContainer(info.LargeIcon, info.NameClean, defaultDevice.Id == info.Id, info.Id)));
if (banner == null)
{
banner = new BannerForm();
Expand Down
32 changes: 0 additions & 32 deletions SoundSwitch/UI/Forms/Components/AudioDeviceBox.cs

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions SoundSwitch/UI/Forms/Components/IconMenuItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
using JetBrains.Annotations;
using SoundSwitch.Util;

namespace SoundSwitch.UI.Forms.Components
{
public partial class IconMenuItem : UserControl
{
public DataContainer CurrentDataContainer { get; }

public class DataContainer : INotifyPropertyChanged
{
private bool _selected;
private Image _image;
private string _label;
private Icon _icon;

public bool Selected
{
get => _selected;
set
{
_selected = value;
OnPropertyChanged();
OnPropertyChanged(nameof(Color));
}
}

public Image Image
{
get { return _image ??= _icon.ToBitmap(); }
}

public string Label
{
get => _label;
set
{
_label = value;
OnPropertyChanged();
}
}

public Icon Icon
{
get => _icon;
set
{
_icon = value;
OnPropertyChanged();
var oldImage = _image;
_image = null;
OnPropertyChanged(nameof(Image));
oldImage?.Dispose();
}
}

public string Id { get; }
public Color Color => Selected ? Color.RoyalBlue.WithOpacity(0x80) : Color.Black.WithOpacity(0x70);

public DataContainer(Icon icon, string label, bool selected, string id)
{
Selected = selected;
Icon = icon;
Label = label;
Id = id;
}

/// <summary>
/// Override the metadata part
/// </summary>
/// <param name="dataContainer"/>
public void OverrideMetadata(DataContainer dataContainer)
{
if (dataContainer.Id != Id)
{
throw new ArgumentException("Need to have the same ID", nameof(dataContainer));
}

if (Selected != dataContainer.Selected)
Selected = dataContainer.Selected;
if (Icon != dataContainer.Icon)
Icon = dataContainer.Icon;
if (Label != dataContainer.Label)
Label = dataContainer.Label;
}

public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}


public IconMenuItem(DataContainer dataContainer)
{
CurrentDataContainer = dataContainer;
InitializeComponent();

base.CreateParams.ExStyle |= 0x20;
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
iconBox.BackColor = Color.Transparent;
deviceName.BackColor = Color.Transparent;
Name = CurrentDataContainer.Id;

iconBox.DataBindings.Add(nameof(PictureBox.Image), CurrentDataContainer, nameof(CurrentDataContainer.Image), false, DataSourceUpdateMode.OnPropertyChanged);
deviceName.DataBindings.Add(nameof(Label.Text), CurrentDataContainer, nameof(CurrentDataContainer.Label), false, DataSourceUpdateMode.OnPropertyChanged);
DataBindings.Add(nameof(BackColor), CurrentDataContainer, nameof(CurrentDataContainer.Color), false, DataSourceUpdateMode.OnPropertyChanged);
}
}
}
63 changes: 51 additions & 12 deletions SoundSwitch/UI/Forms/DeviceSelectorMenu.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using SoundSwitch.UI.Forms.Components;

namespace SoundSwitch.UI.Forms
{
public partial class DeviceSelectorMenu : Form
{
private readonly Dictionary<string, IconMenuItem.DataContainer> _currentPayloads = new();
private readonly object _lock = new();
protected override bool ShowWithoutActivation => true;

/// <summary>
Expand All @@ -28,21 +31,57 @@ public DeviceSelectorMenu()
InitializeComponent();
}

public void SetData(IEnumerable<AudioDeviceBox.Data> payloads)
public void SetData(IEnumerable<IconMenuItem.DataContainer> payloads)
{
Hide();
SetLocationToCursor();
Controls.Clear();
Height = 0;
var top = 5;
foreach (var payload in payloads)
lock (_lock)
{
var control = new AudioDeviceBox(payload);
control.Top = top;
Controls.Add(control);
top += control.Height;
SetLocationToCursor();
var top = 5;

var payloadsArray = payloads.ToArray();
var newPayloads = payloadsArray.ToDictionary(container => container.Id);
var toRemove = _currentPayloads.Keys.Except(newPayloads.Keys);
var toAdd = newPayloads.Keys.Except(_currentPayloads.Keys);
var toModify = _currentPayloads.Keys.Intersect(newPayloads.Keys);

var needRearrange = false;

foreach (var id in toRemove)
{
Controls.RemoveByKey(id);
_currentPayloads.Remove(id);
needRearrange = true;
}

foreach (var key in toModify)
{
_currentPayloads[key].OverrideMetadata(newPayloads[key]);
}


foreach (var key in toAdd)
{
var payload = newPayloads[key];
var control = new IconMenuItem(payload);
Controls.Add(control);
_currentPayloads.Add(payload.Id, payload);
needRearrange = true;
}

if (needRearrange)
{
foreach (var payload in payloadsArray)
{
var control = Controls[payload.Id];
control.Top = top;
top += control.Height;
}
Height = 0;
}


Show();
}
Show();
}

private void SetLocationToCursor()
Expand Down

0 comments on commit ee77ecb

Please sign in to comment.