Skip to content

Commit

Permalink
Add loop mode and count indicator and allow the user to change the lo…
Browse files Browse the repository at this point in the history
…op type
  • Loading branch information
sandermvanvliet committed Aug 8, 2023
1 parent d218c75 commit b3f2937
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 10 deletions.
4 changes: 3 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ Read more about how it works on [the RoadCaptain site](https://roadcaptain.nl/fe
- The color scheme of the elevation profile has been changed to provide much clearer indication of the grade
- When creating a route, Route Builder no longer will attempt to create a loop for segments that join back on the previous segment. This especially happened for routes summiting on mountain tops in Watopia.
- When creating a route and Route Builder detects that you selected a segment that can create a loop, it will now ask you what type of loop you want. You can choose between _No loop_, _Infinite loop_ or _Constrained loop_ where the last one allows you to specify how many times you want to do the loop before exiting it:
![Screenshot of the new make loop dialog](./images/make-loop-dialog.png)
<br />![Screenshot of the new make loop dialog](./images/make-loop-dialog.png)
- When creating a route and the route already contains a loop, Route Builder now no longer asks to create a further loop
- When creating a route with a loop, the segment list now indicates the loop mode (fixed number or infinite) and the number of loops: <br />![Screenshot of the segment list with the loop indicator](./images/loop-indicator.png)![Screenshot of the segment list with the loop indicator](./images/loop-indicator-infinite.png)<br />Clicking the indicator allows you to change the loop settings.


### Runner

Expand Down
Binary file added images/loop-indicator-infinite.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/loop-indicator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/RoadCaptain.App.RouteBuilder/DelegateDecorator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ public async Task<MessageBoxResult> ShowClearRouteDialog()
return await InvokeIfNeededAsync(() => _decorated.ShowClearRouteDialog());
}

public async Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog()
public async Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog(LoopMode? loopMode = null, int? numberOfLoops = null)
{
return await InvokeIfNeededAsync(() => _decorated.ShowRouteLoopDialog());
return await InvokeIfNeededAsync(() => _decorated.ShowRouteLoopDialog(loopMode, numberOfLoops));
}

public async Task ShowSaveRouteDialog(string? lastUsedFolder, RouteViewModel routeViewModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public Task<MessageBoxResult> ShowClearRouteDialog()
throw new System.NotImplementedException();
}

public Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog()
public Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog(LoopMode? loopMode = null, int? numberOfLoops = null)
{
throw new System.NotImplementedException();
}
Expand Down
2 changes: 1 addition & 1 deletion src/RoadCaptain.App.RouteBuilder/IWindowService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public interface IWindowService : RoadCaptain.App.Shared.IWindowService
Task<bool> ShowDefaultSportSelectionDialog(SportType sport);
Task<MessageBoxResult> ShowShouldSaveRouteDialog();
Task<MessageBoxResult> ShowClearRouteDialog();
Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog();
Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog(LoopMode? loopMode = null, int? numberOfLoops = null);
Task ShowSaveRouteDialog(string? lastUsedFolder, RouteViewModel routeViewModel);
Task<TokenResponse?> ShowLogInDialog(Window owner);
Window? GetCurrentWindow();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using Autofac;
using Avalonia.Threading;
using Microsoft.Extensions.Configuration;
using RoadCaptain.App.RouteBuilder.UseCases;
using RoadCaptain.Ports;
using Serilog.Core;

Expand All @@ -32,6 +31,7 @@ public DesignTimeMainWindowViewModel()
{
Route.OutputFilePath = @"C:\git\RoadCaptain\test\RoadCaptain.Tests.Unit\GameState\Repro\Rebel.Route-Italian.Villa.Sprint.Loop.json";
Route.Load();
Route.LoopMode = LoopMode.Infinite;
Route.Markers.Add(new MarkerViewModel(new Segment(new List<TrackPoint>()){ Id = "test", Name="Test", Type = SegmentType.Climb, Sport = SportType.Cycling}));
Route.Markers.Add(new MarkerViewModel(new Segment(new List<TrackPoint>()){ Id = "test", Name="Test", Type = SegmentType.Climb, Sport = SportType.Cycling}));
Route.Markers.Add(new MarkerViewModel(new Segment(new List<TrackPoint>()){ Id = "test", Name="Test", Type = SegmentType.Climb, Sport = SportType.Cycling}));
Expand Down
31 changes: 31 additions & 0 deletions src/RoadCaptain.App.RouteBuilder/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,39 @@ public MainWindowViewModel(IRouteStore routeStore, ISegmentStore segmentStore, I
_ => Route.World != null)
.SubscribeTo(this, () => Route.World);

ConfigureLoopCommand = new AsyncRelayCommand(
_ => ConfigureLoop(),
_ => Route.IsLoop)
.SubscribeTo(this, () => Route.Sequence)
.SubscribeTo(this, () => Route.IsLoop);

Version = GetType().Assembly.GetName().Version?.ToString(4) ?? "0.0.0.0";
}


private async Task<CommandResult> ConfigureLoop()
{
var shouldCreateLoop = await _windowService.ShowRouteLoopDialog(Route.LoopMode, Route.NumberOfLoops);

if (shouldCreateLoop.Mode is LoopMode.Infinite or LoopMode.Constrained)
{
Route.LoopMode = shouldCreateLoop.Mode;
Route.NumberOfLoops = shouldCreateLoop.NumberOfLoops;
this.RaisePropertyChanged(nameof(Route));
}
else
{
// Clear the loop properties
foreach (var seq in Route.Sequence.Where(s => s.IsLoop))
{
seq.Type = SegmentSequenceType.Regular;
}
this.RaisePropertyChanged(nameof(Route));
}

return CommandResult.Success();
}

private async Task<CommandResult> ResetWorldAndSport()
{
if (Route.IsTainted)
Expand Down Expand Up @@ -293,6 +323,7 @@ public List<Segment> Markers
public ICommand SelectSportCommand { get; }
public ICommand ResetDefaultSportCommand { get; }
public ICommand ResetWorldCommand { get; }
public ICommand ConfigureLoopCommand { get; set; }

public Segment? SelectedSegment
{
Expand Down
9 changes: 9 additions & 0 deletions src/RoadCaptain.App.RouteBuilder/ViewModels/RouteViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ public int? NumberOfLoops
}
}

public bool IsLoop
{
get
{
return Sequence.Any(s => s.IsLoop);
}
}

public void StartOn(Segment segment)
{
if (_world == null)
Expand Down Expand Up @@ -513,6 +521,7 @@ public void MakeLoop(int startIndex, int endIndex, LoopMode mode, int? numberOfL
seqList[endIndex].Model.NextSegmentId = seqList[startIndex].SegmentId;
LoopMode = mode;
NumberOfLoops = numberOfLoops;
this.RaisePropertyChanged(nameof(IsLoop));
}

private void DetermineMarkersForRoute()
Expand Down
40 changes: 39 additions & 1 deletion src/RoadCaptain.App.RouteBuilder/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
xmlns:sharedControls="clr-namespace:RoadCaptain.App.Shared.Controls;assembly=RoadCaptain.App.Shared"
xmlns:appConverters="clr-namespace:RoadCaptain.App.RouteBuilder.Converters"
xmlns:map="clr-namespace:Codenizer.Avalonia.Map;assembly=Codenizer.Avalonia.Map"
xmlns:roadCaptain="clr-namespace:RoadCaptain;assembly=RoadCaptain"
mc:Ignorable="d"
x:Class="RoadCaptain.App.RouteBuilder.Views.MainWindow"
Icon="avares://RoadCaptain.App.Shared/icon.png"
Expand Down Expand Up @@ -394,7 +395,44 @@
IsVisible="{Binding Path=LoopImage,Converter={StaticResource NullabilityConverter}}"
Width="24"
Height="56" />

<Button Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,4,4,0"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=DataContext.ConfigureLoopCommand}"
IsVisible="{Binding Path=Type, Converter={StaticResource BooleanConverter}, ConverterParameter={x:Static roadCaptain:SegmentSequenceType.LoopStart}}">
<Button.Template>
<ControlTemplate>
<Border
BorderBrush="#FF6141"
BorderThickness="4"
Background="#FF6141"
CornerRadius="25"
Padding="6,0,6,0">
<StackPanel>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White"
FontWeight="Bold"
ToolTip.Tip="This loop will be followed a number of times and then continue with the rest of the route"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=DataContext.Route.NumberOfLoops, FallbackValue=0, TargetNullValue=0}"
IsVisible="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=DataContext.Route.LoopMode, FallbackValue=false, TargetNullValue=false, Converter={StaticResource BooleanConverter}, ConverterParameter={x:Static roadCaptain:LoopMode.Constrained}}"
/>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White"
FontWeight="Bold"
Text=""
ToolTip.Tip="This is an infinite loop, you must end the activity yourself when you have had enough!"
IsVisible="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=DataContext.Route.LoopMode, FallbackValue=false, TargetNullValue=false, Converter={StaticResource BooleanConverter}, ConverterParameter={x:Static roadCaptain:LoopMode.Infinite}}"
/>
</StackPanel>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
Expand Down
11 changes: 9 additions & 2 deletions src/RoadCaptain.App.RouteBuilder/WindowService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,17 @@ public async Task<MessageBoxResult> ShowClearRouteDialog()
MessageBoxIcon.Question);
}

public async Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog()
public async Task<(LoopMode Mode, int? NumberOfLoops)> ShowRouteLoopDialog(LoopMode? loopMode = null,
int? numberOfLoops = null)
{
var makeLoopDialog = Resolve<MakeLoopDialog>();
var makeLoopDialogViewModel = new MakeLoopDialogViewModel();
var makeLoopDialogViewModel = new MakeLoopDialogViewModel
{
NoLoop = true,
InfiniteLoop = loopMode == LoopMode.Infinite,
ConstrainedLoop = loopMode == LoopMode.Constrained,
NumberOfLoops = numberOfLoops
};
makeLoopDialog.DataContext = makeLoopDialogViewModel;

await makeLoopDialog.ShowDialog(CurrentWindow);
Expand Down
7 changes: 6 additions & 1 deletion src/RoadCaptain.App.Shared/Converters/BooleanConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ public class BooleanConverter : IValueConverter
{
if (value is bool boolean)
{
if (parameter is string flip && flip == "invert")
if (parameter is string and "invert")
{
return !boolean;
}

return boolean;
}

if (value != null && parameter != null && value.GetType() == parameter.GetType())
{
return value.Equals(parameter);
}

return value;
}

Expand Down

0 comments on commit b3f2937

Please sign in to comment.