stability improvements
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
Michele Scandura 2021-09-22 16:16:46 +01:00
parent 79edfcc4d3
commit 333c6c4046
37 changed files with 286 additions and 174 deletions

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Sledgemapper.Api.Models;
using Sledgemapper.Entities;
namespace Sledgemapper.Api.Core.Entities
{

View File

@ -7,6 +7,8 @@ using System.Threading.Tasks;
using System.Linq;
using Sledgemapper.Api.Models;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Core.Entities;
using Session = Sledgemapper.Shared.Entities.Session;
namespace Sledgemapper.Api.Handlers
{
@ -104,8 +106,8 @@ namespace Sledgemapper.Api.Handlers
Timestamp = mapUpdates.Max(mapSession => mapSession.Timestamp),
Object = JsonSerializer.Serialize(mapSession)
};
await _dbcontext.Snapshots.AddAsync(newSnapshot);
await _dbcontext.SaveChangesAsync();
await _dbcontext.Snapshots.AddAsync(newSnapshot, cancellationToken);
await _dbcontext.SaveChangesAsync(cancellationToken);
}
return mapSession;
}

View File

@ -4,6 +4,7 @@ using Sledgemapper.Api.Infrastructure.Data;
using System;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Core.Entities;
namespace Sledgemapper.Api.Handlers
{
@ -22,18 +23,18 @@ namespace Sledgemapper.Api.Handlers
{
try
{
var user = await _dbcontext.Users.FindAsync(notification.UserId);
var user = await _dbcontext.Users.FindAsync(notification.UserId, cancellationToken);
_dbcontext.Attach(user);
var campaign = new Core.Entities.Campaign
{
CampaignName = notification.CampaignName,
OwnerId = user.Id,
InvitedUsers = new System.Collections.Generic.List<Entities.User> { user }
InvitedUsers = new System.Collections.Generic.List<User> { user }
};
_dbcontext.Campaigns.Add(campaign);
await _dbcontext.SaveChangesAsync();
await _dbcontext.SaveChangesAsync(cancellationToken);
return true;
}
catch (Exception ex)

View File

@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using Sledgemapper.Api.Commands;
using Sledgemapper.Api.Core.Entities;
namespace Sledgemapper.Api.Handlers
{
@ -21,15 +22,15 @@ namespace Sledgemapper.Api.Handlers
var session = _dbcontext.Sessions.First(m => m.SessionName == notification.SessionName);
var newSnapshot = new Models.Snapshot
var newSnapshot = new Snapshot
{
SessionId = session.SessionId,
Timestamp = notification.Timestamp,
Object = JsonSerializer.Serialize(notification.Session)
};
await _dbcontext.Snapshots.AddAsync(newSnapshot);
await _dbcontext.SaveChangesAsync();
await _dbcontext.Snapshots.AddAsync(newSnapshot, cancellationToken);
await _dbcontext.SaveChangesAsync(cancellationToken);
return true;
}

View File

@ -2,9 +2,9 @@ using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sledgemapper.Api.Hubs;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Clients;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Shared.Clients;
namespace Sledgemapper.Api.Handlers
{

View File

@ -2,9 +2,9 @@ using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sledgemapper.Api.Hubs;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Clients;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Shared.Clients;
namespace Sledgemapper.Api.Handlers
{

View File

@ -1,10 +1,10 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Clients;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Hubs;
using Sledgemapper.Shared.Clients;
namespace Sledgemapper.Api.Handlers
{

View File

@ -1,10 +1,10 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Clients;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Hubs;
using Sledgemapper.Shared.Clients;
namespace Sledgemapper.Api.Handlers
{

View File

@ -1,10 +1,10 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Clients;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Hubs;
using Sledgemapper.Shared.Clients;
namespace Sledgemapper.Api.Handlers
{

View File

@ -1,10 +1,10 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Clients;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Hubs;
using Sledgemapper.Shared.Clients;
namespace Sledgemapper.Api.Handlers
{

View File

@ -1,10 +1,10 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Sledgemapper.Api.Notifications;
using Sledgemapper.Clients;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Hubs;
using Sledgemapper.Shared.Clients;
namespace Sledgemapper.Api.Handlers
{

View File

@ -5,6 +5,7 @@ using Sledgemapper.Api.Models;
using System;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Core.Entities;
namespace Sledgemapper.Api.Handlers
{

View File

@ -1,6 +1,6 @@
using AutoMapper;
using Sledgemapper.Entities;
using Sledgemapper.Models.Users;
using Sledgemapper.Api.Core.Entities;
using Sledgemapper.Api.Models;
namespace Sledgemapper.Api.Helpers
{

View File

@ -1,8 +1,6 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Sledgemapper.Api.Core.Entities;
using Sledgemapper.Api.Models;
using Sledgemapper.Entities;
namespace Sledgemapper.Api.Infrastructure.Data
{

View File

@ -1,6 +1,6 @@
using MediatR;
using System;
using Sledgemapper.Shared.Entities;
using Sledgemapper.Api.Core.Entities;
namespace Sledgemapper.Api.Notifications
{

View File

@ -1,4 +1,5 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
{
public Note Note { get; private set; }
public DeleteNoteNotification(Models.Session session, Note note, string userId) : base(session, userId)
public DeleteNoteNotification(Session session, Note note, string userId) : base(session, userId)
{
Note = note;
}

View File

@ -1,4 +1,6 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
{
public Overlay Overlay { get; private set; }
public DeleteOverlayNotification(Models.Session session, Overlay overlay, string userId) : base(session, userId)
public DeleteOverlayNotification(Session session, Overlay overlay, string userId) : base(session, userId)
{
Overlay = overlay;
}

View File

@ -1,4 +1,6 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
{
public Tile Tile { get; private set; }
public DeleteTileNotification(Models.Session session, Tile tile, string userId) : base(session, userId)
public DeleteTileNotification(Session session, Tile tile, string userId) : base(session, userId)
{
Tile = tile;
}

View File

@ -1,4 +1,5 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
{
public Wall Wall { get; private set; }
public DeleteWallNotification(Models.Session session, Wall wall, string userId) : base(session, userId)
public DeleteWallNotification(Session session, Wall wall, string userId) : base(session, userId)
{
Wall = wall;
}

View File

@ -1,4 +1,6 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
{
public Line Line { get; private set; }
public NewLineNotification(Models.Session session, Line line, string userId) : base(session, userId)
public NewLineNotification(Session session, Line line, string userId) : base(session, userId)
{
Line = line;
}

View File

@ -1,4 +1,5 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{

View File

@ -1,4 +1,5 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
{
public Overlay Overlay { get; private set; }
public NewOverlayNotification(Models.Session session, Overlay overlay, string userId) : base(session, userId)
public NewOverlayNotification(Session session, Overlay overlay, string userId) : base(session, userId)
{
Overlay = overlay;
}

View File

@ -1,4 +1,5 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
{
public Room Room { get; private set; }
public NewRoomNotification(Models.Session session, Room room, string userId) : base(session, userId)
public NewRoomNotification(Session session, Room room, string userId) : base(session, userId)
{
Room = room;
}

View File

@ -1,8 +1,10 @@
using Sledgemapper.Api.Core.Entities;
namespace Sledgemapper.Api.Notifications
{
public class NewSessionNotification : BaseNotification
{
public NewSessionNotification(string sessionName, string userId) : base(new Models.Session { SessionName = sessionName }, userId)
public NewSessionNotification(string sessionName, string userId) : base(new Session { SessionName = sessionName }, userId)
{ }
}
}

View File

@ -1,4 +1,6 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
{
public Tile Tile { get; private set; }
public NewTileNotification(Models.Session session, Tile tile, string userId) : base(session, userId)
public NewTileNotification(Session session, Tile tile, string userId) : base(session, userId)
{
Tile = tile;
}

View File

@ -1,4 +1,5 @@
using Sledgemapper.Shared.Entities;
using Session = Sledgemapper.Api.Core.Entities.Session;
namespace Sledgemapper.Api.Notifications
{

View File

@ -12,6 +12,7 @@ using System.Text;
using Sledgemapper.Api.Hubs;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Sledgemapper.Api.Core.Entities;
namespace Sledgemapper.Api
{
@ -69,7 +70,7 @@ namespace Sledgemapper.Api
};
});
services.AddDefaultIdentity<Entities.User>(options => options.SignIn.RequireConfirmedAccount = false)
services.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<SledgemapperDbContext>();
services.AddSwaggerGen(c =>
@ -95,7 +96,7 @@ namespace Sledgemapper.Api
Id = "Bearer"
}
},
new string[] { }
Array.Empty<string>()
}
});
});

View File

@ -0,0 +1,38 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace Sledgemapper
{
internal class AuthenticatedHttpClientHandler : HttpClientHandler
{
private readonly Func<Task<string>> _getToken;
public AuthenticatedHttpClientHandler(Func<Task<string>> getToken)
{
_getToken = getToken ?? throw new ArgumentNullException(nameof(getToken));
//if (myConfigurationService.VerifySslCertificate == false)
//{
ServerCertificateCustomValidationCallback =
(message, certificate, chain, sslPolicyErrors) => true;
//}
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
// See if the request has an authorize header
var auth = request.Headers.Authorization;
if (auth != null)
{
var token = await _getToken().ConfigureAwait(false);
request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, token);
}
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
}

View File

@ -2,15 +2,19 @@ using System;
using System.Threading.Tasks;
using System.Threading.Channels;
using Sentry;
using Sledgemapper.Messages;
using TinyMessenger;
namespace Sledgemapper
{
public class ChannelsQueue
{
public TinyMessengerHub Messenger { get; }
private readonly ChannelWriter<Action> _writer;
public ChannelsQueue()
public ChannelsQueue(TinyMessenger.TinyMessengerHub messenger)
{
Messenger = messenger;
var channel = Channel.CreateUnbounded<Action>(new UnboundedChannelOptions() { SingleReader = true });
var reader = channel.Reader;
_writer = channel.Writer;
@ -19,8 +23,8 @@ namespace Sledgemapper
{
while (await reader.WaitToReadAsync())
{
// Fast loop around available jobs
while (reader.TryRead(out var job))
// Fast loop around available jobs
while (reader.TryRead(out var job))
{
try
{
@ -29,7 +33,7 @@ namespace Sledgemapper
catch (Exception ex)
{
SentrySdk.CaptureException(ex);
throw;
messenger.Publish(new ErrorMessage(this, ex.Message));
}
}
}

View File

@ -1,32 +1,50 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;
using Polly;
using Polly.Retry;
using Refit;
using SharpFontInternal;
using Sledgemapper.Messages;
using Sledgemapper.Shared.Entities;
using TinyMessenger;
namespace Sledgemapper
{
public class CommunicationManager
{
private readonly ChannelsQueue _queue = new();
public TinyMessengerHub Messenger { get; }
public IMapApi Api { get; }
public HubConnection Connection { get; }
private readonly ChannelsQueue _queue;
private readonly AsyncRetryPolicy _retryPolicy;
public readonly Session SessionData;
private AuthenticateResponse _authenticateResponse;
public CommunicationManager(Session sessionData)
public CommunicationManager(Session sessionData, TinyMessengerHub messenger)
{
Messenger = messenger;
_queue = new ChannelsQueue(Messenger);
#if DEBUG
var baseAddress = "http://localhost:5000";
#else
var baseAddress = "http://hub.michelescandura.com:5000";
#endif
_retryPolicy = Policy
.Handle<ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.Or<HttpRequestException>()
.RetryAsync(3);
//.RetryAsync(Polly.RetrySyntax., async (exception, retryCount) => await Task.Delay(500))
SessionData = sessionData;
Connection = new HubConnectionBuilder()
.WithAutomaticReconnect()
@ -132,9 +150,6 @@ namespace Sledgemapper
Connection.On<Ping>("Ping", ping => { SessionData.Pings.TryAdd(Guid.NewGuid(), ping); });
}
public IMapApi Api { get; }
public HubConnection Connection { get; }
public void Enqueue(BaseMapEntity entity, TileAction action)
{
switch (action)
@ -209,30 +224,81 @@ namespace Sledgemapper
{
await Policy
.Handle<ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.Or<HttpRequestException>()
.RetryForeverAsync()
//.RetryAsync(Polly.RetrySyntax., async (exception, retryCount) => await Task.Delay(500))
.ExecuteAsync(async () => await call().ConfigureAwait(false))
.ConfigureAwait(false);
}
private Task<string> GetToken()
{
return Task.FromResult(_authenticateResponse.Token);
return Task.FromResult(_authenticateResponse?.Token ?? "");
}
public async Task<List<Campaign>> GetCampaigns()
{
try
{
return await _retryPolicy.ExecuteAsync(Api.GetCampaigns);
}
catch (Exception e)
{
Sentry.SentrySdk.CaptureException(e);
Messenger.Publish(new ErrorMessage(this, "Error loading campaigns"));
}
return null;
}
public async Task<List<Session>> GetMaps(Guid campaignId)
{
try
{
return await _retryPolicy.ExecuteAsync(() => Api.GetMaps(campaignId));
}
catch (Exception e)
{
Sentry.SentrySdk.CaptureException(e);
Messenger.Publish(new ErrorMessage(this, "Error loading maps"));
}
return null;
}
public async Task<List<Player>> GetPlayers(Guid campaignId)
{
try
{
return await _retryPolicy.ExecuteAsync(() => Api.GetPlayers(campaignId));
}
catch (Exception e)
{
Sentry.SentrySdk.CaptureException(e);
Messenger.Publish(new ErrorMessage(this, "Error loading players"));
}
return null;
}
public async Task<AuthenticateResponse> Login(AuthenticateModel authenticateModel)
{
_authenticateResponse = await Api.Authenticate(authenticateModel).ConfigureAwait(false);
_authenticateResponse = await Policy
.Handle<ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.Or<HttpRequestException>()
.RetryAsync(3)
//.RetryAsync(Polly.RetrySyntax., async (exception, retryCount) => await Task.Delay(500))
.ExecuteAsync(async () => await Api.Authenticate(authenticateModel))
.ConfigureAwait(false);
//_authenticateResponse = await Api.Authenticate(authenticateModel).ConfigureAwait(false);
return _authenticateResponse;
}
internal async Task Ping(Tile location)
{
if (Connection is { State: HubConnectionState.Connected })
{
await Connection.InvokeAsync("Ping", SessionData.SessionName, location);
}
}
public async Task<IMapApi.AuthResult> Register(RegisterModel registerModel)
@ -241,34 +307,4 @@ namespace Sledgemapper
return result;
}
}
internal class AuthenticatedHttpClientHandler : HttpClientHandler
{
private readonly Func<Task<string>> _getToken;
public AuthenticatedHttpClientHandler(Func<Task<string>> getToken)
{
_getToken = getToken ?? throw new ArgumentNullException(nameof(getToken));
//if (myConfigurationService.VerifySslCertificate == false)
//{
ServerCertificateCustomValidationCallback =
(message, certificate, chain, sslPolicyErrors) => true;
//}
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
// See if the request has an authorize header
var auth = request.Headers.Authorization;
if (auth != null)
{
var token = await _getToken().ConfigureAwait(false);
request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, token);
}
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
}

View File

@ -1,77 +1,60 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Myra.Graphics2D.UI;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Myra.Graphics2D.Brushes;
using Myra.Graphics2D.UI;
namespace Sledgemapper
{
public static class ExtensionMethods
{
public static Dictionary<string, T> LoadContentFolder<T>(this ContentManager contentManager, string contentFolder)
{
DirectoryInfo dir = new(contentManager.RootDirectory + "/" + contentFolder);
if (!dir.Exists)
throw new DirectoryNotFoundException();
Dictionary<string, T> result = new();
FileInfo[] files = dir.GetFiles("*.*");
foreach (FileInfo file in files.Where(f => f.Extension != ".ttf" && f.Extension != ".otf"))
{
result.Add(file.Name.Split('.')[0], contentManager.Load<T>(contentFolder + "/" + file.Name.Split('.')[0]));
}
return result;
}
public static IEnumerable<string> Split(this string str, int chunkSize) => Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize));
public static Point AbsPoint(this Point point)
{
return new Point(System.Math.Abs(point.X), System.Math.Abs(point.Y));
}
public static (Window Window, C Content) GetParentContentInWindow<C>(this Widget widget) where C : Widget
{
Container container = widget.Parent;
while (!(container is Window))
{
container = container.Parent;
}
var localWindow = (Window)container;
var localContent = localWindow.Content as C;
return (localWindow, localContent);
return new Point(Math.Abs(point.X), Math.Abs(point.Y));
}
public static Window GetContainingWindow(this Widget widget)
{
var container = widget.Parent;
while (!(container is Window) || container is null)
{
container = container.Parent;
}
while (container is not Window or null) container = container.Parent;
return container as Window;
}
public static bool ValidateTextbox(this TextBox textBox)
public static (Window Window, TC Content) GetParentContentInWindow<TC>(this Widget widget) where TC : Widget
{
var valid = !string.IsNullOrWhiteSpace(textBox.Text);
if (!valid)
var container = widget.Parent;
while (container is not Window) container = container.Parent;
var localWindow = (Window)container;
var localContent = localWindow.Content as TC;
return (localWindow, localContent);
}
public static Dictionary<string, T> LoadContentFolder<T>(this ContentManager contentManager, string contentFolder)
{
DirectoryInfo dir = new(contentManager.RootDirectory + "/" + contentFolder);
if (!dir.Exists)
{
textBox.Background = new SolidBrush(Color.Red);
throw new DirectoryNotFoundException();
}
else
Dictionary<string, T> result = new();
var files = dir.GetFiles("*.*");
foreach (var file in files.Where(f => f.Extension != ".ttf" && f.Extension != ".otf"))
{
textBox.Background = new SolidBrush(new Color(51, 51, 51)); ;
result.Add(file.Name.Split('.')[0], contentManager.Load<T>(contentFolder + "/" + file.Name.Split('.')[0]));
}
return valid;
return result;
}
public static void ShowInModalWindow(this Widget widget, Desktop desktop, string title)
@ -79,29 +62,35 @@ namespace Sledgemapper
Window window = new()
{
Title = title,
Content=widget
Content = widget
};
window.ShowModal(desktop);
}
public static void Toast(this Widget widget, Desktop desktop, string title)
public static IEnumerable<string> Split(this string str, int chunkSize)
{
Window window = new()
{
Content = widget
};
window.Show(desktop, new Point(desktop.BoundsFetcher().X-200, desktop.BoundsFetcher().Y - 200));
Task.Delay(500).ContinueWith(_=>window.Close()).SafeFireAndForget();
return Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize));
}
public static void Toast(this Widget widget, Desktop desktop)
{
widget.Left = desktop.BoundsFetcher().Center.X - widget.Width.Value / 2;
widget.Top = desktop.BoundsFetcher().Height - 90;
widget.ZIndex = 1000;
desktop.Widgets.Add(widget);
Task.Delay(2000).ContinueWith(_ => { desktop.Widgets.Remove(widget); }
).SafeFireAndForget();
}
public static bool ValidateTextbox(this TextBox textBox)
{
var valid = !string.IsNullOrWhiteSpace(textBox.Text);
textBox.Background = valid ? new SolidBrush(new Color(51, 51, 51)) : new SolidBrush(Color.Red);
return valid;
}
}
//public interface IExtendedWidget
//{
// void ShowInModalWindow(this Widget widget, string title)
//}
}
}

View File

@ -39,7 +39,7 @@ namespace Sledgemapper
Task<List<Campaign>> GetCampaigns();
[Get("/campaign/{campaignName}/players")]
Task<List<Player>> GetPlayers(string campaignName);
Task<List<Player>> GetPlayers(Guid campaignName);
[Get("/campaign/{campaignName}/maps")]

View File

@ -60,13 +60,12 @@ namespace Sledgemapper
_sessionData = new Session();
IsFixedTimeStep = true;
TargetElapsedTime = TimeSpan.FromSeconds(1d / 30d);
_communicationManager = new CommunicationManager(_sessionData);
_messenger = new TinyMessengerHub();
_communicationManager = new CommunicationManager(_sessionData,_messenger);
_communicationManager.Connection.Reconnected += OnHubReconnected;
_communicationManager.Connection.Reconnecting += OnHubReconnecting;
_communicationManager.Connection.Closed += OnHubDisconnected;
_state = State.Instance;
_messenger = new TinyMessengerHub();
}
protected override void Draw(GameTime gameTime)

View File

@ -44,7 +44,7 @@ namespace Sledgemapper.UI
private void OnMenuCampaignNew(object sender, EventArgs e)
{
if (sender is MenuItem && !((MenuItem)sender).Enabled)
if (sender is MenuItem { Enabled: false })
{
return;
}
@ -61,24 +61,37 @@ namespace Sledgemapper.UI
var list = item.Parent as Grid;
for (var i = 0; i < list.ChildrenCount; i++)
{
var currentItem = list.GetChild(i) as HorizontalStackPanel;// UI.ListItem;
currentItem.Background = new SolidBrush("#D9D9D9FF");
if (list.GetChild(i) is HorizontalStackPanel currentItem) currentItem.Background = new SolidBrush("#D9D9D9FF");
}
item.Background = new SolidBrush(Settings.Instance.OverlayTintColor);
_campaignSelected = true;
}
public async Task LoadCampaigns()
public async Task<bool> LoadCampaigns()
{
var campaigns = await CommunicationManager.Api.GetCampaigns();
var campaigns = await CommunicationManager.GetCampaigns();
if (campaigns is null)
{
return false;
}
foreach (var campaign in campaigns)
{
var item = new ListItem();
item.ItemName.Text = campaign.Name;
item.Tag = campaign.Id;
var item = new ListItem
{
ItemName =
{
Text = campaign.Name
},
Tag = campaign.Id
};
item.TouchUp += OnCampaignSelected;
StackCampaignsList.AddChild(item);
}
return true;
}
}
}

View File

@ -111,7 +111,7 @@ namespace Sledgemapper.UI
private void OnBtnToolbarDeleteClicked(object sender, EventArgs e)
{
Messenger.Publish(new ErrorMessage(this,"test"));
Messenger.Publish(new ErrorMessage(this, "test"));
State.Instance.InsertMode = InsertMode.NewDelete;
ClearSelection();
@ -201,7 +201,7 @@ namespace Sledgemapper.UI
private void OnErrorMessage(ErrorMessage obj)
{
new ErrorWindow(obj.Message).Toast(Desktop,null);
new ErrorWindow(obj.Message).Toast(Desktop);
}
private void OneMenuFileSettingsSelected(object sender, EventArgs e)
@ -273,7 +273,7 @@ namespace Sledgemapper.UI
private void OnMenuCampaignNew(object sender, EventArgs e)
{
if (sender is MenuItem && !((MenuItem)sender).Enabled) return;
if (sender is MenuItem { Enabled: false }) return;
new CampaignWindow(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "New campaign");
;
@ -284,8 +284,10 @@ namespace Sledgemapper.UI
if (!((MenuItem)sender).Enabled) return;
var content = new CampaignList(CommunicationManager, Messenger);
await content.LoadCampaigns();
content.ShowInModalWindow(Desktop, "Campaigns");
if (await content.LoadCampaigns())
{
content.ShowInModalWindow(Desktop, "Campaigns");
}
}
private async void OnMenuCampaignPlayersSelected(object sender, EventArgs e)
@ -293,8 +295,10 @@ namespace Sledgemapper.UI
if (!((MenuItem)sender).Enabled) return;
var content = new PlayerList(CommunicationManager);
await content.LoadPlayers();
content.ShowInModalWindow(Desktop, "Players");
if (await content.LoadPlayers())
{
content.ShowInModalWindow(Desktop, "Players");
}
}
private void OnMenuConnectLoginSelected(object sender, EventArgs e)
@ -373,7 +377,7 @@ namespace Sledgemapper.UI
private void OnMenuMapNew(object sender, EventArgs e)
{
if (sender is MenuItem && !((MenuItem)sender).Enabled) return;
if (sender is MenuItem { Enabled: false }) return;
new MapWindow(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "New map");
}
@ -383,8 +387,10 @@ namespace Sledgemapper.UI
if (!((MenuItem)sender).Enabled) return;
var content = new MapList(CommunicationManager, Messenger);
await content.LoadMaps();
content.ShowInModalWindow(Desktop, "Maps");
if (await content.LoadMaps())
{
content.ShowInModalWindow(Desktop, "Maps");
}
}
private void OnMenuViewCenterOnSelectionSelected(object sender, EventArgs e)
@ -394,11 +400,6 @@ namespace Sledgemapper.UI
private void OnMenuViewNotesSelected(object sender, EventArgs e)
{
Window window = new()
{
Title = "Notes"
};
new NoteList(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "Notes");
}

View File

@ -39,9 +39,14 @@ namespace Sledgemapper.UI
this.GetContainingWindow().Close();
}
public async Task LoadMaps()
public async Task<bool> LoadMaps()
{
var campaigns = await CommunicationManager.Api.GetMaps(State.Instance.CampaignId);
var campaigns = await CommunicationManager.GetMaps(State.Instance.CampaignId);
if (campaigns is null)
{
return false;
}
foreach (var campaign in campaigns)
{
var item = new ListItem();
@ -50,6 +55,8 @@ namespace Sledgemapper.UI
item.TouchUp += OnMapSelected;
StackCampaignsList.AddChild(item);
}
return true;
}
private void OnMapSelected(object sender, EventArgs e)

View File

@ -19,15 +19,21 @@ namespace Sledgemapper.UI
};
}
public async Task LoadPlayers()
public async Task<bool> LoadPlayers()
{
var players = await CommunicationManager.Api.GetPlayers(State.Instance.CampaignName);
var players = await CommunicationManager.GetPlayers(State.Instance.CampaignId);
if (players is null)
{
return false;
}
foreach (var player in players)
{
var item = new ListItem();
item.ItemName.Text = player.UserName;
StackCampaignsList.AddChild(item);
}
return true;
}
private void ShowAddPLayerWindow()