翼度科技»论坛 编程开发 .net 查看内容

一个跨平台的`ChatGPT`悬浮窗工具

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24
一个跨平台的ChatGPT悬浮窗工具

使用avalonia实现的ChatGPT的工具,设计成悬浮窗,并且支持插件。
如何实现悬浮窗?

在使用avalonia实现悬浮窗也是非常的简单的。
实现我们需要将窗体设置成无边框
在Window根节点添加一下属性,想要在Linux下生效请务必添加SystemDecorations属性
  1. ExtendClientAreaToDecorationsHint="True"
  2. ExtendClientAreaChromeHints="NoChrome"
  3. ExtendClientAreaTitleBarHeightHint="-1"
  4. SystemDecorations="None"
复制代码
这样我们的窗口就设置成了无边框。
然后我们还需要将窗体的大小固定,
  1. Height="50"
  2. MaxHeight="50"
  3. Width="{Binding Width}"
  4. MaxWidth="{Binding Width}"
复制代码
高度固定,宽度绑定到ViewModel的Width属性中,默认270,
接下来给出所有代码,
  1. <Window xmlns="https://github.com/avaloniaui"
  2.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  3.         xmlns:vm="using:Gotrays.Suspension.Client.ViewModels"
  4.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6.         xmlns:valueConverter="clr-namespace:Gotrays.Suspension.Client.ValueConverter"
  7.         xmlns:md="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia"
  8.         xmlns:avedit="https://github.com/avaloniaui/avaloniaedit"
  9.         xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"
  10.         mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
  11.         x:
  12.         x:DataType="vm:MainWindowViewModel"
  13.         ExtendClientAreaToDecorationsHint="True"
  14.         ExtendClientAreaChromeHints="NoChrome"
  15.         ExtendClientAreaTitleBarHeightHint="-1"
  16.         SystemDecorations="None"
  17.         WindowStartupLocation="CenterScreen"
  18.         Height="50"
  19.         MaxHeight="50"
  20.         Width="{Binding Width}"
  21.         MaxWidth="{Binding Width}"
  22.         Icon="/Assets/ai.png"
  23.         Title="Gotrays.Suspension.Client">
  24.     <Window.Resources>
  25.         <valueConverter:ImageConverter x:Key="ImageConverter" />
  26.         <valueConverter:ChatToStyleConverter x:Key="ChatToStyleConverter" />
  27.     </Window.Resources>
  28.     <Design.DataContext>
  29.         <vm:MainWindowViewModel />
  30.     </Design.DataContext>
  31.     <Window.Styles>
  32.         
  33.         
  34.     </Window.Styles>
  35.     <Border Name="MainBorder" CornerRadius="1000" Background="Black" Margin="0,0,0,0" Padding="0,0,0,0"
  36.             HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" Height="50">
  37.         <Grid>
  38.             
  39.             <Image Source="../Assets/ai.png" Name="Logo" HorizontalAlignment="Left" VerticalAlignment="Center"
  40.                    Width="46"
  41.                    Tapped="Logo_OnTapped"
  42.                    RenderOptions.BitmapInterpolationMode="HighQuality"
  43.                    PointerPressed="OnLogoClick"
  44.                    PointerEntered="Logo_OnPointerEntered"
  45.                    PointerExited="Logo_OnPointerExited"
  46.                    Height="46" Margin="0,0,0,0" />
  47.             
  48.             <Popup Name="ModulePopup" IsOpen="False" PlacementTarget="{Binding ElementName=MainBorder}"
  49.                    PlacementMode="Top">
  50.                 <StackPanel Margin="5">
  51.                     <Border Background="#1F1F1F" BorderBrush="Black" BorderThickness="1" CornerRadius="12"
  52.                             MaxHeight="400" Width="120">
  53.                         <ScrollViewer Name="ModuleScrollViewer" VerticalScrollBarVisibility="Auto">
  54.                             <ItemsControl CornerRadius="12" ItemsSource="{Binding Modules}" Margin="2">
  55.                                 <ItemsControl.ItemTemplate>
  56.                                     <DataTemplate>
  57.                                         <Border Margin="5"
  58.                                                 Background="{Binding Color}"
  59.                                                 PointerExited="OnSelectStackPointerExited"
  60.                                                 PointerEntered="OnSelectStackPointerEntered"
  61.                                                 PointerPressed="OnSelectStackPointerPressed"
  62.                                                 Tag="{Binding GetThis}"
  63.                                                 CornerRadius="8">
  64.                                             
  65.                                             <StackPanel Orientation="Horizontal">
  66.                                                 <Image
  67.                                                     RenderOptions.BitmapInterpolationMode="HighQuality"
  68.                                                     Source="{Binding Icon, Converter={StaticResource ImageConverter}}"
  69.                                                     HorizontalAlignment="Left"
  70.                                                     Width="20"
  71.                                                     Height="20" />
  72.                                                 <TextBlock TextWrapping="Wrap" Width="60" Text="{Binding Title}"
  73.                                                            Margin="5" Foreground="White" />
  74.                                             </StackPanel>
  75.                                         </Border>
  76.                                     </DataTemplate>
  77.                                 </ItemsControl.ItemTemplate>
  78.                             </ItemsControl>
  79.                         </ScrollViewer>
  80.                     </Border>
  81.                 </StackPanel>
  82.             </Popup>
  83.             
  84.             <Border PointerPressed="SearchBorder_OnPointerPressed"
  85.                     PointerEntered="searchBorder_PointerEnter"
  86.                     PointerExited="OnPointerExited"
  87.                     Name="searchBorder"
  88.                     CornerRadius="1000" Background="#000000" BorderBrush="#FFFFFF"
  89.                     BorderThickness="1" Margin="50,0,0,0" Padding="0,0,0,0" HorizontalAlignment="Left"
  90.                     VerticalAlignment="Center" Width="46" Height="46" Cursor="Hand">
  91.                 <Image Source="../Assets/search.png"
  92.                        RenderOptions.BitmapInterpolationMode="HighQuality"
  93.                        HorizontalAlignment="Center" VerticalAlignment="Center"
  94.                        Width="20" Height="20" Margin="0,0,0,0" />
  95.             </Border>
  96.             
  97.             <TextBox FontSize="20" Name="SearchText" Margin="50,0,0,0" IsVisible="False" Width="0" Height="40"
  98.                      HorizontalAlignment="Left" VerticalAlignment="Center">
  99.                 <TextBox.Styles>
  100.                     
  101.                     </Styles>
  102.                 </TextBox.Styles>
  103.                 <TextBox.Transitions>
  104.                     <Transitions>
  105.                         <DoubleTransition Property="Width" Duration="0:0:0.1" />
  106.                     </Transitions>
  107.                 </TextBox.Transitions>
  108.             </TextBox>
  109.             
  110.             <Popup x:Name="MessagePopup"
  111.                    IsOpen="False"
  112.                    PlacementTarget="{Binding ElementName=MainBorder}"
  113.                    PlacementMode="Bottom">
  114.                 <StackPanel
  115.                     PointerEntered="MessagePopup_OnPointerEntered"
  116.                     PointerExited="MessagePopup_OnPointerExited" Margin="5">
  117.                     <Border Name="MessageBorder"
  118.                             Background="#1F1F1F"
  119.                             BorderBrush="Black"
  120.                             BorderThickness="1"
  121.                             CornerRadius="12"
  122.                             MaxHeight="300">
  123.                         <ScrollViewer Name="ScrollViewer" VerticalScrollBarVisibility="Auto">
  124.                             <ItemsControl ItemsSource="{Binding Messages}" CornerRadius="12" Margin="2">
  125.                                 <ItemsControl.ItemTemplate>
  126.                                     <DataTemplate>
  127.                                         <StackPanel Margin="5">
  128.                                             <StackPanel.Resources>
  129.                                                 <valueConverter:ChatToBackgroundConverter
  130.                                                     x:Key="ChatToBackgroundConverter" />
  131.                                             </StackPanel.Resources>
  132.                                             <Border
  133.                                                 Background="{Binding Chat, Converter={StaticResource ChatToBackgroundConverter}}"
  134.                                                 CornerRadius="5">
  135.                                                 <md:MarkdownScrollViewer
  136.                                                     VerticalAlignment="Stretch"
  137.                                                     MarkdownStyleName="Standard"
  138.                                                     SaveScrollValueWhenContentUpdated="True"
  139.                                                     Markdown="{Binding Message}">
  140.                                                     <md:MarkdownScrollViewer.Styles>
  141.                                                         
  142.                                                         
  143.                                                         
  144.                                                         
  145.                                                     </md:MarkdownScrollViewer.Styles>
  146.                                                 </md:MarkdownScrollViewer>
  147.                                             </Border>
  148.                                         </StackPanel>
  149.                                     </DataTemplate>
  150.                                 </ItemsControl.ItemTemplate>
  151.                             </ItemsControl>
  152.                         </ScrollViewer>
  153.                     </Border>
  154.                 </StackPanel>
  155.             </Popup>
  156.         </Grid>
  157.         <Border.Transitions>
  158.             <Transitions>
  159.                 <DoubleTransition Property="Width" Duration="0:0:0.2" />
  160.             </Transitions>
  161.         </Border.Transitions>
  162.     </Border>
  163. </Window>
复制代码
只需要设置无边框并且固定大小。悬浮窗的效果就达到了。
我们看看执行效果
<img alt="image-20230702133719931" loading="lazy">

就这样简单的悬浮窗写好了,我们使用一下悬浮窗的搜索功能
<img alt="image-20230702133757221" loading="lazy">

这个就是简单的使用效果,对比其他的工具,这个悬浮窗更简洁,并且跨平台和开源。
<img alt="image-20230702133839454" loading="lazy">

目前的项目结构。
plugin下面的项目是默认的插件,用于搜索系统文件(未完善)
Gotrays.Suspension.Client则是实际的客户端。
Gotrays.Suspension.PlugIn则是插件定义的接口规范。
Gotrays.Update则是检查更新程序,用于更新主程序。
实现插件

plug-in

插件模块,用于扩展功能。
插件开发

1. 创建插件项目

在解决方案中创建一个类库项目,项目名称以Gotrays.Suspension.PlugIn.开头,例如Gotrays.Suspension.PlugIn.Test。
然后在项目中依赖Gotrays.Suspension.PlugIn类库。
2. 创建插件类

在项目中创建一个类,继承Gotrays.Suspension.PlugIn.PlugInBase类,例如:
  1. using Gotrays.Suspension.PlugIn;
  2. public class SystemTools : PlugInBase
  3. {
  4.     public SystemTools()
  5.     {
  6.         Name = "系统搜索";
  7. ​        // 获取system.png嵌入资源的Stream
  8. ​        var stream = GetType().Assembly.GetManifestResourceStream("SystemTools.system.png");
  9. ​        if (stream == null) return;
  10. ​        // 读取Stream到byte数组
  11. ​        var bytes = new byte[stream.Length];
  12. ​        var read = stream.Read(bytes, 0, bytes.Length);
  13. ​        Icon = bytes;
  14. ​    }
  15. ​    // 搜索触发
  16. ​    public override async Task SearchAsync(string value)
  17. ​    {
  18. ​        // 打开系统搜索
  19. ​        Process.Start("explorer.exe", "search://" + value);
  20. ​        await Task.CompletedTask;
  21. ​    }
  22. ​   
  23. ​    protected override async Task InitAsync(IServiceCollection services){
  24. ​        // 插件首次加载时执行
  25. ​    }
  26. ​    public override async Task BuilderServiceAsync(IServiceProvider provider)
  27. ​    {
  28. ​        // 这里可以得到服务提供者,可以通过服务提供者获取其他服务
  29. ​    }
  30. ​    protected override void Selection()
  31. ​    {
  32. ​        //  当插件被选中时执行
  33. ​    }
  34. ​   
  35. ​    protected override void UnSelection()
  36. ​    {
  37. ​        // 当插件被取消选中时执行
  38. ​    }
  39. ​   
  40. ​    protected override async Task UnloadAsync()
  41. ​    {
  42. ​        // 当插件被卸载插件发生
  43. ​    }
  44. ​   
  45. }
复制代码
工具服务会进行自动发现,无需手动注册。
只需要将程序集放置在./plug-in目录下即可。
服务会在一个程序集中发现所有的插件类,并且进行注册。
按照上面的方式非常的简单就集成了插件。
开源地址

Gitee:https://gitee.com/gotrays/gotrays-suspension
Github:https://github.com/239573049/Suspension
技术交流群:737776595

来源:https://www.cnblogs.com/hejiale010426/archive/2023/07/02/17520719.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具