Browse Source

added cache to posts images

Veloe 1 year ago
parent
commit
fd5783fd3a

+ 2 - 2
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Android/VeloeAvaloniaKemonoPartyApp.Android.csproj

@@ -9,8 +9,8 @@
     <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
     <AndroidPackageFormat>apk</AndroidPackageFormat>
     <AndroidEnableProfiledAot>False</AndroidEnableProfiledAot>
-    <AssemblyVersion>1.0.0.55</AssemblyVersion>
-    <FileVersion>1.0.0.55</FileVersion>
+    <AssemblyVersion>1.0.0.70</AssemblyVersion>
+    <FileVersion>1.0.0.70</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 53
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Models/Creator.cs

@@ -1,10 +1,6 @@
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Text.Json;
 using System.Threading.Tasks;
 using VeloeKemonoPartyApp.Services;
 
@@ -54,53 +50,5 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
             }
         }
 
-        public async Task SaveAsync()
-        {
-            if (!Directory.Exists("./Cache"))
-            {
-                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(Creator data, Stream stream)
-        {
-            await JsonSerializer.SerializeAsync(stream, data).ConfigureAwait(false);
-        }
-
-        public static async Task<Creator> LoadFromStream(Stream stream)
-        {
-            return (await JsonSerializer.DeserializeAsync<Creator>(stream).ConfigureAwait(false))!;
-        }
-
-        public static async Task<IEnumerable<Creator>> LoadCachedAsync()
-        {
-            if (!Directory.Exists("./Cache"))
-            {
-                Directory.CreateDirectory("./Cache");
-            }
-
-            var results = new List<Creator>();
-
-            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 Creator.LoadFromStream(fs).ConfigureAwait(false));
-            }
-
-            return results;
-        }
-
     }
 }

+ 35 - 106
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Models/Post.cs

@@ -1,11 +1,10 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 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;
+using VeloeAvaloniaKemonoPartyApp.Services;
 using VeloeKemonoPartyApp.Services;
 
 
@@ -70,54 +69,6 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
                 }
             }
         }
-
-        public async Task SaveAsync()
-        {
-            if (!Directory.Exists("./Cache"))
-            {
-                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(Post data, Stream stream)
-        {
-            await JsonSerializer.SerializeAsync(stream, data).ConfigureAwait(false);
-        }
-
-        public static async Task<Post> LoadFromStream(Stream stream)
-        {
-            return (await JsonSerializer.DeserializeAsync<Post>(stream).ConfigureAwait(false))!;
-        }
-
-        public static async Task<IEnumerable<Post>> LoadCachedAsync()
-        {
-            if (!Directory.Exists("./Cache"))
-            {
-                Directory.CreateDirectory("./Cache");
-            }
-
-            var results = new List<Post>();
-
-            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 Post.LoadFromStream(fs).ConfigureAwait(false));
-            }
-
-            return results;
-        }
     }
 
     public class Attachment
@@ -130,75 +81,53 @@ namespace VeloeAvaloniaKemonoPartyApp.Models
         public string Link => $"https://kemono.su/data{Path}";
 
         private static KemonoHttpClient s_httpClient = new();
-        private string CachePath => $"./Cache/{Path.Split('/').Last()}";
+
+        private static StorageService s_storage = new();
+
+        private string CachePath => $"./Cache/{FileName}";
+
+        private string FileName => Path.Split('/').Last();
 
         public async Task<Stream> LoadCoverBitmapAsync()
         {
-            if (System.IO.File.Exists(CachePath + ".bmp"))
+            if (System.IO.File.Exists(System.IO.Path.Combine(await s_storage.GetDocumentsFolderAsync(),  FileName + ".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)
+                var stream = System.IO.File.OpenRead(System.IO.Path.Combine(await s_storage.GetDocumentsFolderAsync(), FileName + ".bmp"));
+
+                byte[] hash = System.Security.Cryptography.SHA256.Create().ComputeHash(stream);
+
+                var hashstr = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
+                if (hashstr == FileName.Split('.').First())
                 {
-                    return new MemoryStream();
+                    stream.Position = 0;
+                    return stream;
                 }
+                stream.Close();
             }
-        }
-
-        public async Task SaveAsync()
-        {
-            if (!Directory.Exists("./Cache"))
-            {
-                Directory.CreateDirectory("./Cache");
-            }
-
-            using (var fs = System.IO.File.OpenWrite(CachePath))
+            
+            try
             {
-                await SaveToStreamAsync(this, fs);
-            }
-        }
+                var data = await s_httpClient.httpClient.GetByteArrayAsync(Link);
 
-        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))!;
-        }
+                using (var stream = System.IO.File.OpenWrite(System.IO.Path.Combine(await s_storage.GetDocumentsFolderAsync(), FileName + ".bmp")))
+                {
+                    await stream.WriteAsync(data);
+                }
 
-        public static async Task<IEnumerable<Attachment>> LoadCachedAsync()
-        {
-            if (!Directory.Exists("./Cache"))
+                return new MemoryStream(data);
+            }
+            catch (System.Net.Http.HttpRequestException ex)
             {
-                Directory.CreateDirectory("./Cache");
+                return null;
             }
-
-            var results = new List<Attachment>();
-
-            foreach (var file in Directory.EnumerateFiles("./Cache"))
+            catch (OperationCanceledException ex)
             {
-                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));
+                //System.IO.File.Delete(CachePath + ".bmp");
+                return null;
             }
-
-            return results;
+            
         }
+
     }
 
     public class Embed

+ 42 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Services/StorageService.cs

@@ -0,0 +1,42 @@
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Controls;
+using Avalonia.Platform.Storage;
+using System;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.VisualTree;
+
+namespace VeloeAvaloniaKemonoPartyApp.Services
+{
+    public class StorageService
+    {
+        protected virtual IStorageProvider Storage => _storage ??= GetTopLevel()?.StorageProvider ?? throw new NullReferenceException("No StorageProvider found.");
+        private IStorageProvider? _storage;
+
+        public async Task<string?> GetDocumentsFolderAsync()
+        {
+            var result = await Storage.TryGetWellKnownFolderAsync(WellKnownFolder.Documents);
+            return result.TryGetLocalPath();
+        }
+
+        public async Task<string?> GetPicturesFolderAsync()
+        {
+            var result = await Storage.TryGetWellKnownFolderAsync(WellKnownFolder.Pictures);
+            return result.TryGetLocalPath();
+        }
+
+        private TopLevel? GetTopLevel()
+        {
+            if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+            {
+                return desktop.MainWindow;
+            }
+            if (Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime viewApp)
+            {
+                var visualRoot = viewApp.MainView?.GetVisualRoot();
+                return visualRoot as TopLevel;
+            }
+            return null;
+        }
+    }
+}

+ 4 - 4
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.csproj

@@ -4,8 +4,8 @@
     <Nullable>enable</Nullable>
     <LangVersion>latest</LangVersion>
     <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
-    <AssemblyVersion>1.0.0.58</AssemblyVersion>
-    <FileVersion>1.0.0.58</FileVersion>
+    <AssemblyVersion>1.0.0.92</AssemblyVersion>
+    <FileVersion>1.0.0.92</FileVersion>
   </PropertyGroup>
 
   
@@ -23,8 +23,8 @@
     <PackageReference Include="Avalonia.ReactiveUI" Version="11.0.6" />
     <!--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 Include="HanumanInstitute.MvvmDialogs.Avalonia" Version="2.0.0" />
-    <PackageReference Include="HanumanInstitute.MvvmDialogs.Avalonia.MessageBox" Version="2.0.0" />
+    <PackageReference Include="HanumanInstitute.MvvmDialogs.Avalonia" Version="2.1.0" />
+    <PackageReference Include="HanumanInstitute.MvvmDialogs.Avalonia.MessageBox" Version="2.1.0" />
     <PackageReference Include="Splat.DependencyInjection.SourceGenerator" Version="1.1.93">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

+ 1 - 22
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/CreatorViewModel.cs

@@ -1,9 +1,6 @@
 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;
 
@@ -20,7 +17,7 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
 
         public string Artist => _creator.name;
 
-        public string Title => _creator.updated.ToString();
+        public string Title => _creator.service;
 
         public Creator Creator => _creator;
 
@@ -51,23 +48,5 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
                 });
             }
         }
-
-        public async Task SaveToDiskAsync()
-        {
-            await _creator.SaveAsync();
-
-            if (Cover != null)
-            {
-                var bitmap = Cover;
-
-                await Task.Run(() =>
-                {
-                    using (var fs = _creator.SaveCoverBitmapStream())
-                    {
-                        bitmap.Save(fs);
-                    }
-                });
-            }
-        }
     }
 }

+ 2 - 20
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostImageViewModel.cs

@@ -1,9 +1,6 @@
 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;
 
@@ -29,6 +26,8 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
         {
             await using (var imageStream = await _attachment.LoadCoverBitmapAsync())
             {
+                if (imageStream is null) return;
+
                 Cover = await Task.Run(() =>
                 {
                     Bitmap? bitmap;
@@ -46,22 +45,5 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
             }
         }
 
-        public async Task SaveToDiskAsync()
-        {
-            await _attachment.SaveAsync();
-
-            if (Cover != null)
-            {
-                var bitmap = Cover;
-
-                await Task.Run(() =>
-                {
-                    using (var fs = _attachment.SaveCoverBitmapStream())
-                    {
-                        bitmap.Save(fs);
-                    }
-                });
-            }
-        }
     }
 }

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

@@ -1,12 +1,4 @@
-using Avalonia.Controls.ApplicationLifetimes;
-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;
+using System.Collections.ObjectModel;
 using VeloeAvaloniaKemonoPartyApp.Models;
 
 namespace VeloeAvaloniaKemonoPartyApp.ViewModels
@@ -30,11 +22,15 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
             }
         }
 
-        public ObservableCollection<PostImageViewModel> Images { get; } = new(); 
+        public ObservableCollection<PostImageViewModel> Images { get; } = new();
+        
+        public bool IsImagesEmpty => Images.Count == 0;
 
-        public string Artist => _post.Content;
+        public string Content => _post.Content;
 
         public string Title => _post.Title;
 
+        public string Date => _post.Published;
+
     }
 }

+ 6 - 4
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostView.axaml

@@ -8,15 +8,17 @@
              x:Class="VeloeAvaloniaKemonoPartyApp.Views.PostView"
 			 x:DataType="vm:PostViewModel">
 	<StackPanel Spacing="5">
+		<TextBlock HorizontalAlignment="Center" FontSize="16" Text="{Binding Title}"/>
 		<ItemsControl ItemsSource="{Binding Images}"
-					   Background="Transparent" Margin="0 20">
+					  Background="Transparent"
+					  IsVisible="{Binding !IsImagesEmpty}">
 			<ItemsControl.ItemsPanel>
 				<ItemsPanelTemplate>
-					<VirtualizingStackPanel/>
+					<StackPanel/>
 				</ItemsPanelTemplate>
 			</ItemsControl.ItemsPanel>
 		</ItemsControl>
-		<TextBlock HorizontalAlignment="Center" Text="{Binding Title}"/>
-		<av:HtmlPanel HorizontalAlignment="Center" Text="{Binding Artist}" Background="MintCream"/>
+		<av:HtmlPanel HorizontalAlignment="Center" Text="{Binding Content}" Background="MintCream"/>
+		<TextBlock HorizontalAlignment="Right" FontSize="10" FontStyle="Italic" Text="{Binding Date}"/>
 	</StackPanel>
 </UserControl>