소스 검색

remade text content parsing, now html images shows in post

Veloe 11 달 전
부모
커밋
01ac2b7324

+ 5 - 5
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Android/VeloeAvaloniaKemonoPartyApp.Android.csproj

@@ -6,11 +6,11 @@
     <Nullable>enable</Nullable>
     <ApplicationId>com.Veloe.AvaloniaKemonoParty</ApplicationId>
     <ApplicationVersion>1</ApplicationVersion>
-    <ApplicationDisplayVersion>1.0.0.149</ApplicationDisplayVersion>
+    <ApplicationDisplayVersion>1.0.0.160</ApplicationDisplayVersion>
     <AndroidPackageFormat>apk</AndroidPackageFormat>
     <AndroidEnableProfiledAot>False</AndroidEnableProfiledAot>
-    <AssemblyVersion>1.0.0.149</AssemblyVersion>
-    <FileVersion>1.0.0.149</FileVersion>
+    <AssemblyVersion>1.0.0.160</AssemblyVersion>
+    <FileVersion>1.0.0.160</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>
@@ -20,8 +20,8 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Avalonia.Android" Version="11.0.6" />
-    <PackageReference Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.5" />
+    <PackageReference Include="Avalonia.Android" Version="11.1.3" />
+    <PackageReference Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.12" />
     <PackageReference Include="Xamarin.Essentials" Version="1.8.1" />
   </ItemGroup>
 

+ 2 - 4
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Browser/Program.cs

@@ -1,5 +1,4 @@
 using Avalonia;
-using Avalonia.Browser;
 using Avalonia.ReactiveUI;
 using System.Runtime.Versioning;
 using System.Threading.Tasks;
@@ -9,10 +8,9 @@ using VeloeAvaloniaKemonoPartyApp;
 
 internal partial class Program
 {
-    private static async Task Main(string[] args) => await BuildAvaloniaApp()
+    private static async Task Main(string[] args) => BuildAvaloniaApp()
             .WithInterFont()
-            .UseReactiveUI()
-            .StartBrowserAppAsync("out");
+            .UseReactiveUI();
 
     public static AppBuilder BuildAvaloniaApp()
         => AppBuilder.Configure<App>();

+ 2 - 5
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Browser/VeloeAvaloniaKemonoPartyApp.Browser.csproj

@@ -4,17 +4,14 @@
     <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
     <WasmMainJSPath>AppBundle\main.js</WasmMainJSPath>
     <OutputType>Exe</OutputType>
-    <AssemblyVersion>1.0.0.9</AssemblyVersion>
-    <FileVersion>1.0.0.9</FileVersion>
+    <AssemblyVersion>1.0.0.14</AssemblyVersion>
+    <FileVersion>1.0.0.14</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>
     <WasmExtraFilesToDeploy Include="AppBundle\**" />
   </ItemGroup>
 
-  <ItemGroup>
-    <PackageReference Include="Avalonia.Browser" Version="11.0.6" />
-  </ItemGroup>
 
   <ItemGroup>
     <ProjectReference Include="..\VeloeAvaloniaKemonoPartyApp\VeloeAvaloniaKemonoPartyApp.csproj" />

+ 4 - 4
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Desktop/VeloeAvaloniaKemonoPartyApp.Desktop.csproj

@@ -10,14 +10,14 @@
 
   <PropertyGroup>
     <ApplicationManifest>app.manifest</ApplicationManifest>
-    <AssemblyVersion>1.0.0.107</AssemblyVersion>
-    <FileVersion>1.0.0.107</FileVersion>
+    <AssemblyVersion>1.0.0.135</AssemblyVersion>
+    <FileVersion>1.0.0.135</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Avalonia.Desktop" Version="11.0.6" />
+    <PackageReference Include="Avalonia.Desktop" Version="11.1.3" />
     <!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
-    <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.6" />
+    <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.3" />
   </ItemGroup>
 
   <ItemGroup>

+ 0 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/App.axaml

@@ -11,7 +11,6 @@
 
     <Application.Styles>
         <FluentTheme />
-		<StyleInclude Source="avares://Avalonia.Controls.TreeDataGrid/Themes/Fluent.axaml"/>
 		<StyleInclude Source="avares://Notification.Avalonia/Themes/Generic.xaml" />
     </Application.Styles>
 

+ 18 - 3
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Models/Post.cs

@@ -1,7 +1,9 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
+using System.Net.Mail;
 using System.Text.Json.Serialization;
 using System.Threading.Tasks;
 using VeloeAvaloniaKemonoPartyApp.Services;
@@ -73,7 +75,7 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
         [JsonPropertyName("path")]
         public string Path { get; set; }
 
-        public string Link => $"https://kemono.su/data{Path}";
+        public virtual string Link => $"https://kemono.su/data{Path}";
 
         public bool IsImage => Path.EndsWith(".jpg") || Path.EndsWith(".png") || Path.EndsWith(".jpeg");
 
@@ -81,7 +83,7 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
 
         private static StorageService s_storage = new();
 
-        private string FileName => Path.Split('/').Last();
+        protected virtual string FileName => Path.Split('/').Last();
 
         public async Task<Stream?> LoadCoverBitmapAsync()
         {
@@ -111,8 +113,9 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
 
                 return new MemoryStream(data);
             }
-            catch (Exception)
+            catch (Exception ex)
             {
+                Debug.WriteLine(ex);
                 return null;
             }
             
@@ -120,6 +123,18 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
 
     }
 
+    public class ExternalAttachment : Attachment
+    {
+        public string Url { get; set; }
+
+        public override string Link => Url;
+
+        protected override string FileName => System.IO.Path.HasExtension(Path) ?
+                    System.IO.Path.GetFileNameWithoutExtension(Path) :
+                    Extensions.CreateMD5(Path);
+
+    }
+
     public class Embed
     {
         [JsonPropertyName("description")]

+ 31 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Services/Extensions.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace VeloeAvaloniaKemonoPartyApp.Services
+{
+    internal static class Extensions
+    {
+        public static string CreateMD5(string input)
+        {
+            // Use input string to calculate MD5 hash
+            using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
+            {
+                byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
+                byte[] hashBytes = md5.ComputeHash(inputBytes);
+
+                return Convert.ToHexString(hashBytes); // .NET 5 +
+
+                // Convert the byte array to hexadecimal string prior to .NET 5
+                // StringBuilder sb = new System.Text.StringBuilder();
+                // for (int i = 0; i < hashBytes.Length; i++)
+                // {
+                //     sb.Append(hashBytes[i].ToString("X2"));
+                // }
+                // return sb.ToString();
+            }
+        }
+    }
+}

+ 11 - 11
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.csproj

@@ -4,8 +4,8 @@
     <Nullable>enable</Nullable>
     <LangVersion>latest</LangVersion>
     <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
-    <AssemblyVersion>1.0.0.313</AssemblyVersion>
-    <FileVersion>1.0.0.313</FileVersion>
+    <AssemblyVersion>1.0.0.350</AssemblyVersion>
+    <FileVersion>1.0.0.350</FileVersion>
   </PropertyGroup>
 
   
@@ -14,20 +14,20 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Avalonia" Version="11.0.6" />
-    <PackageReference Include="Avalonia.Browser" Version="11.0.6" />
-    <PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.0.0.2" />
-    <PackageReference Include="Avalonia.Controls.TreeDataGrid" Version="11.0.2" />
+    <PackageReference Include="AngleSharp" Version="1.1.2" />
+    <PackageReference Include="Avalonia" Version="11.1.3" />
+    <PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.1.0.1" />
     <PackageReference Include="Avalonia.HtmlRenderer" Version="11.0.0" />
-    <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.6" />
-    <PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.6" />
-    <PackageReference Include="Avalonia.ReactiveUI" Version="11.0.6" />
+    <PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.3" />
+    <PackageReference Include="Avalonia.Fonts.Inter" Version="11.1.3" />
+    <PackageReference Include="Avalonia.ReactiveUI" Version="11.1.3" />
     <!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
-    <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.6" />
+    <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.3" />
     <PackageReference Include="HanumanInstitute.MvvmDialogs.Avalonia" Version="2.1.0" />
     <PackageReference Include="HanumanInstitute.MvvmDialogs.Avalonia.MessageBox" Version="2.1.0" />
+    <PackageReference Include="HyperText.Avalonia" Version="2.0.0" />
     <PackageReference Include="Notification.Avalonia" Version="2.1.0" />
-    <PackageReference Include="Splat.DependencyInjection.SourceGenerator" Version="1.1.93">
+    <PackageReference Include="Splat.DependencyInjection.SourceGenerator" Version="1.2.3">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>

+ 0 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/AttachmentViewModel.cs

@@ -1,5 +1,4 @@
 using Avalonia.Interactivity;
-using Avalonia.Browser;
 using VeloeAvaloniaKemonoPartyApp.Models;
 using System.Diagnostics;
 using System.Runtime.InteropServices;

+ 11 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/CreatorPostsViewModel.cs

@@ -153,7 +153,7 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
 
         private async void LoadAvatars(CancellationToken cancellationToken,int startIndex = 0)
         {
-            foreach (var images in Posts.Skip(startIndex).SelectMany(x=>x.Images).ToList())
+            foreach (var images in Posts.Skip(startIndex).SelectMany(x=>x.Images.Concat(x.ContentViewModels.OfType<PostImageViewModel>())).ToList())
             {
                 await images.LoadAvatar();
 
@@ -183,6 +183,16 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
 
         public async Task OnClosingAsync(CancelEventArgs e)
         {
+            foreach (var post in Posts)
+            {
+                post.Attachments.Clear();
+                post.Images.Clear();
+                post.ContentViewModels.Clear();
+            }
+            Posts.Clear();
+
+            GC.Collect();
+
             //var result = await _dialogService.ShowMessageBoxAsync(this, "Do you want to close it?", "Confirmation", MessageBoxButton.YesNo);
             _cancellationTokenSource?.Cancel();
             e.Cancel = false;

+ 2 - 7
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/CreatorsViewModel.cs

@@ -21,15 +21,10 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
 
         public CreatorsViewModel(IDialogService dialogService)
         {
-            /*
-            BuyMusicCommand = ReactiveCommand.Create(() =>
-            {
-                return SelectedAlbum;
-            });*/
-            this._dialogService = dialogService;
+            _dialogService = dialogService;
 
             this.WhenAnyValue(x => x.SearchText)
-                .Throttle(TimeSpan.FromMilliseconds(400))
+                .Throttle(TimeSpan.FromMilliseconds(800))
                 .ObserveOn(RxApp.MainThreadScheduler)
                 .Subscribe(DoSearch!);
 

+ 64 - 4
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostViewModel.cs

@@ -1,5 +1,16 @@
-using HanumanInstitute.MvvmDialogs;
+using AngleSharp.Dom;
+using AngleSharp.Html.Dom;
+using AngleSharp.Html.Parser;
+using DynamicData;
+using HanumanInstitute.MvvmDialogs;
+using System;
+using System.Collections;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
 using System.Text.RegularExpressions;
 using VeloeAvaloniaKemonoPartyApp.Models;
 
@@ -10,6 +21,7 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
         private readonly Post _post;
         private readonly IDialogService _dialogService;
         private readonly ViewModelBase _parent;
+        private readonly IHtmlDocument _postContent;
 
         public PostViewModel(IDialogService dialogService,ViewModelBase parent, Post post)
         {
@@ -30,17 +42,65 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
 
                 Attachments.Add(new AttachmentViewModel(attachment));
             }
+
+            _postContent =  new HtmlParser().ParseDocument(post.Content);
+
+            foreach (var element in _postContent.Children)
+                SetUpViewModels(element, null);
+        }
+        
+        private void SetUpViewModels(IElement element, object vm)
+        {
+            var added = false;
+            if (element.TagName.Equals("p",StringComparison.OrdinalIgnoreCase))
+            {
+                if (vm is string text)
+                {
+                    text = text + (element.TextContent);
+                }
+                else
+                {
+                    vm = element.TextContent;
+                }
+                added = true;
+            }
+            else if (element.TagName.Equals("img", StringComparison.OrdinalIgnoreCase))
+            {
+                var attachment = new ExternalAttachment() { Url = element.Attributes.First(x => x.Name == "src").Value };
+                attachment.Path = Path.GetFileName(attachment.Url);
+                attachment.Name = Path.GetFileNameWithoutExtension(attachment.Path);
+
+                vm = new PostImageViewModel(_dialogService, _parent, attachment);
+                added = true;
+            }
+            else if (element.TagName.Equals("table",StringComparison.OrdinalIgnoreCase))
+            {
+                Debug.Assert(false);
+            }
+         
+            //ContentViewModels.Add();
+            foreach (var child in element.Children)
+                SetUpViewModels(child, vm);
+
+            if (vm is not null && added)
+            {
+                ContentViewModels.Add(vm);
+                vm = null;
+            }
         }
 
         public ObservableCollection<PostImageViewModel> Images { get; } = new();
 
         public ObservableCollection<AttachmentViewModel> Attachments { get; } = new();
 
+        public ObservableCollection<object> ContentViewModels { get; } = new();
+
         public AttachmentViewModel SelectedAttachment { get; set; }
         
         public bool IsImagesEmpty => Images.Count == 0;
 
-        public string Content => Regex.Replace(_post.Content, "<[^>]*>|&lt|&gt|&apos|&amp|&quot", (Match m) =>
+        public string Content => _postContent.FirstChild?.TextContent;
+            /*Regex.Replace(_post.Content, "<[^>]*>|&lt|&gt|&apos|&amp|&quot", (Match m) =>
             m.Value switch
             {
                 "&lt" => "<",
@@ -51,11 +111,11 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
                 "</p>" => "\n",
                 _ => ""
             }
-        );
+        );*/
 
         public string Title => _post.Title;
 
         public string Date => _post.Published;
-
     }
+
 }

+ 17 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostView.axaml

@@ -3,7 +3,8 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 			 xmlns:vm="clr-namespace:VeloeAvaloniaKemonoPartyApp.ViewModels"
-			 xmlns:av="clr-namespace:TheArtOfDev.HtmlRenderer.Avalonia;assembly=Avalonia.HtmlRenderer"
+			 xmlns:local="using:VeloeAvaloniaKemonoPartyApp.ViewModels"
+			 xmlns:system="using:System"
              mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="854"
              x:Class="VeloeAvaloniaKemonoPartyApp.Views.PostView"
 			 x:DataType="vm:PostViewModel">
@@ -18,7 +19,22 @@
 				</ItemsPanelTemplate>
 			</ItemsControl.ItemsPanel>
 		</ItemsControl>
+		<!-- 
 		<TextBlock Text="{Binding Content}" TextWrapping="Wrap" Margin="10 0 10 0"/>
+		-->
+		<ItemsControl ItemsSource="{Binding ContentViewModels}"
+					  Background="Transparent">
+			<ItemsControl.ItemsPanel>
+				<ItemsPanelTemplate>
+					<StackPanel/>
+				</ItemsPanelTemplate>
+			</ItemsControl.ItemsPanel>
+			<ItemsControl.DataTemplates>
+				<DataTemplate x:DataType="{x:Type system:String}">
+					<TextBlock TextWrapping="Wrap" Margin="10 0 10 0" Text="{Binding }"/>
+				</DataTemplate>	
+			</ItemsControl.DataTemplates>
+		</ItemsControl>
 		<ListBox ItemsSource="{Binding Attachments}" 
 				 SelectionMode="Single"
 				 Background="Transparent">