diff --git a/Sledgemapper.Api/Commands/NewNoteCommand.cs b/Sledgemapper.Api/Commands/NewNoteCommand.cs new file mode 100644 index 0000000..5c2dfb6 --- /dev/null +++ b/Sledgemapper.Api/Commands/NewNoteCommand.cs @@ -0,0 +1,14 @@ +using Sledgemapper.Shared.Entities; + +namespace Sledgemapper.Api.Commands +{ + public class NewNoteCommand : BaseCommand + { + public Note Note { get; private set; } + + public NewNoteCommand(string sessionName, Note note, int userId) : base(sessionName, userId) + { + Note = note; + } + } +} diff --git a/Sledgemapper.Api/Controllers/SessionController.cs b/Sledgemapper.Api/Controllers/SessionController.cs index fbf2f7c..9e4df30 100644 --- a/Sledgemapper.Api/Controllers/SessionController.cs +++ b/Sledgemapper.Api/Controllers/SessionController.cs @@ -54,6 +54,12 @@ namespace Sledgemapper.Api.Controllers await _mediator.Send(new NewWallCommand(sessionName, wall, UserId)); } + [HttpPost("note")] + public async Task Post(string sessionName, [FromBody] Note note) + { + await _mediator.Send(new NewNoteCommand(sessionName, note, UserId)); + } + [HttpDelete("tile")] public async Task Delete(string sessionName, [FromBody] Tile tile) { diff --git a/Sledgemapper.Api/Handlers/NewWallCommandHandler.cs b/Sledgemapper.Api/Handlers/NewWallCommandHandler.cs index af69b69..a1a34ea 100644 --- a/Sledgemapper.Api/Handlers/NewWallCommandHandler.cs +++ b/Sledgemapper.Api/Handlers/NewWallCommandHandler.cs @@ -36,4 +36,31 @@ namespace Sledgemapper.Api.Handlers return true; } } + + public class NewNoteCommandHandler : IRequestHandler + { + private readonly MyDbContext _dbcontext; + + private readonly IMediator _mediator; + + public NewNoteCommandHandler(IMediator mediator, MyDbContext dbcontext) { _dbcontext = dbcontext; _mediator = mediator; } + + public async Task Handle(NewNoteCommand notification, CancellationToken cancellationToken) + { + var jsonString = JsonSerializer.Serialize(notification.Note); + var session = _dbcontext.Sessions.First(m => m.SessionName == notification.SessionName); + _dbcontext.MapLogs.Add(new Sledgemapper.Api.Models.MapLog + { + Operation = "N", + SessionId = session.SessionId, + Type = "N", + Timestamp = notification.Timestamp, + Object = jsonString, + UserId = notification.UserId, + }); + await _dbcontext.SaveChangesAsync(); + await _mediator.Publish(new NewNoteNotification(session, notification.Note, notification.UserId)); + return true; + } + } } diff --git a/Sledgemapper.Api/Handlers/SendNewWallMessage.cs b/Sledgemapper.Api/Handlers/SendNewWallMessage.cs index 34d5567..699ff55 100644 --- a/Sledgemapper.Api/Handlers/SendNewWallMessage.cs +++ b/Sledgemapper.Api/Handlers/SendNewWallMessage.cs @@ -19,4 +19,16 @@ namespace Sledgemapper.Api.Handlers await _hub.Clients.Groups(notification.Session.SessionName).NewWall(notification.Wall); } } + + public class SendNewNoteMessage : INotificationHandler + { + private readonly IHubContext _hub; + + public SendNewNoteMessage(IHubContext hub) => _hub = hub; + + public async Task Handle(NewNoteNotification notification, CancellationToken cancellationToken) + { + await _hub.Clients.Groups(notification.Session.SessionName).NewNote(notification.Note); + } + } } diff --git a/Sledgemapper.Api/Hubs/SledgemapperHub.cs b/Sledgemapper.Api/Hubs/SledgemapperHub.cs index cb16740..5ccd453 100644 --- a/Sledgemapper.Api/Hubs/SledgemapperHub.cs +++ b/Sledgemapper.Api/Hubs/SledgemapperHub.cs @@ -56,6 +56,11 @@ namespace Sledgemapper.Api.Hubs await Clients.Group(sessionName).NewOverlay(tile); } + public async Task NewNote(string sessionName, Note note) + { + await Clients.Group(sessionName).NewNote(note); + } + public async Task DeleteTile(string sessionName, Tile tile) { await Clients.Group(sessionName).DeleteTile(tile); diff --git a/Sledgemapper.Api/Notifications/NewNoteNotification.cs b/Sledgemapper.Api/Notifications/NewNoteNotification.cs new file mode 100644 index 0000000..bf65b42 --- /dev/null +++ b/Sledgemapper.Api/Notifications/NewNoteNotification.cs @@ -0,0 +1,14 @@ +using Sledgemapper.Shared.Entities; + +namespace Sledgemapper.Api.Notifications +{ + public class NewNoteNotification : BaseNotification + { + public Note Note { get; private set; } + + public NewNoteNotification(Models.Session session, Note note, int userId) : base(session, userId) + { + Note = note; + } + } +} diff --git a/Sledgemapper.Shared/Clients/ISledgemapperClient.cs b/Sledgemapper.Shared/Clients/ISledgemapperClient.cs index eb2f426..3dfdd71 100644 --- a/Sledgemapper.Shared/Clients/ISledgemapperClient.cs +++ b/Sledgemapper.Shared/Clients/ISledgemapperClient.cs @@ -8,6 +8,7 @@ namespace Sledgemapper.Clients Task NewTile(Tile tile); Task NewWall(Wall wall); Task NewOverlay(Overlay overlay); + Task NewNote(Note note); Task DeleteTile(Tile tile); Task DeleteWall(Wall wall); Task DeleteOverlay(Overlay overlay); diff --git a/Sledgemapper.Shared/Entities/Session.cs b/Sledgemapper.Shared/Entities/Session.cs index 692471f..ab1faa5 100644 --- a/Sledgemapper.Shared/Entities/Session.cs +++ b/Sledgemapper.Shared/Entities/Session.cs @@ -101,6 +101,23 @@ namespace Sledgemapper.Shared.Entities OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newWall)); } + public void NewNote(Note selectedNote) + { + if (selectedNote is null) + { + return; + } + var noteExists = Notes.TryGetValue(selectedNote.ToString(), out var note); + var newNote = new Note { X = selectedNote.X, Y = selectedNote.Y, Text=selectedNote.Text }; + if (noteExists) + { + Walls.TryRemove(note.ToString(), out var _); + } + + Notes.TryAdd(newNote.ToString(), newNote); + OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newNote)); + } + public void DeleteWall(Wall wall) { if (wall is null) @@ -114,6 +131,19 @@ namespace Sledgemapper.Shared.Entities } } + public void DeleteNote(Note note) + { + if (note is null) + { + return; + } + var removed = Notes.TryRemove(note.ToString(), out var _); + if (removed) + { + OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(note)); + } + } + public void DeleteOverlay(Overlay overlay) { if (overlay is null) diff --git a/Sledgemapper/CommunicationManager.cs b/Sledgemapper/CommunicationManager.cs index ebe1818..ea28c64 100644 --- a/Sledgemapper/CommunicationManager.cs +++ b/Sledgemapper/CommunicationManager.cs @@ -42,7 +42,7 @@ namespace Sledgemapper new HttpClient(new AuthenticatedHttpClientHandler(GetToken)) { BaseAddress = new Uri("http://hub.michelescandura.com:5000") - // BaseAddress = new Uri("http://localhost:5001") + // BaseAddress = new Uri("http://localhost:5001") } ); @@ -107,6 +107,12 @@ namespace Sledgemapper SessionData.Overlays.TryAdd(tile.ToString(), tile); }); + Connection.On("NewNote", (note) => + { + //SessionData.Notes.Remove(note.ToString(), out var _); + SessionData.Notes.AddOrUpdate(note.ToString(), note, (key, oldnote) => note); + }); + Connection.On("NewPlayer", (player) => { var p = SessionData.Players.FirstOrDefault(m => m.UserId == player.UserId); @@ -165,6 +171,9 @@ namespace Sledgemapper case Wall wall: Queue.Enqueue(async () => await Execute(async () => await Api.NewWall(wall, SessionData.SessionName).ConfigureAwait(false))); break; + case Note note: + Queue.Enqueue(async () => await Execute(async () => await Api.NewNote(note, SessionData.SessionName).ConfigureAwait(false))); + break; } break; @@ -180,6 +189,9 @@ namespace Sledgemapper case Wall wall: Queue.Enqueue(async () => await Execute(async () => await Api.DeleteWall(wall, SessionData.SessionName).ConfigureAwait(false))); break; + case Note note: + Queue.Enqueue(async () => await Execute(async () => await Api.DeleteNote(note, SessionData.SessionName).ConfigureAwait(false))); + break; } break; } diff --git a/Sledgemapper/IMapApi.cs b/Sledgemapper/IMapApi.cs index aa369d4..5b0ebc5 100644 --- a/Sledgemapper/IMapApi.cs +++ b/Sledgemapper/IMapApi.cs @@ -23,6 +23,9 @@ namespace Sledgemapper [Post("/session/{sessionName}/overlay")] Task NewOverlay([Body] Overlay overlay, string sessionName); + [Post("/session/{sessionName}/note")] + Task NewNote([Body] Note note, string sessionName); + [Post("/session/{sessionName}/wall")] Task NewWall([Body] Wall overlay, string sessionName); @@ -35,12 +38,15 @@ namespace Sledgemapper [Delete("/session/{sessionName}/overlay")] Task DeleteOverlay([Body] Overlay overlay, string sessionName); + [Delete("/session/{sessionName}/note")] + Task DeleteNote([Body] Note overlay, string sessionName); - [Headers("Authorization")] + + [Headers("Authorization")] [Post("/users/register")] Task Register([Body] RegisterModel registerModel); - [Headers("Authorization")] + [Headers("Authorization")] [Post("/users/authenticate")] Task Authenticate([Body] AuthenticateModel registerModel); } diff --git a/Sledgemapper/Sledgemapper.cs b/Sledgemapper/Sledgemapper.cs index d5fa279..8a6e2bc 100644 --- a/Sledgemapper/Sledgemapper.cs +++ b/Sledgemapper/Sledgemapper.cs @@ -57,7 +57,7 @@ namespace Sledgemapper _communicationManager.Connection.Reconnecting += OnHubReconnecting; _communicationManager.Connection.Closed += OnHubDisconnected; _state = new State(); - _settings= new Settings(); + _settings = new Settings(); } private async Task OnHubDisconnected(Exception arg) @@ -137,17 +137,17 @@ namespace Sledgemapper private void OneMenuFileSettingsSelected(object sender, EventArgs e) { - var propertyGrid = new PropertyGrid - { - Object = _settings, - Width = 350 - }; + var propertyGrid = new PropertyGrid + { + Object = _settings, + Width = 350 + }; - var _windowEditor = new Window - { - Title = "Object Editor", - Content = propertyGrid - }; + var _windowEditor = new Window + { + Title = "Object Editor", + Content = propertyGrid + }; _windowEditor.ShowModal(_desktop); } @@ -269,9 +269,29 @@ namespace Sledgemapper _state.SelectedNote.X = _state.HoveredTile.X; _state.SelectedNote.Y = _state.HoveredTile.Y; - var contextMenu = new TextButton { Text = "New Note" }; - contextMenu.Click += OnContextMenuNewNoteClick; - _desktop.ShowContextMenu(contextMenu, mouseState.Position); + var popup = new VerticalStackPanel { Padding = new Myra.Graphics2D.Thickness(1), Spacing = 2, Background = new SolidBrush(Color.DarkGray) }; + + if (!_sessionData.Notes.ContainsKey(_state.SelectedNote.ToString())) + { + var newNoteButton = new TextButton { Text = "New Note", Width = 80, Height = 20, Padding = new Myra.Graphics2D.Thickness(2), HorizontalAlignment = HorizontalAlignment.Left }; + newNoteButton.Click += OnContextMenuNewNoteClick; + popup.AddChild(newNoteButton); + } + else + { + _sessionData.Notes.TryGetValue(_state.SelectedNote.ToString(), out var n); + _state.SelectedNote = n; + var viewNoteButton = new TextButton { Text = "View Note", Width = 80, Height = 20, Padding = new Myra.Graphics2D.Thickness(2), HorizontalAlignment = HorizontalAlignment.Left }; + var deleteNoteButton = new TextButton { Text = "Delete Note", Width = 80, Height = 20, Padding = new Myra.Graphics2D.Thickness(2), HorizontalAlignment = HorizontalAlignment.Left }; + viewNoteButton.Click += OnContextMenuViewNoteClick; + deleteNoteButton.Click += OnContextMenuDeleteNoteClick; + + + popup.AddChild(viewNoteButton); + popup.AddChild(deleteNoteButton); + } + + _desktop.ShowContextMenu(popup, mouseState.Position); } if (newState.IsKeyDown(Keys.LeftControl) @@ -590,8 +610,8 @@ namespace Sledgemapper _spriteBatch.Draw( _comment, new Rectangle( - note.X * _state.TileSize + _state.TileSize - (int)(_state.TileSize / 2) + _state.TileSize / 20, - note.Y * _state.TileSize + _state.TileSize / 8 + _state.TileSize / 20, + note.X * _state.TileSize + _state.TileSize - (int)(_state.TileSize / 2) + _state.TileSize / 25, + note.Y * _state.TileSize + _state.TileSize / 8 + _state.TileSize / 25, (int)(_state.TileSize / 2.5), (int)(_state.TileSize / 2.5 / 1.136) ), Color.Black * .2f ); @@ -916,63 +936,14 @@ namespace Sledgemapper var localWindow = (Window)container; var localContent = localWindow.Content as NoteWindow; - - if (!button.Enabled) + var note = new Note { - return; - } - - var isValid = true; - isValid &= ValidateTextbox(localContent.NoteText); - - - if (!isValid) - { - return; - } - - var successful = false; - try - { - var note = new Note - { - X = _state.SelectedNote.X, - Y = _state.SelectedNote.Y, - Text = localContent.NoteText.Text - }; - _sessionData.Notes.AddOrUpdate(note.ToString(), note, (key, oldValue) => note); - - button.Text = "Wait..."; - // localContent.LblLoginError.Text = ""; - // localContent.LblLoginError.Visible = false; - // _authResponse = await _communicationManager.Login(new AuthenticateModel - // { - // Username = localContent.TxtEmail.Text, - // Password = localContent.TxtPassword.Text - // }); - // successful = _authResponse != null; - successful = true; - } - catch (Refit.ApiException refitException) - { - // localContent.LblLoginError.Text = refitException.Content; - // localContent.LblLoginError.Visible = true; - } - catch (Exception ex) - { - // localContent.LblLoginError.Text = "Can't connect to the server"; - // localContent.LblLoginError.Visible = true; - } - finally - { - button.Enabled = true; - button.Text = "OK"; - } - - if (successful) - { - localWindow.Close(); - } + X = _state.SelectedNote.X, + Y = _state.SelectedNote.Y, + Text = localContent.NoteText.Text + }; + _sessionData.NewNote(note); + localWindow.Close(); } private async void OnButtonNoteCancelClick(object sender, EventArgs e) @@ -1162,6 +1133,18 @@ namespace Sledgemapper window.ShowModal(_desktop); } + private void OnContextMenuDeleteNoteClick(object sender, EventArgs e) + { + _desktop.HideContextMenu(); + _sessionData.DeleteNote(_state.SelectedNote); + } + + private void OnContextMenuViewNoteClick(object sender, EventArgs e) + { + _desktop.HideContextMenu(); + EditNote(_state.SelectedNote); + } + private void OnOverlayButtonClicked(object sender, EventArgs e) { _state.CurrentOverlayId = ((ImageButton)sender).Id;