Skip to content

Commit

Permalink
Improved calendar
Browse files Browse the repository at this point in the history
Displays images and a seasonal delimiter in each day card
  • Loading branch information
dend committed Jun 20, 2024
1 parent 4070436 commit a8ea76f
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 33 deletions.
11 changes: 6 additions & 5 deletions src/OpenSpartan.Workshop/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,18 +153,19 @@
<converters:PerformanceToGlyphConverter x:Key="PerformanceToGlyphConverter"/>
<converters:PerformanceToColorConverter x:Key="PerformanceToColorConverter"/>
<converters:RewardTypeToStringConverter x:Key="RewardTypeToStringConverter"/>
<converters:RewardTypeToVisibilityConverter x:Key="RewardTypeToVisibilityConverter" />
<converters:ISO8601ToLocalDateStringConverter x:Key="ISO8601ToLocalDateStringConverter" />
<converters:RewardTypeToVisibilityConverter x:Key="RewardTypeToVisibilityConverter"/>
<converters:ISO8601ToLocalDateStringConverter x:Key="ISO8601ToLocalDateStringConverter"/>
<converters:SingleValueAvailabilityToVisibilityConverter x:Key="SingleValueAvailabilityToVisibilityConverter"/>
<converters:ListCountToVisibilityConverter x:Key="ListCountToVisibilityConverter"/>
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<converters:RankIdentifierToPathConverter x:Key="RankIdentifierToPathConverter"/>
<converters:StringAvailabilityToVisibilityConverter x:Key="StringAvailabilityToVisibilityConverter"/>
<converters:CsrProgressStateConverter x:Key="CsrProgressStateConverter"/>
<converters:CsrToPathConverter x:Key="CsrToPathConverter"/>
<converters:CsrToTextRankConverter x:Key="CsrToTextRankConverter" />
<converters:CsrToProgressConverter x:Key="CsrToProgressConverter" />
<converters:CsrToTooltipValueConverter x:Key="CsrToTooltipValueConverter" />
<converters:CsrToTextRankConverter x:Key="CsrToTextRankConverter"/>
<converters:CsrToProgressConverter x:Key="CsrToProgressConverter"/>
<converters:CsrToTooltipValueConverter x:Key="CsrToTooltipValueConverter"/>
<converters:StringAvailabilityToParameterSource x:Key="StringAvailabilityToParameterSource"/>
</ResourceDictionary>
</Application.Resources>
</Application>
1 change: 1 addition & 0 deletions src/OpenSpartan.Workshop/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ private async static void LoadSettings()
SettingsViewModel.Instance.Settings.Sandbox = settings.Sandbox;
SettingsViewModel.Instance.Settings.UseObanClearance = settings.UseObanClearance;
SettingsViewModel.Instance.Settings.ExtraRitualEvents = settings.ExtraRitualEvents;
SettingsViewModel.Instance.Settings.ExcludedOperations = settings.ExcludedOperations;

SettingsManager.StoreSettings(SettingsViewModel.Instance.Settings);
}
Expand Down
13 changes: 10 additions & 3 deletions src/OpenSpartan.Workshop/Controls/SeasonCalendarControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid x:Name="CalendarItemGrid">
<Image Opacity=".4" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="UniformToFill" Source="{Binding BackgroundImagePath, Converter={StaticResource ServicePathToLocalPathConverter}}">

</Image>

<StackPanel VerticalAlignment="Bottom">
<Grid
Padding="5"
Expand All @@ -47,15 +51,18 @@
<Grid.Background>
<SolidColorBrush Color="{Binding RegularSeasonMarkerColor.Color}" Opacity="1"></SolidColorBrush>
</Grid.Background>
<TextBlock Text="{Binding RegularSeasonText}" TextDecorations="None"></TextBlock>
<StackPanel Orientation="Horizontal" Visibility="{Binding RegularSeasonText, Converter={StaticResource StringAvailabilityToVisibilityConverter}}">
<Image Source="{Binding RegularSeasonText, Converter={StaticResource StringAvailabilityToParameterSource}, ConverterParameter='/CustomImages/season-marker.svg'}" Height="12"></Image>
<TextBlock Margin="8,0,0,0" Text="{Binding RegularSeasonText}" TextDecorations="None"></TextBlock>
</StackPanel>
</Grid>

<Grid
Padding="5"
Margin="4,0,4,0"
VerticalAlignment="Bottom">
<Grid.Background>
<SolidColorBrush Color="{Binding CSRSeasonMarkerColor.Color}" Opacity=".3"></SolidColorBrush>
<SolidColorBrush Color="{Binding CSRSeasonMarkerColor.Color}" Opacity=".5"></SolidColorBrush>
</Grid.Background>
<TextBlock Text="{Binding CSRSeasonText}" TextDecorations="None"></TextBlock>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,22 @@ internal sealed class ServicePathToLocalPathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var medalPath = string.Empty;
var localPath = string.Empty;

if (value != null)
{
medalPath = Path.Join(Core.Configuration.AppDataDirectory, "imagecache", value.ToString());
string? targetPath = value as string;

if (Path.IsPathRooted(targetPath))
{
targetPath = targetPath.TrimStart(Path.DirectorySeparatorChar);
targetPath = targetPath.TrimStart(Path.AltDirectorySeparatorChar);
}

localPath = Path.Join(Core.Configuration.AppDataDirectory, "imagecache", targetPath);
}

return medalPath;
return localPath;
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.UI.Xaml.Data;
using System;

namespace OpenSpartan.Workshop.Converters
{
internal class StringAvailabilityToParameterSource : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
// Check if value is a non-null and non-empty string
if (value is string str && !String.IsNullOrEmpty(str))
{
// Return the converter parameter as string
return parameter?.ToString() ?? string.Empty;
}

// Return null or empty string if value is null or empty
return string.Empty;
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException(); // ConvertBack is not needed for this example
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal sealed class StringAvailabilityToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (!string.IsNullOrEmpty((string)value))
if (value != null && !string.IsNullOrWhiteSpace((string)value))
{
return Visibility.Visible;
}
Expand Down
88 changes: 77 additions & 11 deletions src/OpenSpartan.Workshop/Core/UserContextManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -335,24 +336,24 @@ internal static void EnsureDirectoryExists(string path)
file.Directory.Create();
}

private static async Task DownloadAndSetImage(string imageName, string imagePath, Action setImageAction = null, bool isOnWaypoint = false)
private static async Task DownloadAndSetImage(string serviceImagePath, string localImagePath, Action setImageAction = null, bool isOnWaypoint = false)

Check warning on line 339 in src/OpenSpartan.Workshop/Core/UserContextManager.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
{
if (!System.IO.File.Exists(imagePath))
if (!System.IO.File.Exists(localImagePath))
{
HaloApiResultContainer<byte[], RawResponseContainer> image = null;

if (isOnWaypoint)
{
image = await SafeAPICall(async () => await HaloClient.GameCmsGetGenericWaypointFile(imageName));
image = await SafeAPICall(async () => await HaloClient.GameCmsGetGenericWaypointFile(serviceImagePath));
}
else
{
image = await SafeAPICall(async () => await HaloClient.GameCmsGetImage(imageName));
image = await SafeAPICall(async () => await HaloClient.GameCmsGetImage(serviceImagePath));
}

if (image != null && image.Result != null && image.Response.Code == 200)
{
await System.IO.File.WriteAllBytesAsync(imagePath, image.Result);
await System.IO.File.WriteAllBytesAsync(localImagePath, image.Result);
}
}

Expand Down Expand Up @@ -1007,7 +1008,11 @@ await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
{
await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
{
SeasonCalendarViewDayItem calendarItem = new(day, csrCalendar.Result.Seasons[i].CsrSeasonFilePath.Replace(".json", string.Empty), ColorConverter.FromHex(Configuration.SeasonColors[i]));
SeasonCalendarViewDayItem calendarItem = new();
calendarItem.DateTime = day;
calendarItem.CSRSeasonText = csrCalendar.Result.Seasons[i].CsrSeasonFilePath.Replace(".json", string.Empty);
calendarItem.CSRSeasonMarkerColor = ColorConverter.FromHex(Configuration.SeasonColors[i]);

SeasonCalendarViewModel.Instance.SeasonDays.Add(calendarItem);
});
}
Expand All @@ -1028,7 +1033,24 @@ await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
{
// Date ranges for season reward tracks are not structured, so we will need to extract them separately.
var rewardTrack = seasonRewardTracks.ElementAt(i);
await ProcessRegularSeasonRanges(rewardTrack.Value.DateRange.Value, rewardTrack.Value.Name.Value, i);

string? targetBackgroundPath = rewardTrack.Value?.CardBackgroundImage ??
rewardTrack.Value?.Logo ??
rewardTrack.Value?.SummaryBackgroundPath;

if (!string.IsNullOrEmpty(targetBackgroundPath))
{
if (Path.IsPathRooted(targetBackgroundPath))
{
targetBackgroundPath = targetBackgroundPath.TrimStart(Path.DirectorySeparatorChar);
targetBackgroundPath = targetBackgroundPath.TrimStart(Path.AltDirectorySeparatorChar);
}

string qualifiedBackgroundImagePath = Path.Combine(Configuration.AppDataDirectory, "imagecache", targetBackgroundPath);
await DownloadAndSetImage(targetBackgroundPath, qualifiedBackgroundImagePath);
}

await ProcessRegularSeasonRanges(rewardTrack.Value.DateRange.Value, rewardTrack.Value.Name.Value, i, targetBackgroundPath);
}

// Then, we process operations
Expand Down Expand Up @@ -1057,7 +1079,27 @@ await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
LogEngine.Log($"{operation.RewardTrackPath} - calendar prep completed");
}

await ProcessRegularSeasonRanges(compoundOperation.RewardTrackMetadata.DateRange.Value, compoundOperation.RewardTrackMetadata.Name.Value, operations.OperationRewardTracks.IndexOf(operation));
// If there is a background image, let's make sure that we attempt to download it.
// The same image may be downloaded when the Operations view is populated, but we
// don't know if that happened yet or not.

string? targetBackgroundPath = compoundOperation.RewardTrackMetadata?.SummaryImagePath ??
compoundOperation.RewardTrackMetadata?.BackgroundImagePath ??
compoundOperation.SeasonRewardTrack?.Logo;

if (!string.IsNullOrEmpty(targetBackgroundPath))
{
if (Path.IsPathRooted(targetBackgroundPath))
{
targetBackgroundPath = targetBackgroundPath.TrimStart(Path.DirectorySeparatorChar);
targetBackgroundPath = targetBackgroundPath.TrimStart(Path.AltDirectorySeparatorChar);
}

string qualifiedBackgroundImagePath = Path.Combine(Configuration.AppDataDirectory, "imagecache", targetBackgroundPath);
await DownloadAndSetImage(targetBackgroundPath, qualifiedBackgroundImagePath);
}

await ProcessRegularSeasonRanges(compoundOperation.RewardTrackMetadata.DateRange.Value, compoundOperation.RewardTrackMetadata.Name.Value, operations.OperationRewardTracks.IndexOf(operation), targetBackgroundPath);
}

// And now we check the event data.
Expand Down Expand Up @@ -1091,7 +1133,26 @@ await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
LogEngine.Log($"{eventEntry.RewardTrackPath} - calendar prep completed");
}

await ProcessRegularSeasonRanges(compoundEvent.RewardTrackMetadata.DateRange.Value, compoundEvent.RewardTrackMetadata.Name.Value, distinctEvents.IndexOf(eventEntry));
// If there is a background image, let's make sure that we attempt to download it.
// The same image may be downloaded when the Operations view is populated, but we
// don't know if that happened yet or not.
string? targetBackgroundPath = compoundEvent?.RewardTrackMetadata?.SummaryImagePath ??
compoundEvent?.RewardTrackMetadata?.BackgroundImagePath ??
compoundEvent?.SeasonRewardTrack?.Logo;

if (!string.IsNullOrEmpty(targetBackgroundPath))
{
if (Path.IsPathRooted(targetBackgroundPath))
{
targetBackgroundPath = targetBackgroundPath.TrimStart(Path.DirectorySeparatorChar);
targetBackgroundPath = targetBackgroundPath.TrimStart(Path.AltDirectorySeparatorChar);
}

string qualifiedBackgroundImagePath = Path.Combine(Configuration.AppDataDirectory, "imagecache", targetBackgroundPath);
await DownloadAndSetImage(targetBackgroundPath, qualifiedBackgroundImagePath);
}

await ProcessRegularSeasonRanges(compoundEvent.RewardTrackMetadata.DateRange.Value, compoundEvent.RewardTrackMetadata.Name.Value, distinctEvents.IndexOf(eventEntry), targetBackgroundPath);
}

await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
Expand All @@ -1102,7 +1163,7 @@ await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
return true;
}

private async static Task ProcessRegularSeasonRanges(string rangeText, string name, int index)
private async static Task ProcessRegularSeasonRanges(string rangeText, string name, int index, string backgroundPath = "")
{
List<Tuple<DateTime, DateTime>> ranges = DateRangeParser.ExtractDateRanges(rangeText);
foreach (var range in ranges)
Expand All @@ -1122,12 +1183,17 @@ await DispatcherWindow.DispatcherQueue.EnqueueAsync(() =>
{
targetDay.RegularSeasonText = name;
targetDay.RegularSeasonMarkerColor = ColorConverter.FromHex(Configuration.SeasonColors[index]);
targetDay.BackgroundImagePath = backgroundPath;
}
else
{
SeasonCalendarViewDayItem calendarItem = new(day, string.Empty, new Microsoft.UI.Xaml.Media.SolidColorBrush(Colors.White));
SeasonCalendarViewDayItem calendarItem = new();
calendarItem.DateTime = day;
calendarItem.CSRSeasonText = string.Empty;
calendarItem.CSRSeasonMarkerColor = new Microsoft.UI.Xaml.Media.SolidColorBrush(Colors.White);
calendarItem.RegularSeasonText = name;
calendarItem.RegularSeasonMarkerColor = ColorConverter.FromHex(Configuration.SeasonColors[index]);
calendarItem.BackgroundImagePath = backgroundPath;
SeasonCalendarViewModel.Instance.SeasonDays.Add(calendarItem);
}
});
Expand Down
Loading

0 comments on commit a8ea76f

Please sign in to comment.