Skip to content

Commit 1056b8d

Browse files
Add track overview panel
1 parent 4fff519 commit 1056b8d

File tree

9 files changed

+610
-0
lines changed

9 files changed

+610
-0
lines changed

.idea/.idea.MSUScripter/.idea/avalonia.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MSUScripter/Configs/Settings.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,10 @@ public class Settings
2929
public bool ProjectTreeDisplayCheckCopyrightIcon { get; set; }
3030
public bool ProjectTreeDisplayCopyrightSafeIcon { get; set; }
3131
public bool SkipDesktopFile { get; set; }
32+
public bool TrackOverviewShowIsCompleteIcon { get; set; } = true;
33+
public bool TrackOverviewShowHasSongIcon { get; set; }
34+
public bool TrackOverviewShowCheckCopyrightIcon { get; set; }
35+
public bool TrackOverviewShowCopyrightSafeIcon { get; set; }
36+
3237
public DefaultSongPanel DefaultSongPanel { get; set; } = DefaultSongPanel.Prompt;
3338
}

MSUScripter/Services/ControlServices/MsuProjectWindowService.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ public MsuProjectWindowViewModel InitViewModel(MsuProject project)
6464
ShowCheckbox = false,
6565
SortIndex = -10000,
6666
MsuDetails = true
67+
},
68+
new()
69+
{
70+
Name = "Track Overview",
71+
CollapseIcon = MaterialIconKind.ListBox,
72+
LeftSpacing = 0,
73+
ShowCheckbox = false,
74+
SortIndex = -9999,
75+
TrackOverview = true
6776
}
6877
};
6978

@@ -333,6 +342,7 @@ public void SelectedTreeItem(MsuProjectWindowViewModelTreeData treeData, bool is
333342
SaveCurrentPanel();
334343
_viewModel.CurrentTreeItem = treeData;
335344
_viewModel.BasicInfoViewModel.IsVisible = false;
345+
_viewModel.TrackOverviewPanelViewModel.IsVisible = false;
336346
_viewModel.MsuSongViewModel.BasicPanelViewModel.PyMusicLooperEnabled = pythonCompanionService.IsValid;
337347
_viewModel.MsuSongViewModel.UpdateViewModel(_project, treeData.TrackInfo!, null, treeData);
338348
}
@@ -342,6 +352,7 @@ public void SelectedTreeItem(MsuProjectWindowViewModelTreeData treeData, bool is
342352
SaveCurrentPanel();
343353
_viewModel.CurrentTreeItem = treeData;
344354
_viewModel.BasicInfoViewModel.IsVisible = false;
355+
_viewModel.TrackOverviewPanelViewModel.IsVisible = false;
345356
_viewModel.MsuSongViewModel.BasicPanelViewModel.PyMusicLooperEnabled = pythonCompanionService.IsValid;
346357
_viewModel.MsuSongViewModel.UpdateViewModel(_project, treeData.TrackInfo!, treeData.SongInfo, treeData);
347358
}
@@ -355,6 +366,19 @@ public void SelectedTreeItem(MsuProjectWindowViewModelTreeData treeData, bool is
355366
_viewModel.CurrentTreeItem = treeData;
356367
_viewModel.BasicInfoViewModel.UpdateModel(_project);
357368
_viewModel.BasicInfoViewModel.IsVisible = true;
369+
_viewModel.TrackOverviewPanelViewModel.IsVisible = false;
370+
}
371+
else if (treeData.TrackOverview)
372+
{
373+
if (_viewModel.MsuSongViewModel.IsEnabled)
374+
{
375+
_viewModel.MsuSongViewModel.SaveChanges();
376+
_viewModel.MsuSongViewModel.IsEnabled = false;
377+
}
378+
_viewModel.CurrentTreeItem = treeData;
379+
_viewModel.TrackOverviewPanelViewModel.UpdateModel(_project, Settings);
380+
_viewModel.BasicInfoViewModel.IsVisible = false;
381+
_viewModel.TrackOverviewPanelViewModel.IsVisible = true;
358382
}
359383
}
360384

@@ -799,6 +823,11 @@ await Parallel.ForEachAsync(songs,
799823
}, cancellationToken);
800824
}
801825

826+
public void SaveSettings()
827+
{
828+
settingsService.TrySaveSettings();
829+
}
830+
802831
private void HandleDragged(MsuProjectWindowViewModelTreeData from, MsuProjectWindowViewModelTreeData to)
803832
{
804833
if (_viewModel.MsuProject == null || from.TrackInfo == null || to.TrackInfo == null || from.SongInfo == null)

MSUScripter/ViewModels/MsuProjectWindowViewModel.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public class MsuProjectWindowViewModelTreeData : TranslatedViewModelBase
4444
public int ParentIndex { get; init; }
4545

4646
public bool MsuDetails { get; set; }
47+
public bool TrackOverview { get; set; }
4748
public bool Track { get; set; }
4849
public bool Song => SongInfo != null;
4950
public bool IsSongOrTrack => TrackInfo != null;
@@ -351,6 +352,7 @@ public class MsuProjectWindowViewModel : TranslatedViewModelBase
351352
public MsuProject? MsuProject { get; set; }
352353
public MsuSongOuterPanelViewModel MsuSongViewModel { get; set; } = new();
353354
public MsuBasicInfoViewModel BasicInfoViewModel { get; set; } = new();
355+
public TrackOverviewPanelViewModel TrackOverviewPanelViewModel { get; set; } = new();
354356
[Reactive] public bool IsBusy { get; set; } = false;
355357
public List<RecentProject> RecentProjects { get; set; } = [];
356358
public DefaultSongPanel DefaultSongPanel { get; set; }
@@ -368,6 +370,15 @@ public override ViewModelBase DesignerExample()
368370
Name = "MSU Details",
369371
LeftSpacing = 0,
370372
ShowCheckbox = false,
373+
MsuDetails = true
374+
},
375+
new MsuProjectWindowViewModelTreeData
376+
{
377+
CollapseIcon = MaterialIconKind.ListBox,
378+
Name = "Track Overview",
379+
LeftSpacing = 0,
380+
ShowCheckbox = false,
381+
TrackOverview = true,
371382
},
372383
new MsuProjectWindowViewModelTreeData
373384
{
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Avalonia.Media;
4+
using AvaloniaControls.Models;
5+
using Material.Icons;
6+
using MSUScripter.Configs;
7+
using ReactiveUI.Fody.Helpers;
8+
9+
namespace MSUScripter.ViewModels;
10+
11+
public class TrackOverviewPanelViewModel : ViewModelBase
12+
{
13+
[Reactive] public List<TrackOverviewRow> Rows { get; set; } = [];
14+
[Reactive] public bool IsVisible { get; set; }
15+
[Reactive] public int SelectedIndex { get; set; }
16+
[Reactive] public bool ShowCompleteColumn { get; set; } = true;
17+
[Reactive] public bool ShowCopyrightSafeColumn { get; set; } = false;
18+
[Reactive] public bool ShowCheckCopyrightColumn { get; set; } = false;
19+
[Reactive] public bool ShowHasAudioColumn { get; set; } = false;
20+
public Settings Settings { get; private set; }
21+
22+
public void UpdateModel(MsuProject project, Settings settings)
23+
{
24+
List<TrackOverviewRow> newRows = [];
25+
26+
foreach (var track in project.Tracks.Where(x => !x.IsScratchPad))
27+
{
28+
if (track.Songs.Count != 0)
29+
{
30+
newRows.AddRange(track.Songs.Select(x => new TrackOverviewRow(track, x)));
31+
}
32+
else
33+
{
34+
newRows.Add(new TrackOverviewRow(track));
35+
}
36+
}
37+
38+
Settings = settings;
39+
ShowCompleteColumn = settings.TrackOverviewShowIsCompleteIcon;
40+
ShowCopyrightSafeColumn = settings.TrackOverviewShowCopyrightSafeIcon;
41+
ShowCheckCopyrightColumn = settings.TrackOverviewShowCheckCopyrightIcon;
42+
ShowHasAudioColumn = settings.TrackOverviewShowHasSongIcon;
43+
44+
SelectedIndex = 0;
45+
Rows = newRows;
46+
}
47+
48+
public class TrackOverviewRow : ViewModelBase
49+
{
50+
public TrackOverviewRow(MsuTrackInfo track, MsuSongInfo? song = null)
51+
{
52+
Track = track;
53+
SongInfo = song;
54+
UpdateIcons();
55+
}
56+
57+
public MsuTrackInfo Track { get; }
58+
public int TrackNumber => Track.TrackNumber;
59+
public string TrackName => Track.TrackName;
60+
public MsuSongInfo? SongInfo { get; }
61+
public bool HasSong => SongInfo != null;
62+
public string Name => SongInfo?.SongName ?? "";
63+
public string Artist => SongInfo?.Artist ?? "";
64+
public string Album => SongInfo?.Album ?? "";
65+
66+
67+
[Reactive] public MaterialIconKind CompletedIconKind { get; set; } = MaterialIconKind.FlagOutline;
68+
[Reactive] public IBrush CompletedIconColor { get; set; } = Brushes.DimGray;
69+
[Reactive] public MaterialIconKind HasSongIconKind { get; set; } = MaterialIconKind.VolumeSource;
70+
[Reactive] public IBrush HasSongIconColor { get; set; } = Brushes.DimGray;
71+
[Reactive] public MaterialIconKind CheckCopyrightIconKind { get; set; } = MaterialIconKind.Video;
72+
[Reactive] public IBrush CheckCopyrightIconColor { get; set; } = Brushes.DimGray;
73+
[Reactive] public MaterialIconKind CopyrightSafeIconKind { get; set; } = MaterialIconKind.Copyright;
74+
[Reactive] public IBrush CopyrightSafeIconColor { get; set; } = Brushes.DimGray;
75+
76+
public string File =>
77+
SongInfo == null
78+
? ""
79+
: !SongInfo.MsuPcmInfo.HasFiles()
80+
? ""
81+
: SongInfo.MsuPcmInfo.GetFiles().Count == 1
82+
? SongInfo.MsuPcmInfo.GetFiles().First()
83+
: $"{SongInfo.MsuPcmInfo.GetFiles().Count} files";
84+
85+
public void UpdateIcons()
86+
{
87+
if (SongInfo == null)
88+
{
89+
return;
90+
}
91+
92+
if (SongInfo.IsComplete)
93+
{
94+
CompletedIconColor = Brushes.LimeGreen;
95+
CompletedIconKind = MaterialIconKind.Flag;
96+
}
97+
else
98+
{
99+
CompletedIconColor = Brushes.IndianRed;
100+
CompletedIconKind = MaterialIconKind.FlagOutline;
101+
}
102+
103+
if (SongInfo.HasAudioFiles())
104+
{
105+
HasSongIconColor = Brushes.LimeGreen;
106+
HasSongIconKind = MaterialIconKind.VolumeSource;
107+
}
108+
else
109+
{
110+
HasSongIconColor = Brushes.IndianRed;
111+
HasSongIconKind = MaterialIconKind.VolumeMute;
112+
}
113+
114+
if (SongInfo.CheckCopyright == true)
115+
{
116+
CheckCopyrightIconColor = Brushes.LimeGreen;
117+
CheckCopyrightIconKind = MaterialIconKind.Video;
118+
}
119+
else
120+
{
121+
CheckCopyrightIconColor = Brushes.IndianRed;
122+
CheckCopyrightIconKind = MaterialIconKind.VideoOutline;
123+
}
124+
125+
if (SongInfo.IsCopyrightSafe == true)
126+
{
127+
CopyrightSafeIconColor = Brushes.LimeGreen;
128+
CopyrightSafeIconKind = MaterialIconKind.Copyright;
129+
}
130+
else if (SongInfo.IsCopyrightSafe == false)
131+
{
132+
CopyrightSafeIconColor = Brushes.IndianRed;
133+
CopyrightSafeIconKind = MaterialIconKind.CloseCircleOutline;
134+
}
135+
else
136+
{
137+
CopyrightSafeIconColor = Brushes.Goldenrod;
138+
CopyrightSafeIconKind = MaterialIconKind.QuestionMarkCircleOutline;
139+
}
140+
}
141+
142+
public override ViewModelBase DesignerExample()
143+
{
144+
return this;
145+
}
146+
}
147+
148+
public override ViewModelBase DesignerExample()
149+
{
150+
return this;
151+
}
152+
}

MSUScripter/Views/MsuProjectWindow.axaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,19 @@
445445
IsVisible="{Binding IsVisible}"
446446
/>
447447
</Border>
448+
<Border>
449+
<views:TrackOverviewPanel
450+
x:Name="TrackOverviewPanel"
451+
DataContext="{Binding TrackOverviewPanelViewModel}"
452+
IsVisible="{Binding IsVisible}"
453+
ClickedSong="TrackOverviewPanel_OnClickedSong"
454+
AddSong="TrackOverviewPanel_OnAddSong"
455+
ToggleComplete="TrackOverviewPanel_OnToggleComplete"
456+
ToggleCopyrightSafe="TrackOverviewPanel_OnToggleCopyrightSafe"
457+
ToggleCheckCopyright="TrackOverviewPanel_OnToggleCheckCopyright"
458+
UpdatedSettings="TrackOverviewPanel_OnUpdatedSettings"
459+
/>
460+
</Border>
448461
</Grid>
449462
<controls:HeaderFooter Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
450463
<TextBlock

MSUScripter/Views/MsuProjectWindow.axaml.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,11 @@ private void ToggleCompleteButton_OnClick(object? sender, RoutedEventArgs e)
404404
}
405405

406406
_service?.UpdateCompletedFlag(treeData);
407+
408+
if (_viewModel?.TrackOverviewPanelViewModel.IsVisible == true && treeData.SongInfo != null)
409+
{
410+
TrackOverviewPanel.UpdateIconsForSong(treeData.SongInfo);
411+
}
407412

408413
e.Handled = true;
409414
}
@@ -417,6 +422,11 @@ private void ToggleCheckCopyrightButton_OnClick(object? sender, RoutedEventArgs
417422

418423
_service?.UpdateCheckCopyright(treeData);
419424

425+
if (_viewModel?.TrackOverviewPanelViewModel.IsVisible == true && treeData.SongInfo != null)
426+
{
427+
TrackOverviewPanel.UpdateIconsForSong(treeData.SongInfo);
428+
}
429+
420430
e.Handled = true;
421431
}
422432

@@ -429,6 +439,11 @@ private void ToggleCopyrightSafeButton_OnClick(object? sender, RoutedEventArgs e
429439

430440
_service?.UpdateCopyrightSafe(treeData);
431441

442+
if (_viewModel?.TrackOverviewPanelViewModel.IsVisible == true && treeData.SongInfo != null)
443+
{
444+
TrackOverviewPanel.UpdateIconsForSong(treeData.SongInfo);
445+
}
446+
432447
e.Handled = true;
433448
}
434449

@@ -794,6 +809,62 @@ private void GenerateTracksJsonMenuItem_OnClick(object? sender, RoutedEventArgs
794809
_ = ShowError(errorMessage);
795810
}
796811
}
812+
813+
private void TrackOverviewPanel_OnAddSong(object? sender, (MsuTrackInfo Track, MsuSongInfo? Song) e)
814+
{
815+
var treeItem = _viewModel?.TreeItems.FirstOrDefault(x => x.TrackInfo == e.Track && x.SongInfo == e.Song);
816+
if (treeItem == null)
817+
{
818+
return;
819+
}
820+
AddNewSong(treeItem);
821+
}
822+
823+
private void TrackOverviewPanel_OnClickedSong(object? sender, (MsuTrackInfo Track, MsuSongInfo? Song) e)
824+
{
825+
var treeItem = _viewModel?.TreeItems.FirstOrDefault(x => x.TrackInfo == e.Track && x.SongInfo == e.Song);
826+
if (treeItem == null)
827+
{
828+
return;
829+
}
830+
_service?.SelectedTreeItem(treeItem, false);
831+
_viewModel!.SelectedTreeItem = treeItem;
832+
}
833+
834+
private void TrackOverviewPanel_OnToggleComplete(object? sender, (MsuTrackInfo Track, MsuSongInfo? Song) e)
835+
{
836+
var treeItem = _viewModel?.TreeItems.FirstOrDefault(x => x.TrackInfo == e.Track && x.SongInfo == e.Song);
837+
if (treeItem == null)
838+
{
839+
return;
840+
}
841+
_service?.UpdateCompletedFlag(treeItem);
842+
}
843+
844+
private void TrackOverviewPanel_OnToggleCopyrightSafe(object? sender, (MsuTrackInfo Track, MsuSongInfo? Song) e)
845+
{
846+
var treeItem = _viewModel?.TreeItems.FirstOrDefault(x => x.TrackInfo == e.Track && x.SongInfo == e.Song);
847+
if (treeItem == null)
848+
{
849+
return;
850+
}
851+
_service?.UpdateCopyrightSafe(treeItem);
852+
}
853+
854+
private void TrackOverviewPanel_OnToggleCheckCopyright(object? sender, (MsuTrackInfo Track, MsuSongInfo? Song) e)
855+
{
856+
var treeItem = _viewModel?.TreeItems.FirstOrDefault(x => x.TrackInfo == e.Track && x.SongInfo == e.Song);
857+
if (treeItem == null)
858+
{
859+
return;
860+
}
861+
_service?.UpdateCheckCopyright(treeItem);
862+
}
863+
864+
private void TrackOverviewPanel_OnUpdatedSettings(object? sender, EventArgs e)
865+
{
866+
_service?.SaveSettings();
867+
}
797868
}
798869

799870
public enum MsuProjectWindowCloseReason

0 commit comments

Comments
 (0)