Add - Added edit button for history overview and series

Chg - Detect special episodes in series to ignore them from new episodes
Chg - History always tries to take the original version to not have multiple versions of the same season

Fix - Updater failed because it couldn't update itself (for the fix you need to download the new updater)
This commit is contained in:
Elwador 2024-05-11 13:08:24 +02:00
parent 76ddd9241a
commit 3e33843bc0
8 changed files with 197 additions and 73 deletions

View file

@ -137,7 +137,7 @@ public class CrSeries(Crunchyroll crunInstance){
var s = result[season][key]; var s = result[season][key];
if (data?.S != null && s.Id != data.Value.S) continue; if (data?.S != null && s.Id != data.Value.S) continue;
int fallbackIndex = 0; int fallbackIndex = 0;
var seasonData = await GetSeasonDataById(s); var seasonData = await GetSeasonDataById(s.Id);
if (seasonData.Data != null){ if (seasonData.Data != null){
if (crunInstance.CrunOptions.History){ if (crunInstance.CrunOptions.History){
@ -268,7 +268,7 @@ public class CrSeries(Crunchyroll crunInstance){
return crunchySeriesList; return crunchySeriesList;
} }
public async Task<CrunchyEpisodeList> GetSeasonDataById(SeriesSearchItem item, bool log = false){ public async Task<CrunchyEpisodeList> GetSeasonDataById(string seasonID, bool log = false){
CrunchyEpisodeList episodeList = new CrunchyEpisodeList(){ Data = new List<CrunchyEpisode>(), Total = 0, Meta = new Meta() }; CrunchyEpisodeList episodeList = new CrunchyEpisodeList(){ Data = new List<CrunchyEpisode>(), Total = 0, Meta = new Meta() };
if (crunInstance.CmsToken?.Cms == null){ if (crunInstance.CmsToken?.Cms == null){
@ -277,7 +277,7 @@ public class CrSeries(Crunchyroll crunInstance){
} }
if (log){ if (log){
var showRequest = HttpClientReq.CreateRequestMessage($"{Api.Cms}/seasons/{item.Id}?preferred_audio_language=ja-JP", HttpMethod.Get, true, true, null); var showRequest = HttpClientReq.CreateRequestMessage($"{Api.Cms}/seasons/{seasonID}?preferred_audio_language=ja-JP", HttpMethod.Get, true, true, null);
var response = await HttpClientReq.Instance.SendHttpRequest(showRequest); var response = await HttpClientReq.Instance.SendHttpRequest(showRequest);
@ -290,7 +290,7 @@ public class CrSeries(Crunchyroll crunInstance){
//TODO //TODO
var episodeRequest = new HttpRequestMessage(HttpMethod.Get, $"{Api.Cms}/seasons/{item.Id}/episodes?preferred_audio_language=ja-JP"); var episodeRequest = new HttpRequestMessage(HttpMethod.Get, $"{Api.Cms}/seasons/{seasonID}/episodes?preferred_audio_language=ja-JP");
episodeRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", crunInstance.Token?.access_token); episodeRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", crunInstance.Token?.access_token);

View file

@ -20,7 +20,7 @@ namespace CRD.Downloader;
public class History(Crunchyroll crunInstance){ public class History(Crunchyroll crunInstance){
public async Task UpdateSeries(string seriesId, string? seasonId){ public async Task UpdateSeries(string seriesId, string? seasonId){
await crunInstance.CrAuth.RefreshToken(true); await crunInstance.CrAuth.RefreshToken(true);
CrSeriesSearch? parsedSeries = await crunInstance.CrSeries.ParseSeriesById(seriesId, "ja"); CrSeriesSearch? parsedSeries = await crunInstance.CrSeries.ParseSeriesById(seriesId, "ja");
if (parsedSeries == null){ if (parsedSeries == null){
@ -35,7 +35,20 @@ public class History(Crunchyroll crunInstance){
foreach (var key in result[season].Keys){ foreach (var key in result[season].Keys){
var s = result[season][key]; var s = result[season][key];
if (!string.IsNullOrEmpty(seasonId) && s.Id != seasonId) continue; if (!string.IsNullOrEmpty(seasonId) && s.Id != seasonId) continue;
var seasonData = await crunInstance.CrSeries.GetSeasonDataById(s);
var sId = s.Id;
if (s.Versions is{ Count: > 0 }){
foreach (var sVersion in s.Versions){
if (sVersion.Original == true){
if (sVersion.Guid != null){
sId = sVersion.Guid;
}
break;
}
}
}
var seasonData = await crunInstance.CrSeries.GetSeasonDataById(sId);
UpdateWithSeasonData(seasonData); UpdateWithSeasonData(seasonData);
} }
} }
@ -107,7 +120,7 @@ public class History(Crunchyroll crunInstance){
historySeries.Seasons.Add(newSeason); historySeries.Seasons.Add(newSeason);
historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum).ToList(); historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum != null ? int.Parse(s.SeasonNum) : 0).ToList();
} }
historySeries.UpdateNewEpisodes(); historySeries.UpdateNewEpisodes();
} else{ } else{
@ -148,15 +161,24 @@ public class History(Crunchyroll crunInstance){
if (historySeason != null){ if (historySeason != null){
foreach (var crunchyEpisode in seasonData.Data){ foreach (var crunchyEpisode in seasonData.Data){
if (historySeason.EpisodesList.All(e => e.EpisodeId != crunchyEpisode.Id)){
var historyEpisode = historySeason.EpisodesList.Find(e => e.EpisodeId == crunchyEpisode.Id);
if (historyEpisode == null){
var newHistoryEpisode = new HistoryEpisode{ var newHistoryEpisode = new HistoryEpisode{
EpisodeTitle = crunchyEpisode.Title, EpisodeTitle = crunchyEpisode.Title,
EpisodeId = crunchyEpisode.Id, EpisodeId = crunchyEpisode.Id,
Episode = crunchyEpisode.Episode, Episode = crunchyEpisode.Episode,
SpecialEpisode = !int.TryParse(crunchyEpisode.Episode, out _),
}; };
historySeason.EpisodesList.Add(newHistoryEpisode); historySeason.EpisodesList.Add(newHistoryEpisode);
} else{
//Update existing episode
historyEpisode.EpisodeTitle = crunchyEpisode.Title;
historyEpisode.SpecialEpisode = !int.TryParse(crunchyEpisode.Episode, out _);
} }
} }
historySeason.EpisodesList.Sort(new NumericStringPropertyComparer()); historySeason.EpisodesList.Sort(new NumericStringPropertyComparer());
@ -167,7 +189,7 @@ public class History(Crunchyroll crunInstance){
historySeries.Seasons.Add(newSeason); historySeries.Seasons.Add(newSeason);
historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum).ToList(); historySeries.Seasons = historySeries.Seasons.OrderBy(s => s.SeasonNum != null ? int.Parse(s.SeasonNum) : 0).ToList();
} }
historySeries.UpdateNewEpisodes(); historySeries.UpdateNewEpisodes();
} else{ } else{
@ -190,6 +212,7 @@ public class History(Crunchyroll crunInstance){
newHistorySeries.Seasons.Add(newSeason); newHistorySeries.Seasons.Add(newSeason);
newHistorySeries.UpdateNewEpisodes(); newHistorySeries.UpdateNewEpisodes();
} }
} }
@ -235,6 +258,7 @@ public class History(Crunchyroll crunInstance){
EpisodeTitle = crunchyEpisode.Title, EpisodeTitle = crunchyEpisode.Title,
EpisodeId = crunchyEpisode.Id, EpisodeId = crunchyEpisode.Id,
Episode = crunchyEpisode.Episode, Episode = crunchyEpisode.Episode,
SpecialEpisode = !int.TryParse(crunchyEpisode.Episode, out _),
}; };
newSeason.EpisodesList.Add(newHistoryEpisode); newSeason.EpisodesList.Add(newHistoryEpisode);
@ -255,6 +279,7 @@ public class History(Crunchyroll crunInstance){
EpisodeTitle = episode.Title, EpisodeTitle = episode.Title,
EpisodeId = episode.Id, EpisodeId = episode.Id,
Episode = episode.Episode, Episode = episode.Episode,
SpecialEpisode = !int.TryParse(episode.Episode, out _),
}; };
newSeason.EpisodesList.Add(newHistoryEpisode); newSeason.EpisodesList.Add(newHistoryEpisode);
@ -269,7 +294,7 @@ public class NumericStringPropertyComparer : IComparer<HistoryEpisode>{
if (int.TryParse(x.Episode, out int xInt) && int.TryParse(y.Episode, out int yInt)){ if (int.TryParse(x.Episode, out int xInt) && int.TryParse(y.Episode, out int yInt)){
return xInt.CompareTo(yInt); return xInt.CompareTo(yInt);
} }
// Fall back to string comparison if not parseable as integers // Fall back to string comparison if not parseable as integers
return String.Compare(x.Episode, y.Episode, StringComparison.Ordinal); return String.Compare(x.Episode, y.Episode, StringComparison.Ordinal);
} }
@ -328,7 +353,7 @@ public class HistorySeries : INotifyPropertyChanged{
// Iterate over the Episodes from the end to the beginning // Iterate over the Episodes from the end to the beginning
for (int j = Seasons[i].EpisodesList.Count - 1; j >= 0 && !foundWatched; j--){ for (int j = Seasons[i].EpisodesList.Count - 1; j >= 0 && !foundWatched; j--){
if (!Seasons[i].EpisodesList[j].WasDownloaded){ if (!Seasons[i].EpisodesList[j].WasDownloaded && !Seasons[i].EpisodesList[j].SpecialEpisode){
count++; count++;
} else{ } else{
foundWatched = true; foundWatched = true;
@ -351,7 +376,7 @@ public class HistorySeries : INotifyPropertyChanged{
// Iterate over the Episodes from the end to the beginning // Iterate over the Episodes from the end to the beginning
for (int j = Seasons[i].EpisodesList.Count - 1; j >= 0 && !foundWatched; j--){ for (int j = Seasons[i].EpisodesList.Count - 1; j >= 0 && !foundWatched; j--){
if (!Seasons[i].EpisodesList[j].WasDownloaded){ if (!Seasons[i].EpisodesList[j].WasDownloaded && !Seasons[i].EpisodesList[j].SpecialEpisode){
//ADD to download queue //ADD to download queue
await Seasons[i].EpisodesList[j].DownloadEpisode(); await Seasons[i].EpisodesList[j].DownloadEpisode();
} else{ } else{
@ -419,8 +444,11 @@ public partial class HistoryEpisode : INotifyPropertyChanged{
[JsonProperty("episode_was_downloaded")] [JsonProperty("episode_was_downloaded")]
public bool WasDownloaded{ get; set; } public bool WasDownloaded{ get; set; }
public event PropertyChangedEventHandler? PropertyChanged; [JsonProperty("episode_special_episode")]
public bool SpecialEpisode{ get; set; }
public event PropertyChangedEventHandler? PropertyChanged;
public void ToggleWasDownloaded(){ public void ToggleWasDownloaded(){
WasDownloaded = !WasDownloaded; WasDownloaded = !WasDownloaded;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(WasDownloaded))); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(WasDownloaded)));

View file

@ -32,7 +32,7 @@ public struct SeriesSearchItem{
[JsonProperty("season_number")] public int SeasonNumber{ get; set; } [JsonProperty("season_number")] public int SeasonNumber{ get; set; }
public Dictionary<object, object> Images{ get; set; } public Dictionary<object, object> Images{ get; set; }
[JsonProperty("mature_blocked")] public bool MatureBlocked{ get; set; } [JsonProperty("mature_blocked")] public bool MatureBlocked{ get; set; }
public List<Version> Versions{ get; set; } public List<Version>? Versions{ get; set; }
public string Title{ get; set; } public string Title{ get; set; }
[JsonProperty("is_subbed")] public bool IsSubbed{ get; set; } [JsonProperty("is_subbed")] public bool IsSubbed{ get; set; }
public string Id{ get; set; } public string Id{ get; set; }

View file

@ -4,59 +4,77 @@ using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using CRD.Downloader; using CRD.Downloader;
using CRD.Utils;
using CRD.Views; using CRD.Views;
using ReactiveUI; using ReactiveUI;
namespace CRD.ViewModels; namespace CRD.ViewModels;
public partial class HistoryPageViewModel : ViewModelBase{ public partial class HistoryPageViewModel : ViewModelBase{
public ObservableCollection<HistorySeries> Items{ get; } public ObservableCollection<HistorySeries> Items{ get; }
[ObservableProperty] private bool? _showLoading = false;
[ObservableProperty]
private bool? _showLoading = false;
[ObservableProperty] [ObservableProperty]
public HistorySeries _selectedSeries; public HistorySeries _selectedSeries;
[ObservableProperty]
public static bool _editMode;
public HistoryPageViewModel(){ public HistoryPageViewModel(){
Items = Crunchyroll.Instance.HistoryList; Items = Crunchyroll.Instance.HistoryList;
foreach (var historySeries in Items){ foreach (var historySeries in Items){
if (historySeries.ThumbnailImage == null){ if (historySeries.ThumbnailImage == null){
historySeries.LoadImage(); historySeries.LoadImage();
} }
historySeries.UpdateNewEpisodes(); historySeries.UpdateNewEpisodes();
} }
} }
partial void OnSelectedSeriesChanged(HistorySeries value){ partial void OnSelectedSeriesChanged(HistorySeries value){
Crunchyroll.Instance.SelectedSeries = value; Crunchyroll.Instance.SelectedSeries = value;
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel),false,false)); MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel), false, false));
_selectedSeries = null; _selectedSeries = null;
} }
[RelayCommand]
public void NavToSeries(){
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel),false,false));
}
[RelayCommand]
public void RemoveSeries(string? seriesId){
HistorySeries? objectToRemove = Crunchyroll.Instance.HistoryList.ToList().Find(se => se.SeriesId == seriesId) ?? null;
if (objectToRemove != null) {
Crunchyroll.Instance.HistoryList.Remove(objectToRemove);
Items.Remove(objectToRemove);
}
CfgManager.WriteJsonToFile(CfgManager.PathCrHistory, Crunchyroll.Instance.HistoryList);
}
[RelayCommand]
public void NavToSeries(){
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel), false, false));
}
[RelayCommand] [RelayCommand]
public async void RefreshAll(){ public async void RefreshAll(){
for (int i = 0; i < Items.Count; i++) { for (int i = 0; i < Items.Count; i++){
ShowLoading = true; ShowLoading = true;
await Items[i].FetchData(""); await Items[i].FetchData("");
Items[i].UpdateNewEpisodes(); Items[i].UpdateNewEpisodes();
} }
ShowLoading = false; ShowLoading = false;
} }
[RelayCommand] [RelayCommand]
public async void AddMissingToQueue(){ public async void AddMissingToQueue(){
for (int i = 0; i < Items.Count; i++) { for (int i = 0; i < Items.Count; i++){
await Items[i].AddNewMissingToDownloads(); await Items[i].AddNewMissingToDownloads();
} }
ShowLoading = false; ShowLoading = false;
} }
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -23,9 +24,25 @@ public partial class MainWindowViewModel : ViewModelBase{
_faTheme = App.Current.Styles[0] as FluentAvaloniaTheme; _faTheme = App.Current.Styles[0] as FluentAvaloniaTheme;
Init(); Init();
CleanUpOldUpdater();
} }
private void CleanUpOldUpdater() {
string backupFilePath = Path.Combine(Directory.GetCurrentDirectory(), "Updater.exe.bak");
if (File.Exists(backupFilePath)) {
try {
File.Delete(backupFilePath);
Console.WriteLine($"Deleted old updater file: {backupFilePath}");
} catch (Exception ex) {
Console.WriteLine($"Failed to delete old updater file: {ex.Message}");
}
} else {
Console.WriteLine("No old updater file found to delete.");
}
}
public async void Init(){ public async void Init(){

View file

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using CRD.Downloader; using CRD.Downloader;
using CRD.Utils;
using CRD.Views; using CRD.Views;
using ReactiveUI; using ReactiveUI;
@ -14,6 +15,9 @@ public partial class SeriesPageViewModel : ViewModelBase{
[ObservableProperty] [ObservableProperty]
public HistorySeries _selectedSeries; public HistorySeries _selectedSeries;
[ObservableProperty]
public static bool _editMode;
public SeriesPageViewModel(){ public SeriesPageViewModel(){
_selectedSeries = Crunchyroll.Instance.SelectedSeries; _selectedSeries = Crunchyroll.Instance.SelectedSeries;
@ -29,6 +33,19 @@ public partial class SeriesPageViewModel : ViewModelBase{
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel),false,true)); MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel),false,true));
} }
[RelayCommand]
public void RemoveSeason(string? season){
HistorySeason? objectToRemove = SelectedSeries.Seasons.Find(se => se.SeasonId == season) ?? null;
if (objectToRemove != null) {
SelectedSeries.Seasons.Remove(objectToRemove);
}
CfgManager.WriteJsonToFile(CfgManager.PathCrHistory, Crunchyroll.Instance.HistoryList);
MessageBus.Current.SendMessage(new NavigationMessage(typeof(SeriesPageViewModel),false,true));
}
[RelayCommand] [RelayCommand]
public void NavBack(){ public void NavBack(){
SelectedSeries.UpdateNewEpisodes(); SelectedSeries.UpdateNewEpisodes();

View file

@ -5,6 +5,7 @@
xmlns:vm="clr-namespace:CRD.ViewModels" xmlns:vm="clr-namespace:CRD.ViewModels"
xmlns:ui="clr-namespace:CRD.Utils.UI" xmlns:ui="clr-namespace:CRD.Utils.UI"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
x:DataType="vm:HistoryPageViewModel" x:DataType="vm:HistoryPageViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="CRD.Views.HistoryPageView"> x:Class="CRD.Views.HistoryPageView">
@ -23,6 +24,7 @@
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal" Margin="20 0 0 0 "> <StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal" Margin="20 0 0 0 ">
<Button Command="{Binding RefreshAll}" Margin="10">Refresh All</Button> <Button Command="{Binding RefreshAll}" Margin="10">Refresh All</Button>
<Button Command="{Binding AddMissingToQueue}" Margin="10">Add To Queue</Button> <Button Command="{Binding AddMissingToQueue}" Margin="10">Add To Queue</Button>
<ToggleButton IsChecked="{Binding EditMode}" Margin="10">Edit</ToggleButton>
</StackPanel> </StackPanel>
<Grid Grid.Row="1" Grid.Column="0"> <Grid Grid.Row="1" Grid.Column="0">
@ -44,20 +46,43 @@
</ListBox.ItemsPanel> </ListBox.ItemsPanel>
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="250" Width="250"
MaxHeight="400" Height="400" Margin="5"> <Grid>
<Grid>
<Image Source="{Binding ThumbnailImage}" Width="240" Height="360"></Image> <StackPanel Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="250" Width="250"
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Right" IsVisible="{Binding NewEpisodes, Converter={StaticResource UiIntToVisibilityConverter}}"> MaxHeight="400" Height="400" Margin="5">
<TextBlock VerticalAlignment="Center" TextAlignment="Center" Margin="0 0 5 0" Width="30" Height="30" <Grid>
Background="Black" Opacity="0.8" Text="{Binding NewEpisodes}" <Image Source="{Binding ThumbnailImage}" Width="240" Height="360"></Image>
Padding="0,5,0,0"/> <StackPanel VerticalAlignment="Top" HorizontalAlignment="Right" IsVisible="{Binding NewEpisodes, Converter={StaticResource UiIntToVisibilityConverter}}">
</StackPanel> <TextBlock VerticalAlignment="Center" TextAlignment="Center" Margin="0 0 5 0" Width="30" Height="30"
</Grid> Background="Black" Opacity="0.8" Text="{Binding NewEpisodes}"
<TextBlock HorizontalAlignment="Center" Text="{Binding SeriesTitle}" TextWrapping="NoWrap" Padding="0,5,0,0"/>
Margin="4,0,0,0"> </StackPanel>
</TextBlock> </Grid>
</StackPanel> <TextBlock HorizontalAlignment="Center" Text="{Binding SeriesTitle}" TextWrapping="NoWrap"
Margin="4,0,0,0">
</TextBlock>
</StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" MaxWidth="250" Width="250"
MaxHeight="400" Height="400" Background="#90000000" IsVisible="{Binding $parent[UserControl].((vm:HistoryPageViewModel)DataContext).EditMode}">
<Button MaxWidth="250" Width="250" MaxHeight="400" Height="400" FontStyle="Italic"
VerticalAlignment="Center"
Command="{Binding $parent[UserControl].((vm:HistoryPageViewModel)DataContext).RemoveSeries}"
CommandParameter="{Binding SeriesId}"
>
<ToolTip.Tip>
<TextBlock Text="Remove Series" FontSize="15" />
</ToolTip.Tip>
<StackPanel Orientation="Horizontal">
<controls:SymbolIcon Symbol="Delete" FontSize="32" />
</StackPanel>
</Button>
</StackPanel>
</Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>

View file

@ -9,7 +9,7 @@
x:DataType="vm:SeriesPageViewModel" x:DataType="vm:SeriesPageViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="CRD.Views.SeriesPageView"> x:Class="CRD.Views.SeriesPageView">
<Grid Margin="10"> <Grid Margin="10">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@ -28,26 +28,24 @@
Height="360"> Height="360">
</Image> </Image>
<Grid Grid.Row="1" Grid.Column="1"> <Grid Grid.Row="1" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="50" Text="{Binding SelectedSeries.SeriesTitle}"></TextBlock>
<TextBlock Grid.Row="1" FontSize="20" TextWrapping="Wrap" Text="{Binding SelectedSeries.SeriesDescription}"></TextBlock>
<Button Grid.Row="3" Command="{Binding UpdateData}" Margin="0 0 0 10">Fetch Series</Button>
</Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="50" Text="{Binding SelectedSeries.SeriesTitle}"></TextBlock>
<TextBlock Grid.Row="1" FontSize="20" TextWrapping="Wrap" Text="{Binding SelectedSeries.SeriesDescription}"></TextBlock>
<StackPanel Grid.Row="3" Orientation="Horizontal">
<Button Command="{Binding UpdateData}" Margin="0 0 5 10">Fetch Series</Button>
<ToggleButton IsChecked="{Binding EditMode}" Margin="0 0 0 10">Edit</ToggleButton>
</StackPanel>
</Grid>
<ScrollViewer Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"> <ScrollViewer Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
@ -58,11 +56,10 @@
<controls:SettingsExpander <controls:SettingsExpander
Header="{Binding CombinedProperty}" Header="{Binding CombinedProperty}"
ItemsSource="{Binding EpisodesList}" ItemsSource="{Binding EpisodesList}"
Description="{Binding SeasonTitle}" Description="{Binding SeasonTitle}"
IsExpanded="False"> IsExpanded="False">
<controls:SettingsExpander.ItemTemplate> <controls:SettingsExpander.ItemTemplate>
<DataTemplate> <DataTemplate>
@ -83,20 +80,28 @@
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center"> <StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
<Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent" BorderThickness="0" CornerRadius="50" IsVisible="{Binding !WasDownloaded}" Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}" CommandParameter="{Binding EpisodeId}"> <Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent"
<Grid > BorderThickness="0" CornerRadius="50"
IsVisible="{Binding !WasDownloaded}"
Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}"
CommandParameter="{Binding EpisodeId}">
<Grid>
<Ellipse Width="25" Height="25" Fill="Gray" /> <Ellipse Width="25" Height="25" Fill="Gray" />
<controls:SymbolIcon Symbol="Checkmark" FontSize="18" /> <controls:SymbolIcon Symbol="Checkmark" FontSize="18" />
</Grid> </Grid>
</Button> </Button>
<Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent" BorderThickness="0" CornerRadius="50" IsVisible="{Binding WasDownloaded}" Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}" CommandParameter="{Binding EpisodeId}"> <Button Width="34" Height="34" Margin="0 0 10 0" Background="Transparent"
<Grid > BorderThickness="0" CornerRadius="50"
IsVisible="{Binding WasDownloaded}"
Command="{Binding $parent[controls:SettingsExpander].((downloader:HistorySeason)DataContext).UpdateDownloaded}"
CommandParameter="{Binding EpisodeId}">
<Grid>
<Ellipse Width="25" Height="25" Fill="#21a556" /> <Ellipse Width="25" Height="25" Fill="#21a556" />
<controls:SymbolIcon Symbol="Checkmark" FontSize="18" /> <controls:SymbolIcon Symbol="Checkmark" FontSize="18" />
</Grid> </Grid>
</Button> </Button>
<Button Margin="0 0 5 0" FontStyle="Italic" HorizontalAlignment="Right" <Button Margin="0 0 5 0" FontStyle="Italic" HorizontalAlignment="Right"
VerticalAlignment="Center" Command="{Binding DownloadEpisode}"> VerticalAlignment="Center" Command="{Binding DownloadEpisode}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@ -114,8 +119,10 @@
<TextBlock Text="{Binding DownloadedEpisodes}" VerticalAlignment="Center"></TextBlock> <TextBlock Text="{Binding DownloadedEpisodes}" VerticalAlignment="Center"></TextBlock>
<TextBlock Text="/" VerticalAlignment="Center"></TextBlock> <TextBlock Text="/" VerticalAlignment="Center"></TextBlock>
<TextBlock Text="{Binding EpisodesList.Count}" VerticalAlignment="Center"></TextBlock> <TextBlock Text="{Binding EpisodesList.Count}" VerticalAlignment="Center"></TextBlock>
<Button Margin="10 0 0 0" FontStyle="Italic" <Button Margin="10 0 0 0" FontStyle="Italic"
VerticalAlignment="Center" Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).UpdateData}" CommandParameter="{Binding SeasonId}" > VerticalAlignment="Center"
Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).UpdateData}"
CommandParameter="{Binding SeasonId}">
<ToolTip.Tip> <ToolTip.Tip>
<TextBlock Text="Fetch Season" FontSize="15" /> <TextBlock Text="Fetch Season" FontSize="15" />
</ToolTip.Tip> </ToolTip.Tip>
@ -123,6 +130,18 @@
<controls:SymbolIcon Symbol="Refresh" FontSize="18" /> <controls:SymbolIcon Symbol="Refresh" FontSize="18" />
</StackPanel> </StackPanel>
</Button> </Button>
<Button Margin="10 0 0 0" FontStyle="Italic"
VerticalAlignment="Center"
Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).RemoveSeason}"
CommandParameter="{Binding SeasonId}"
IsVisible="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).EditMode}">
<ToolTip.Tip>
<TextBlock Text="Remove Season" FontSize="15" />
</ToolTip.Tip>
<StackPanel Orientation="Horizontal">
<controls:SymbolIcon Symbol="Delete" FontSize="18" />
</StackPanel>
</Button>
</StackPanel> </StackPanel>
</controls:SettingsExpander.Footer> </controls:SettingsExpander.Footer>