mirror of
https://github.com/Stone-Red-Code/Decho.git
synced 2026-09-04 00:46:11 +02:00
Patch for EchoHub v0.2.17
This commit is contained in:
@@ -2,7 +2,7 @@ using System.Collections.ObjectModel;
|
|||||||
|
|
||||||
namespace Decho.Models;
|
namespace Decho.Models;
|
||||||
|
|
||||||
public sealed class ChannelModel(string id, string name, ObservableCollection<MessageModel> messages, string? topic = null, bool isPublic = true, bool isProtected = false)
|
public sealed class ChannelModel(string id, string name, ObservableCollection<MessageModel> messages, string? topic = null, bool isPublic = true, bool isProtected = false, bool isEncrypted = false, bool isSystem = false)
|
||||||
{
|
{
|
||||||
public string Id { get; } = id;
|
public string Id { get; } = id;
|
||||||
|
|
||||||
@@ -14,5 +14,9 @@ public sealed class ChannelModel(string id, string name, ObservableCollection<Me
|
|||||||
|
|
||||||
public bool IsProtected { get; } = isProtected;
|
public bool IsProtected { get; } = isProtected;
|
||||||
|
|
||||||
|
public bool IsEncrypted { get; } = isEncrypted;
|
||||||
|
|
||||||
|
public bool IsSystem { get; } = isSystem;
|
||||||
|
|
||||||
public ObservableCollection<MessageModel> Messages { get; } = messages;
|
public ObservableCollection<MessageModel> Messages { get; } = messages;
|
||||||
}
|
}
|
||||||
@@ -205,7 +205,9 @@ internal sealed class ChannelService : IChannelService
|
|||||||
[],
|
[],
|
||||||
channelDto.Topic,
|
channelDto.Topic,
|
||||||
channelDto.IsPublic,
|
channelDto.IsPublic,
|
||||||
channelDto.IsProtected);
|
channelDto.IsProtected,
|
||||||
|
channelDto.IsEncrypted,
|
||||||
|
channelDto.IsSystem);
|
||||||
entry.Server.Channels.Add(channel);
|
entry.Server.Channels.Add(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
|
||||||
using Decho.Models;
|
using Decho.Models;
|
||||||
|
|
||||||
using EchoHub.Client.Config;
|
using EchoHub.Client.Config;
|
||||||
@@ -5,8 +8,10 @@ using EchoHub.Client.Services;
|
|||||||
using EchoHub.Client.UI.Dialogs;
|
using EchoHub.Client.UI.Dialogs;
|
||||||
using EchoHub.Core.Constants;
|
using EchoHub.Core.Constants;
|
||||||
using EchoHub.Core.DTOs;
|
using EchoHub.Core.DTOs;
|
||||||
using EchoHub.Core.Models;
|
|
||||||
using EchoHub.Core.Services;
|
using MsBox.Avalonia;
|
||||||
|
using MsBox.Avalonia.Base;
|
||||||
|
using MsBox.Avalonia.Enums;
|
||||||
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -140,7 +145,9 @@ public sealed class ConnectionService : IConnectionService
|
|||||||
[],
|
[],
|
||||||
dto.Topic,
|
dto.Topic,
|
||||||
dto.IsPublic,
|
dto.IsPublic,
|
||||||
dto.IsProtected);
|
dto.IsProtected,
|
||||||
|
dto.IsEncrypted,
|
||||||
|
dto.IsSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static MessageModel MessageModelFromDto(MessageDto dto, ServerConnection entry)
|
internal static MessageModel MessageModelFromDto(MessageDto dto, ServerConnection entry)
|
||||||
@@ -219,11 +226,37 @@ public sealed class ConnectionService : IConnectionService
|
|||||||
SaveRefreshToken(dialogResult.ServerUrl, dialogResult.RememberMe);
|
SaveRefreshToken(dialogResult.ServerUrl, dialogResult.RememberMe);
|
||||||
ServerAdded?.Invoke(serverModel);
|
ServerAdded?.Invoke(serverModel);
|
||||||
|
|
||||||
|
// Check for version mismatch
|
||||||
|
//if (result.ServerInfo is not null && !string.IsNullOrEmpty(result.ServerInfo.Version)
|
||||||
|
// && result.ServerInfo.Version != App.AppVersion)
|
||||||
|
//{
|
||||||
|
// await ShowVersionMismatchDialogAsync(dialogResult.ServerUrl, result.ServerInfo.Version);
|
||||||
|
//}
|
||||||
|
|
||||||
AutoJoinRemainingChannels(dialogResult.ServerUrl, result.Channels);
|
AutoJoinRemainingChannels(dialogResult.ServerUrl, result.Channels);
|
||||||
|
|
||||||
return serverModel;
|
return serverModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//private async Task ShowVersionMismatchDialogAsync(string serverUrl, string serverVersion)
|
||||||
|
//{
|
||||||
|
// await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
|
// {
|
||||||
|
// IMsBox<ButtonResult> box = MessageBoxManager.GetMessageBoxStandard(
|
||||||
|
// "Version Mismatch",
|
||||||
|
// $"Server version {serverVersion} does not match client version {App.AppVersion}.\n\nSome features may not work correctly. Consider updating both to the same version.",
|
||||||
|
// ButtonEnum.YesNo);
|
||||||
|
//
|
||||||
|
// ButtonResult result = await box.ShowWindowDialogAsync(
|
||||||
|
// (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow);
|
||||||
|
//
|
||||||
|
// if (result == ButtonResult.No)
|
||||||
|
// {
|
||||||
|
// _ = DisconnectAsync(serverUrl);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
|
||||||
private async void AutoJoinRemainingChannels(string serverUrl, List<ChannelDto> channels)
|
private async void AutoJoinRemainingChannels(string serverUrl, List<ChannelDto> channels)
|
||||||
{
|
{
|
||||||
ClientConfig config = ConfigManager.Load();
|
ClientConfig config = ConfigManager.Load();
|
||||||
@@ -342,7 +375,9 @@ public sealed class ConnectionService : IConnectionService
|
|||||||
[],
|
[],
|
||||||
channel.Topic,
|
channel.Topic,
|
||||||
channel.IsPublic,
|
channel.IsPublic,
|
||||||
channel.IsProtected);
|
channel.IsProtected,
|
||||||
|
channel.IsEncrypted,
|
||||||
|
channel.IsSystem);
|
||||||
entry.Server.Channels.Add(model);
|
entry.Server.Channels.Add(model);
|
||||||
ChannelAdded?.Invoke(entry.Server.ServerUrl, model);
|
ChannelAdded?.Invoke(entry.Server.ServerUrl, model);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,18 @@ public sealed class ChannelViewModel(ChannelModel model) : ViewModelBase
|
|||||||
|
|
||||||
public bool IsNotProtected => !Model.IsProtected;
|
public bool IsNotProtected => !Model.IsProtected;
|
||||||
|
|
||||||
|
public bool IsSystem => Model.IsSystem;
|
||||||
|
|
||||||
|
public bool IsNotSystem => !Model.IsSystem;
|
||||||
|
|
||||||
|
public bool ShowLockIcon => Model.IsProtected && IsLocked;
|
||||||
|
|
||||||
|
public bool ShowUnlockIcon => Model.IsProtected && !IsLocked;
|
||||||
|
|
||||||
|
public bool ShowServerIcon => Model.IsSystem && !Model.IsProtected;
|
||||||
|
|
||||||
|
public bool ShowHashtagIcon => !Model.IsProtected && !Model.IsSystem;
|
||||||
|
|
||||||
public bool IsLocked
|
public bool IsLocked
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
|
|||||||
@@ -892,7 +892,7 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
ChannelJoinResult joinResult = await ChannelService.JoinChannelAsync(server.ServerUrl, channel.Name);
|
ChannelJoinResult joinResult = await ChannelService.JoinChannelAsync(server.ServerUrl, channel.Name);
|
||||||
|
|
||||||
ChannelModel channelModel = new ChannelModel(
|
ChannelModel channelModel = new ChannelModel(
|
||||||
channel.Id.ToString(), channel.Name, [], channel.Topic, channel.IsPublic, channel.IsProtected);
|
channel.Id.ToString(), channel.Name, [], channel.Topic, channel.IsPublic, channel.IsProtected, channel.IsEncrypted, channel.IsSystem);
|
||||||
|
|
||||||
ServerViewModel? serverVm = Sidebar.GetServer(server.ServerUrl);
|
ServerViewModel? serverVm = Sidebar.GetServer(server.ServerUrl);
|
||||||
if (serverVm is not null)
|
if (serverVm is not null)
|
||||||
@@ -1040,10 +1040,18 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
Chat.Composer.SetCommandHandler(new CommandHandler());
|
Chat.Composer.SetCommandHandler(new CommandHandler());
|
||||||
|
|
||||||
if (channel.IsProtected && channel.Messages.Count == 0)
|
if (channel.IsSystem)
|
||||||
|
{
|
||||||
|
Chat.Composer.IsReadOnly = true;
|
||||||
|
}
|
||||||
|
else if (channel.IsProtected && channel.Messages.Count == 0)
|
||||||
{
|
{
|
||||||
channel.IsLocked = true;
|
channel.IsLocked = true;
|
||||||
Chat.Composer.IsConnected = false;
|
Chat.Composer.IsReadOnly = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Chat.Composer.IsReadOnly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
@@ -1064,7 +1072,7 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
Avalonia.Threading.Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
channel.IsLocked = true;
|
channel.IsLocked = true;
|
||||||
Chat.Composer.IsConnected = false;
|
Chat.Composer.IsReadOnly = true;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1078,6 +1086,11 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
channel.IsLocked = false;
|
channel.IsLocked = false;
|
||||||
Chat.Composer.IsConnected = isServerConnected;
|
Chat.Composer.IsConnected = isServerConnected;
|
||||||
|
|
||||||
|
if (channel.IsProtected)
|
||||||
|
{
|
||||||
|
Chat.Composer.IsReadOnly = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!channel.Messages.Any(m => m.AuthorName != "System"))
|
if (!channel.Messages.Any(m => m.AuthorName != "System"))
|
||||||
{
|
{
|
||||||
foreach (MessageModel msg in joinResult.History)
|
foreach (MessageModel msg in joinResult.History)
|
||||||
@@ -1090,7 +1103,7 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
_ = RefreshOnlineUsersAsync(serverUrl, channel.Name);
|
_ = RefreshOnlineUsersAsync(serverUrl, channel.Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (EchoHub.Client.Services.ChannelPasswordRequiredException)
|
catch (ChannelPasswordRequiredException)
|
||||||
{
|
{
|
||||||
string? pwd = await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
|
string? pwd = await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
@@ -1242,7 +1255,11 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
ChannelModel channelModel = new ChannelModel(
|
ChannelModel channelModel = new ChannelModel(
|
||||||
Guid.NewGuid().ToString("N"),
|
Guid.NewGuid().ToString("N"),
|
||||||
channelName,
|
channelName,
|
||||||
[]);
|
[],
|
||||||
|
isPublic: true,
|
||||||
|
isProtected: false,
|
||||||
|
isEncrypted: false,
|
||||||
|
isSystem: false);
|
||||||
ChannelViewModel channelVm = new ChannelViewModel(channelModel);
|
ChannelViewModel channelVm = new ChannelViewModel(channelModel);
|
||||||
serverVm.Channels.Add(channelVm);
|
serverVm.Channels.Add(channelVm);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,25 @@ public sealed class MessageComposerViewModel : ViewModelBase
|
|||||||
public bool IsConnected
|
public bool IsConnected
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set => this.RaiseAndSetIfChanged(ref field, value);
|
set
|
||||||
|
{
|
||||||
|
this.RaiseAndSetIfChanged(ref field, value);
|
||||||
|
this.RaisePropertyChanged(nameof(IsEditable));
|
||||||
|
}
|
||||||
} = true;
|
} = true;
|
||||||
|
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.RaiseAndSetIfChanged(ref field, value);
|
||||||
|
this.RaisePropertyChanged(nameof(IsEditable));
|
||||||
|
}
|
||||||
|
} = false;
|
||||||
|
|
||||||
|
public bool IsEditable => !IsReadOnly && IsConnected;
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> SendCommand { get; }
|
public ReactiveCommand<Unit, Unit> SendCommand { get; }
|
||||||
|
|
||||||
public bool HasCommandHandler => _commandHandler is not null;
|
public bool HasCommandHandler => _commandHandler is not null;
|
||||||
@@ -84,10 +100,11 @@ public sealed class MessageComposerViewModel : ViewModelBase
|
|||||||
Autocomplete = new AutocompleteController([mentionProvider, channelProvider]);
|
Autocomplete = new AutocompleteController([mentionProvider, channelProvider]);
|
||||||
|
|
||||||
IObservable<bool> canSend = this.WhenAnyValue(
|
IObservable<bool> canSend = this.WhenAnyValue(
|
||||||
x => x.Draft,
|
x => x.Draft,
|
||||||
x => x.HasStagedFiles,
|
x => x.HasStagedFiles,
|
||||||
(draft, hasFiles) =>
|
x => x.IsReadOnly,
|
||||||
!string.IsNullOrWhiteSpace(draft) || hasFiles);
|
(draft, hasFiles, isReadOnly) =>
|
||||||
|
(!string.IsNullOrWhiteSpace(draft) || hasFiles) && !isReadOnly);
|
||||||
SendCommand = ReactiveCommand.Create(Send, canSend);
|
SendCommand = ReactiveCommand.Create(Send, canSend);
|
||||||
|
|
||||||
_ = this.WhenAnyValue(x => x.Draft).Subscribe(OnDraftChanged);
|
_ = this.WhenAnyValue(x => x.Draft).Subscribe(OnDraftChanged);
|
||||||
|
|||||||
@@ -14,8 +14,10 @@
|
|||||||
<DataTemplate x:DataType="vm:ChannelViewModel">
|
<DataTemplate x:DataType="vm:ChannelViewModel">
|
||||||
<Grid ColumnDefinitions="Auto, *, Auto" Margin="2 0">
|
<Grid ColumnDefinitions="Auto, *, Auto" Margin="2 0">
|
||||||
<Grid Grid.Column="0" Margin="0 0 4 0">
|
<Grid Grid.Column="0" Margin="0 0 4 0">
|
||||||
<i:Icon Value="fa-hashtag" FontWeight="Bold" VerticalAlignment="Center" IsVisible="{Binding IsNotProtected}" />
|
<i:Icon Value="fa-lock" FontWeight="Bold" VerticalAlignment="Center" IsVisible="{Binding ShowLockIcon}" />
|
||||||
<i:Icon Value="fa-lock" FontWeight="Bold" VerticalAlignment="Center" IsVisible="{Binding IsProtected}" />
|
<i:Icon Value="fa-lock-open" FontWeight="Bold" VerticalAlignment="Center" IsVisible="{Binding ShowUnlockIcon}" />
|
||||||
|
<i:Icon Value="fa-server" FontWeight="Bold" VerticalAlignment="Center" IsVisible="{Binding ShowServerIcon}" />
|
||||||
|
<i:Icon Value="fa-hashtag" FontWeight="Bold" VerticalAlignment="Center" IsVisible="{Binding ShowHashtagIcon}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Name}" TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
|
<TextBlock Grid.Column="1" Text="{Binding Name}" TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
|
||||||
<Border Grid.Column="2"
|
<Border Grid.Column="2"
|
||||||
|
|||||||
@@ -25,6 +25,12 @@
|
|||||||
|
|
||||||
<CheckBox x:Name="RememberCheck" Content="Remember me" IsChecked="True" />
|
<CheckBox x:Name="RememberCheck" Content="Remember me" IsChecked="True" />
|
||||||
|
|
||||||
|
<TextBlock Text="Display Name (optional):" FontWeight="SemiBold" />
|
||||||
|
<TextBox x:Name="DisplayNameBox" Watermark="Display name" />
|
||||||
|
|
||||||
|
<TextBlock Text="Invite Code (optional):" FontWeight="SemiBold" />
|
||||||
|
<TextBox x:Name="InviteCodeBox" Watermark="Invite code" />
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal"
|
<StackPanel Orientation="Horizontal"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Spacing="10"
|
Spacing="10"
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ public sealed partial class ConnectDialogWindow : Window
|
|||||||
string url = UrlBox.Text?.Trim() ?? "";
|
string url = UrlBox.Text?.Trim() ?? "";
|
||||||
string user = UserBox.Text?.Trim() ?? "";
|
string user = UserBox.Text?.Trim() ?? "";
|
||||||
string pass = PassBox.Text ?? "";
|
string pass = PassBox.Text ?? "";
|
||||||
|
string displayName = DisplayNameBox.Text?.Trim() ?? "";
|
||||||
|
string inviteCode = InviteCodeBox.Text?.Trim() ?? "";
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
|
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
|
||||||
{
|
{
|
||||||
@@ -108,7 +110,9 @@ public sealed partial class ConnectDialogWindow : Window
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Close(new ConnectDialogResult(url, user, pass, true, RememberCheck.IsChecked ?? false, null));
|
Close(new ConnectDialogResult(url, user, pass, true, RememberCheck.IsChecked ?? false, null,
|
||||||
|
string.IsNullOrEmpty(displayName) ? null : displayName,
|
||||||
|
string.IsNullOrEmpty(inviteCode) ? null : inviteCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCancelClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
private void OnCancelClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
xmlns:vm="using:Decho.ViewModels"
|
xmlns:vm="using:Decho.ViewModels"
|
||||||
xmlns:models="using:Decho.Models"
|
xmlns:models="using:Decho.Models"
|
||||||
xmlns:i="https://github.com/projektanker/icons.avalonia"
|
xmlns:i="https://github.com/projektanker/icons.avalonia"
|
||||||
|
xmlns:converters="using:Avalonia.Data.Converters"
|
||||||
x:Class="Decho.Views.MessageComposerView"
|
x:Class="Decho.Views.MessageComposerView"
|
||||||
x:DataType="vm:MessageComposerViewModel">
|
x:DataType="vm:MessageComposerViewModel">
|
||||||
<Grid RowDefinitions="Auto,Auto,*">
|
<Grid RowDefinitions="Auto,Auto,*">
|
||||||
@@ -78,7 +79,7 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Margin="0 0 5 0"
|
Margin="0 0 5 0"
|
||||||
Text="{Binding Draft, Mode=TwoWay}"
|
Text="{Binding Draft, Mode=TwoWay}"
|
||||||
IsEnabled="{Binding IsConnected}"
|
IsEnabled="{Binding IsEditable}"
|
||||||
AcceptsReturn="False"
|
AcceptsReturn="False"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
KeyDown="OnTextBoxKeyDown" />
|
KeyDown="OnTextBoxKeyDown" />
|
||||||
@@ -119,7 +120,7 @@
|
|||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
i:Attached.Icon="fa-paper-plane"
|
i:Attached.Icon="fa-paper-plane"
|
||||||
Command="{Binding SendCommand}"
|
Command="{Binding SendCommand}"
|
||||||
IsEnabled="{Binding IsConnected}" />
|
IsEnabled="{Binding IsEditable}" />
|
||||||
<Button Grid.Column="2"
|
<Button Grid.Column="2"
|
||||||
Height="33"
|
Height="33"
|
||||||
Width="33"
|
Width="33"
|
||||||
@@ -127,7 +128,7 @@
|
|||||||
Click="OnFileUploadClicked"
|
Click="OnFileUploadClicked"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
i:Attached.Icon="fa-paperclip"
|
i:Attached.Icon="fa-paperclip"
|
||||||
IsEnabled="{Binding IsConnected}" />
|
IsEnabled="{Binding IsEditable}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
+1
-1
Submodule src/EchoHub updated: ef42c42736...e335790aab
Reference in New Issue
Block a user