mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-05 15:56:14 +02:00
Initial commit
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
using Decho.Models;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public sealed class ChannelViewModel : ViewModelBase
|
||||
{
|
||||
public ChannelViewModel(ChannelModel model)
|
||||
{
|
||||
Model = model;
|
||||
Messages = new ObservableCollection<MessageViewModel>(
|
||||
model.Messages.Select(message => new MessageViewModel(message)));
|
||||
}
|
||||
|
||||
public ChannelModel Model { get; }
|
||||
|
||||
public string Name => Model.Name;
|
||||
|
||||
public ObservableCollection<MessageViewModel> Messages { get; }
|
||||
|
||||
public void AddMessage(MessageModel message)
|
||||
{
|
||||
Model.Messages.Add(message);
|
||||
Messages.Add(new MessageViewModel(message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public sealed class ChatViewModel : ViewModelBase
|
||||
{
|
||||
private ObservableCollection<MessageViewModel> _messages = new();
|
||||
private string _channelTitle = "Select a channel";
|
||||
|
||||
public ChatViewModel()
|
||||
{
|
||||
Composer = new MessageComposerViewModel();
|
||||
}
|
||||
|
||||
public ObservableCollection<MessageViewModel> Messages
|
||||
{
|
||||
get => _messages;
|
||||
private set => this.RaiseAndSetIfChanged(ref _messages, value);
|
||||
}
|
||||
|
||||
public string ChannelTitle
|
||||
{
|
||||
get => _channelTitle;
|
||||
private set => this.RaiseAndSetIfChanged(ref _channelTitle, value);
|
||||
}
|
||||
|
||||
public MessageComposerViewModel Composer { get; }
|
||||
|
||||
public void SetChannel(ChannelViewModel? channel)
|
||||
{
|
||||
if (channel is null)
|
||||
{
|
||||
Messages = new ObservableCollection<MessageViewModel>();
|
||||
ChannelTitle = "Select a channel";
|
||||
return;
|
||||
}
|
||||
|
||||
Messages = channel.Messages;
|
||||
ChannelTitle = "#" + channel.Name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
using Decho.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public sealed class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
private readonly UserModel _currentUser;
|
||||
|
||||
public string Title { get; } = "Decho";
|
||||
|
||||
public SidebarViewModel Sidebar { get; }
|
||||
|
||||
public ChatViewModel Chat { get; }
|
||||
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
_currentUser = new UserModel("user-1", "You");
|
||||
|
||||
var servers = SeedServers();
|
||||
Sidebar = new SidebarViewModel(servers);
|
||||
Chat = new ChatViewModel();
|
||||
|
||||
Sidebar.WhenAnyValue(x => x.SelectedChannel)
|
||||
.Subscribe(channel => Chat.SetChannel(channel));
|
||||
|
||||
Chat.Composer.SendRequested += HandleSendRequested;
|
||||
|
||||
if (Sidebar.SelectedChannel is not null)
|
||||
Chat.SetChannel(Sidebar.SelectedChannel);
|
||||
}
|
||||
|
||||
private void HandleSendRequested(string text)
|
||||
{
|
||||
if (Sidebar.SelectedChannel is null)
|
||||
return;
|
||||
|
||||
var message = new MessageModel(
|
||||
Guid.NewGuid().ToString("N"),
|
||||
_currentUser,
|
||||
DateTimeOffset.Now,
|
||||
text);
|
||||
|
||||
Sidebar.SelectedChannel.AddMessage(message);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<ServerModel> SeedServers()
|
||||
{
|
||||
var alex = new UserModel("user-2", "Alex");
|
||||
var sam = new UserModel("user-3", "Sam");
|
||||
|
||||
var general = new ChannelModel(
|
||||
"channel-1",
|
||||
"general",
|
||||
new ObservableCollection<MessageModel>
|
||||
{
|
||||
new("message-1", alex, DateTimeOffset.Now.AddMinutes(-30), "This is a message."),
|
||||
new("message-2", sam, DateTimeOffset.Now.AddMinutes(-25), "Another message for the channel."),
|
||||
new("message-3", alex, DateTimeOffset.Now.AddMinutes(-10), "We should test the new layout."),
|
||||
});
|
||||
|
||||
var random = new ChannelModel(
|
||||
"channel-2",
|
||||
"random",
|
||||
new ObservableCollection<MessageModel>
|
||||
{
|
||||
new("message-4", sam, DateTimeOffset.Now.AddMinutes(-5), "Random chat keeps the vibe light."),
|
||||
});
|
||||
|
||||
var music = new ChannelModel(
|
||||
"channel-3",
|
||||
"music",
|
||||
new ObservableCollection<MessageModel>());
|
||||
|
||||
var server = new ServerModel(
|
||||
"server-1",
|
||||
"Server",
|
||||
new ObservableCollection<ChannelModel> { general, random });
|
||||
|
||||
var anotherServer = new ServerModel(
|
||||
"server-2",
|
||||
"Another Server",
|
||||
new ObservableCollection<ChannelModel>() { general, music});
|
||||
|
||||
return new[] { server, anotherServer };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public sealed class MessageComposerViewModel : ViewModelBase
|
||||
{
|
||||
private string _draft = string.Empty;
|
||||
|
||||
public MessageComposerViewModel()
|
||||
{
|
||||
var canSend = this.WhenAnyValue(x => x.Draft, draft => !string.IsNullOrWhiteSpace(draft));
|
||||
SendCommand = ReactiveCommand.Create(Send, canSend);
|
||||
}
|
||||
|
||||
public string Draft
|
||||
{
|
||||
get => _draft;
|
||||
set => this.RaiseAndSetIfChanged(ref _draft, value);
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> SendCommand { get; }
|
||||
|
||||
public event Action<string>? SendRequested;
|
||||
|
||||
private void Send()
|
||||
{
|
||||
var text = Draft.Trim();
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
|
||||
Draft = string.Empty;
|
||||
SendRequested?.Invoke(text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Decho.Models;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public sealed class MessageViewModel : ViewModelBase
|
||||
{
|
||||
public MessageViewModel(MessageModel model)
|
||||
{
|
||||
Model = model;
|
||||
}
|
||||
|
||||
public MessageModel Model { get; }
|
||||
|
||||
public string AuthorName => Model.Author.DisplayName;
|
||||
|
||||
public string Content => Model.Content;
|
||||
|
||||
public string TimeText => Model.SentAt.ToLocalTime().ToString("h:mm tt");
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
using Decho.Models;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public sealed class ServerViewModel : ViewModelBase
|
||||
{
|
||||
private bool _isExpanded = true;
|
||||
private ChannelViewModel? _selectedChannel;
|
||||
|
||||
public ServerViewModel(ServerModel model)
|
||||
{
|
||||
Model = model;
|
||||
Channels = new ObservableCollection<ChannelViewModel>(
|
||||
model.Channels.Select(channel => new ChannelViewModel(channel)));
|
||||
}
|
||||
|
||||
public ServerModel Model { get; }
|
||||
|
||||
public string Name => Model.Name;
|
||||
|
||||
public ObservableCollection<ChannelViewModel> Channels { get; }
|
||||
|
||||
public ChannelViewModel? SelectedChannel
|
||||
{
|
||||
get => _selectedChannel;
|
||||
set => this.RaiseAndSetIfChanged(ref _selectedChannel, value);
|
||||
}
|
||||
|
||||
public bool IsExpanded
|
||||
{
|
||||
get => _isExpanded;
|
||||
set => this.RaiseAndSetIfChanged(ref _isExpanded, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
using Decho.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public sealed class SidebarViewModel : ViewModelBase
|
||||
{
|
||||
private ChannelViewModel? _selectedChannel;
|
||||
|
||||
public SidebarViewModel(IEnumerable<ServerModel> servers)
|
||||
{
|
||||
Servers = new ObservableCollection<ServerViewModel>(
|
||||
servers.Select(server => new ServerViewModel(server)));
|
||||
SelectedChannel = Servers.FirstOrDefault()?.Channels.FirstOrDefault();
|
||||
|
||||
foreach (var server in Servers)
|
||||
{
|
||||
server.WhenAnyValue(s => s.SelectedChannel)
|
||||
.Where(channel => channel is not null)
|
||||
.Subscribe(new Action<ChannelViewModel?>(channel => SelectedChannel = channel!));
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<ServerViewModel> Servers { get; }
|
||||
|
||||
public ChannelViewModel? SelectedChannel
|
||||
{
|
||||
get => _selectedChannel;
|
||||
set
|
||||
{
|
||||
if (ReferenceEquals(_selectedChannel, value))
|
||||
return;
|
||||
|
||||
this.RaiseAndSetIfChanged(ref _selectedChannel, value);
|
||||
|
||||
if (value is null)
|
||||
return;
|
||||
|
||||
foreach (var server in Servers)
|
||||
{
|
||||
if (server.Channels.Contains(value))
|
||||
{
|
||||
if (!ReferenceEquals(server.SelectedChannel, value))
|
||||
server.SelectedChannel = value;
|
||||
}
|
||||
else if (server.SelectedChannel is not null)
|
||||
{
|
||||
server.SelectedChannel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Decho.ViewModels;
|
||||
|
||||
public abstract class ViewModelBase : ReactiveObject
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user