Bläddra i källkod

updated to net 8, added loading all images from post

Veloe 1 år sedan
förälder
incheckning
80e1c6acfe
15 ändrade filer med 202 tillägg och 70 borttagningar
  1. 4 4
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Android/VeloeAvaloniaKemonoPartyApp.Android.csproj
  2. 1 1
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Browser/VeloeAvaloniaKemonoPartyApp.Browser.csproj
  3. 3 3
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Desktop/VeloeAvaloniaKemonoPartyApp.Desktop.csproj
  4. 1 1
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.iOS/VeloeAvaloniaKemonoPartyApp.iOS.csproj
  5. 1 1
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/App.axaml.cs
  6. 69 3
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Models/Post.cs
  7. 9 3
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.csproj
  8. 7 1
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewLocator.cs
  9. 2 2
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/CreatorPostsViewModel.cs
  10. 67 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostImageViewModel.cs
  11. 11 46
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostViewModel.cs
  12. 1 1
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/CreatorPostsView.axaml
  13. 13 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostImageView.axaml
  14. 13 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostImageView.axaml.cs
  15. 0 4
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostView.axaml

+ 4 - 4
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Android/VeloeAvaloniaKemonoPartyApp.Android.csproj

@@ -1,16 +1,16 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net7.0-android33.0</TargetFramework>
-    <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
+    <TargetFramework>net8.0-android34.0</TargetFramework>
+    <SupportedOSPlatformVersion>29</SupportedOSPlatformVersion>
     <Nullable>enable</Nullable>
     <ApplicationId>com.CompanyName.VeloeAvaloniaKemonoPartyApp</ApplicationId>
     <ApplicationVersion>1</ApplicationVersion>
     <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
     <AndroidPackageFormat>apk</AndroidPackageFormat>
     <AndroidEnableProfiledAot>False</AndroidEnableProfiledAot>
-    <AssemblyVersion>1.0.0.46</AssemblyVersion>
-    <FileVersion>1.0.0.46</FileVersion>
+    <AssemblyVersion>1.0.0.55</AssemblyVersion>
+    <FileVersion>1.0.0.55</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Browser/VeloeAvaloniaKemonoPartyApp.Browser.csproj

@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
     <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
     <WasmMainJSPath>AppBundle\main.js</WasmMainJSPath>
     <OutputType>Exe</OutputType>

+ 3 - 3
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Desktop/VeloeAvaloniaKemonoPartyApp.Desktop.csproj

@@ -3,15 +3,15 @@
     <OutputType>WinExe</OutputType>
     <!--If you are willing to use Windows/MacOS native APIs you will need to create 3 projects.
     One for Windows with net7.0-windows TFM, one for MacOS with net7.0-macos and one with net7.0 TFM for Linux.-->
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
     <Nullable>enable</Nullable>
     <BuiltInComInteropSupport>true</BuiltInComInteropSupport>
   </PropertyGroup>
 
   <PropertyGroup>
     <ApplicationManifest>app.manifest</ApplicationManifest>
-    <AssemblyVersion>1.0.0.11</AssemblyVersion>
-    <FileVersion>1.0.0.11</FileVersion>
+    <AssemblyVersion>1.0.0.12</AssemblyVersion>
+    <FileVersion>1.0.0.12</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.iOS/VeloeAvaloniaKemonoPartyApp.iOS.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>net7.0-ios</TargetFramework>
+    <TargetFramework>net8.0-ios</TargetFramework>
     <SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
     <Nullable>enable</Nullable>
     <AssemblyVersion>1.0.0.5</AssemblyVersion>

+ 1 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/App.axaml.cs

@@ -19,7 +19,7 @@ namespace VeloeAvaloniaKemonoPartyApp
             var build = Locator.CurrentMutable;
             build.RegisterLazySingleton(() => (IDialogService)new DialogService(
                 new DialogManager(
-                    viewLocator: new VeloeAvaloniaKemonoPartyApp.Dialogs.ViewLocator(),
+                    viewLocator: ApplicationLifetime is IClassicDesktopStyleApplicationLifetime ? new Dialogs.ViewLocatorDesktop() : new Dialogs.ViewLocatorSingle(),
                     dialogFactory: new DialogFactory().AddMessageBox(MessageBoxMode.Popup)),
                 viewModelFactory: x => Locator.Current.GetService(x)));
 

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

@@ -2,6 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Net;
+using System.Net.Mail;
 using System.Text.Json;
 using System.Text.Json.Serialization;
 using System.Threading.Tasks;
@@ -126,13 +127,78 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
         [JsonPropertyName("path")]
         public string Path { get; set; }
 
-        public string Link
+        public string Link => $"https://kemono.su/data{Path}";
+
+        private static KemonoHttpClient s_httpClient = new();
+        private string CachePath => $"./Cache/{Path.Split('/').Last()}";
+
+        public async Task<Stream> LoadCoverBitmapAsync()
+        {
+            if (System.IO.File.Exists(CachePath + ".bmp"))
+            {
+                return System.IO.File.OpenRead(CachePath + ".bmp");
+            }
+            else
+            {
+                try
+                {
+                    var data = await s_httpClient.httpClient.GetByteArrayAsync(Link);
+                    return new MemoryStream(data);
+                }
+                catch (System.Net.Http.HttpRequestException ex)
+                {
+                    return new MemoryStream();
+                }
+            }
+        }
+
+        public async Task SaveAsync()
         {
-            get
+            if (!Directory.Exists("./Cache"))
             {
-                return $"https://kemono.su/data{Path}";
+                Directory.CreateDirectory("./Cache");
+            }
+
+            using (var fs = System.IO.File.OpenWrite(CachePath))
+            {
+                await SaveToStreamAsync(this, fs);
             }
         }
+
+        public Stream SaveCoverBitmapStream()
+        {
+            return System.IO.File.OpenWrite(CachePath + ".bmp");
+        }
+
+        private static async Task SaveToStreamAsync(Attachment data, Stream stream)
+        {
+            await JsonSerializer.SerializeAsync(stream, data).ConfigureAwait(false);
+        }
+
+        public static async Task<Attachment> LoadFromStream(Stream stream)
+        {
+            return (await JsonSerializer.DeserializeAsync<Attachment>(stream).ConfigureAwait(false))!;
+        }
+
+        public static async Task<IEnumerable<Attachment>> LoadCachedAsync()
+        {
+            if (!Directory.Exists("./Cache"))
+            {
+                Directory.CreateDirectory("./Cache");
+            }
+
+            var results = new List<Attachment>();
+
+            foreach (var file in Directory.EnumerateFiles("./Cache"))
+            {
+                if (!string.IsNullOrWhiteSpace(new DirectoryInfo(file).Extension)) continue;
+
+                await using var fs = System.IO.File.OpenRead(file);
+                results.Add(await Attachment.LoadFromStream(fs).ConfigureAwait(false));
+            }
+
+            return results;
+        }
     }
 
     public class Embed

+ 9 - 3
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.csproj

@@ -1,11 +1,11 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
     <Nullable>enable</Nullable>
     <LangVersion>latest</LangVersion>
     <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
-    <AssemblyVersion>1.0.0.51</AssemblyVersion>
-    <FileVersion>1.0.0.51</FileVersion>
+    <AssemblyVersion>1.0.0.58</AssemblyVersion>
+    <FileVersion>1.0.0.58</FileVersion>
   </PropertyGroup>
 
   
@@ -30,4 +30,10 @@
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
   </ItemGroup>
+
+  <ItemGroup>
+    <Compile Update="Views\PostImageView.axaml.cs">
+      <DependentUpon>PostImageView.axaml</DependentUpon>
+    </Compile>
+  </ItemGroup>
 </Project>

+ 7 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewLocator.cs

@@ -33,9 +33,15 @@ namespace VeloeAvaloniaKemonoPartyApp
 
 namespace VeloeAvaloniaKemonoPartyApp.Dialogs
 {
-    public class ViewLocator : ViewLocatorBase
+    public class ViewLocatorSingle : ViewLocatorBase
     {
         /// <inheritdoc />
         protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", "View");
     }
+
+    public class  ViewLocatorDesktop : ViewLocatorBase
+    {
+        /// <inheritdoc />
+        protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", "Window");
+    }
 }

+ 2 - 2
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/CreatorPostsViewModel.cs

@@ -75,9 +75,9 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
 
         private async void LoadAvatars(CancellationToken cancellationToken)
         {
-            foreach (var post in Posts.ToList())
+            foreach (var images in Posts.SelectMany(x=>x.Images).ToList())
             {
-                await post.LoadAvatar();
+                await images.LoadAvatar();
 
                 if (cancellationToken.IsCancellationRequested)
                 {

+ 67 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostImageViewModel.cs

@@ -0,0 +1,67 @@
+using Avalonia.Media.Imaging;
+using ReactiveUI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using VeloeAvaloniaKemonoPartyApp.Models;
+
+namespace VeloeAvaloniaKemonoPartyApp.ViewModels
+{
+    public class PostImageViewModel : ViewModelBase
+    {
+        private Attachment _attachment;
+        public PostImageViewModel(Attachment attachment)
+        {
+            _attachment = attachment;
+        }
+
+        private Bitmap? _cover;
+
+        public Bitmap? Cover
+        {
+            get => _cover;
+            private set => this.RaiseAndSetIfChanged(ref _cover, value);
+        }
+
+        public async Task LoadAvatar()
+        {
+            await using (var imageStream = await _attachment.LoadCoverBitmapAsync())
+            {
+                Cover = await Task.Run(() =>
+                {
+                    Bitmap? bitmap;
+                    try
+                    {
+                        bitmap = new Bitmap(imageStream);
+                        bitmap = bitmap.CreateScaledBitmap(new Avalonia.PixelSize(bitmap.PixelSize.Width / 2, bitmap.PixelSize.Height / 2));
+                    }
+                    catch (Exception ex)
+                    {
+                        bitmap = null;
+                    }
+                    return bitmap;
+                });
+            }
+        }
+
+        public async Task SaveToDiskAsync()
+        {
+            await _attachment.SaveAsync();
+
+            if (Cover != null)
+            {
+                var bitmap = Cover;
+
+                await Task.Run(() =>
+                {
+                    using (var fs = _attachment.SaveCoverBitmapStream())
+                    {
+                        bitmap.Save(fs);
+                    }
+                });
+            }
+        }
+    }
+}

+ 11 - 46
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostViewModel.cs

@@ -3,6 +3,7 @@ using Avalonia.Media.Imaging;
 using ReactiveUI;
 using System;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -17,59 +18,23 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
         public PostViewModel(Post post)
         {
             _post = post;
-        }
-
-        public string Artist => _post.Content;
-
-        public string Title => _post.Title;
-
-        private Bitmap? _cover;
-
-        public Bitmap? Cover
-        {
-            get => _cover;
-            private set => this.RaiseAndSetIfChanged(ref _cover, value);
-        }
 
-        public async Task LoadAvatar()
-        {
-            if (_post.Attachments.Count == 0) return;
+            Images.Clear();
 
-            await using (var imageStream = await _post.LoadCoverBitmapAsync())
+            foreach (var attachment in _post.Attachments)
             {
-                Cover = await Task.Run(() =>
-                {
-                    Bitmap? bitmap;
-                    try
-                    {
-                        bitmap = new Bitmap(imageStream);
-                        bitmap = bitmap.CreateScaledBitmap(new Avalonia.PixelSize(bitmap.PixelSize.Width / 2, bitmap.PixelSize.Height / 2));
-                    }
-                    catch (Exception ex)
-                    {
-                        bitmap = null;
-                    }
-                    return bitmap;
-                });
+                if (attachment is null) continue;
+
+                if (attachment.Path.EndsWith(".jpg") || attachment.Path.EndsWith(".png") || attachment.Path.EndsWith(".jpeg"))
+                    Images.Add(new PostImageViewModel(attachment));
             }
         }
 
-        public async Task SaveToDiskAsync()
-        {
-            await _post.SaveAsync();
+        public ObservableCollection<PostImageViewModel> Images { get; } = new(); 
 
-            if (Cover != null)
-            {
-                var bitmap = Cover;
+        public string Artist => _post.Content;
+
+        public string Title => _post.Title;
 
-                await Task.Run(() =>
-                {
-                    using (var fs = _post.SaveCoverBitmapStream())
-                    {
-                        bitmap.Save(fs);
-                    }
-                });
-            }
-        }
     }
 }

+ 1 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/CreatorPostsView.axaml

@@ -18,7 +18,7 @@
 					 Background="Transparent" Margin="0 20">
 				<ItemsControl.ItemsPanel>
 					<ItemsPanelTemplate>
-						<VirtualizingStackPanel />					
+						<VirtualizingStackPanel/>					
 					</ItemsPanelTemplate>
 				</ItemsControl.ItemsPanel>
 			</ItemsControl>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 13 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostImageView.axaml


+ 13 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostImageView.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace VeloeAvaloniaKemonoPartyApp.Views;
+
+public partial class PostImageView : UserControl
+{
+    public PostImageView()
+    {
+        InitializeComponent();
+    }
+}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 4
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostView.axaml


Vissa filer visades inte eftersom för många filer har ändrats