Ver código fonte

added image zoom view

Veloe 1 ano atrás
pai
commit
ae4ec34483
19 arquivos alterados com 267 adições e 39 exclusões
  1. 2 2
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Android/VeloeAvaloniaKemonoPartyApp.Android.csproj
  2. 2 2
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Browser/VeloeAvaloniaKemonoPartyApp.Browser.csproj
  3. 2 2
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Desktop/VeloeAvaloniaKemonoPartyApp.Desktop.csproj
  4. 2 2
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.iOS/VeloeAvaloniaKemonoPartyApp.iOS.csproj
  5. 2 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/App.axaml
  6. 0 1
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/App.axaml.cs
  7. 4 3
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.csproj
  8. 40 7
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/CreatorPostsViewModel.cs
  9. 83 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/ImageZoomViewModel.cs
  10. 13 2
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostImageViewModel.cs
  11. 8 3
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostViewModel.cs
  12. 18 8
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/CreatorPostsView.axaml
  13. 5 6
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/CreatorsView.axaml
  14. 23 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/ImageZoomView.axaml
  15. 32 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/ImageZoomView.axaml.cs
  16. 1 1
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostImageView.axaml
  17. 7 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostImageView.axaml.cs
  18. 10 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Windows/ImageZoomWindow.axaml
  19. 13 0
      VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Windows/ImageZoomWindow.axaml.cs

+ 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.70</AssemblyVersion>
-    <FileVersion>1.0.0.70</FileVersion>
+    <AssemblyVersion>1.0.0.73</AssemblyVersion>
+    <FileVersion>1.0.0.73</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

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

@@ -4,8 +4,8 @@
     <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
     <WasmMainJSPath>AppBundle\main.js</WasmMainJSPath>
     <OutputType>Exe</OutputType>
-    <AssemblyVersion>1.0.0.5</AssemblyVersion>
-    <FileVersion>1.0.0.5</FileVersion>
+    <AssemblyVersion>1.0.0.6</AssemblyVersion>
+    <FileVersion>1.0.0.6</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

+ 2 - 2
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.Desktop/VeloeAvaloniaKemonoPartyApp.Desktop.csproj

@@ -10,8 +10,8 @@
 
   <PropertyGroup>
     <ApplicationManifest>app.manifest</ApplicationManifest>
-    <AssemblyVersion>1.0.0.20</AssemblyVersion>
-    <FileVersion>1.0.0.20</FileVersion>
+    <AssemblyVersion>1.0.0.43</AssemblyVersion>
+    <FileVersion>1.0.0.43</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

+ 2 - 2
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.iOS/VeloeAvaloniaKemonoPartyApp.iOS.csproj

@@ -4,8 +4,8 @@
     <TargetFramework>net8.0-ios</TargetFramework>
     <SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
     <Nullable>enable</Nullable>
-    <AssemblyVersion>1.0.0.5</AssemblyVersion>
-    <FileVersion>1.0.0.5</FileVersion>
+    <AssemblyVersion>1.0.0.6</AssemblyVersion>
+    <FileVersion>1.0.0.6</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

+ 2 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/App.axaml

@@ -12,5 +12,7 @@
     <Application.Styles>
         <FluentTheme />
 		<StyleInclude Source="avares://Avalonia.Controls.TreeDataGrid/Themes/Fluent.axaml"/>
+		<StyleInclude Source="avares://UVtools.AvaloniaControls/Controls.axaml"/>
     </Application.Styles>
+
 </Application>

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

@@ -40,7 +40,6 @@ namespace VeloeAvaloniaKemonoPartyApp
         public static CreatorsViewModel CreatorsViewModel => Locator.Current.GetService<CreatorsViewModel>()!;
 
         public static CreatorPostsViewModel CreatorPostsViewModel => Locator.Current.GetService<CreatorPostsViewModel>()!;
-
         private static IDialogService DialogService => Locator.Current.GetService<IDialogService>()!;
         public static StrongViewLocator ViewLocator { get; private set; } = default!;
     }

+ 4 - 3
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp.csproj

@@ -4,8 +4,8 @@
     <Nullable>enable</Nullable>
     <LangVersion>latest</LangVersion>
     <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
-    <AssemblyVersion>1.0.0.122</AssemblyVersion>
-    <FileVersion>1.0.0.122</FileVersion>
+    <AssemblyVersion>1.0.0.166</AssemblyVersion>
+    <FileVersion>1.0.0.166</FileVersion>
   </PropertyGroup>
 
   
@@ -14,8 +14,8 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="AsyncImageLoader.Avalonia" Version="3.2.1" />
     <PackageReference Include="Avalonia" 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="Avalonia.HtmlRenderer" Version="11.0.0" />
     <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.6" />
@@ -29,6 +29,7 @@
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
+    <PackageReference Include="UVtools.AvaloniaControls" Version="3.0.1" />
   </ItemGroup>
 
   <ItemGroup>

+ 40 - 7
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/CreatorPostsViewModel.cs

@@ -20,9 +20,6 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
         public event EventHandler? RequestClose;
         public bool? DialogResult => true;
 
-
-        private Creator _creator;
-
         public ObservableCollection<PostViewModel> Posts { get; } = new();
 
         public CreatorPostsViewModel(IDialogService dialogService) 
@@ -39,11 +36,17 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
             get => _isBusy;
             set => this.RaiseAndSetIfChanged(ref _isBusy, value);
         }
-
-        public Creator Creator { get => _creator; set {
+        
+        private Creator _creator;
+        public Creator Creator 
+        {
+            get => _creator; 
+            set 
+            {
                 _creator = value;
                 InitPosts();
-            } }
+            } 
+        }
 
         private async void InitPosts()
         {
@@ -60,7 +63,37 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
 
                 foreach (var post in posts)
                 {
-                    var vm = new PostViewModel(post);
+                    var vm = new PostViewModel(_dialogService,post);
+                    Posts.Add(vm);
+                }
+
+                if (!cancellationToken.IsCancellationRequested)
+                {
+                    LoadAvatars(cancellationToken);
+                }
+            }
+
+            IsBusy = false;
+        }
+
+        public async void LoadMorePosts()
+        {
+            if (IsBusy) return;
+
+            if (_cancellationTokenSource is null)
+                _cancellationTokenSource = new();
+
+            var cancellationToken = _cancellationTokenSource.Token;
+
+            IsBusy = true;
+
+            if (_creator is not null)
+            {
+                var posts = await Post.LoadPostsAsync(_creator,Posts.Count);
+
+                foreach (var post in posts)
+                {
+                    var vm = new PostViewModel(_dialogService,post);
                     Posts.Add(vm);
                 }
 

+ 83 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/ImageZoomViewModel.cs

@@ -0,0 +1,83 @@
+using Avalonia.Media.Imaging;
+using HanumanInstitute.MvvmDialogs;
+using ReactiveUI;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using VeloeAvaloniaKemonoPartyApp.Models;
+
+namespace VeloeAvaloniaKemonoPartyApp.ViewModels
+{
+    public class ImageZoomViewModel : ViewModelBase, IModalDialogViewModel, IViewClosing, IViewLoaded, ICloseable
+    {
+        private readonly Attachment _attachment;
+
+        public event EventHandler? RequestClose;
+        public bool? DialogResult => true;
+
+        public ReactiveCommand<System.Reactive.Unit, System.Reactive.Unit> Close { get; }
+
+        public ImageZoomViewModel(Attachment attachment) 
+        {
+            _attachment = attachment;
+            Close = ReactiveCommand.Create(CloseImpl);
+            LoadAvatar();
+        }
+
+        private Bitmap? _cover;
+
+        public Bitmap? Cover
+        {
+            get => _cover;
+            private set => this.RaiseAndSetIfChanged(ref _cover, value);
+        }
+
+        public UVtools.AvaloniaControls.AdvancedImageBox.SizeModes SizeModeValue => UVtools.AvaloniaControls.AdvancedImageBox.SizeModes.Fit;
+
+        public async Task LoadAvatar()
+        {
+            await using (var imageStream = await _attachment.LoadCoverBitmapAsync())
+            {
+                if (imageStream is null) return;
+                Cover = await Task.Run(() =>
+                {
+                    Bitmap? bitmap;
+                    try
+                    {
+                        bitmap = new Bitmap(imageStream);
+                    }
+                    catch (Exception ex)
+                    {
+                        bitmap = null;
+                    }
+                    return bitmap;
+                });
+            }
+        }
+
+        public void OnLoaded()
+        {
+
+        }
+
+        public void OnClosing(CancelEventArgs e)
+        {
+            e.Cancel = true;
+        }
+
+        private void CloseImpl()
+        {
+            RequestClose?.Invoke(this, EventArgs.Empty);
+        }
+
+        public async Task OnClosingAsync(CancelEventArgs e)
+        {
+            //_cancellationTokenSource?.Cancel();
+            e.Cancel = false;
+        }
+    }
+}

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

@@ -1,4 +1,7 @@
-using Avalonia.Media.Imaging;
+using Avalonia.Interactivity;
+using Avalonia.Media.Imaging;
+using Avalonia.Threading;
+using HanumanInstitute.MvvmDialogs;
 using ReactiveUI;
 using System;
 using System.Threading.Tasks;
@@ -9,9 +12,11 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
     public class PostImageViewModel : ViewModelBase
     {
         private Attachment _attachment;
-        public PostImageViewModel(Attachment attachment)
+        private readonly IDialogService _dialogService;
+        public PostImageViewModel(IDialogService dialogService,Attachment attachment)
         {
             _attachment = attachment;
+            _dialogService = dialogService;
         }
 
         private Bitmap? _cover;
@@ -45,5 +50,11 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
             }
         }
 
+        public async Task OnImageClick(object sender, RoutedEventArgs e)
+        {
+            var vm = new ImageZoomViewModel(_attachment);
+            _dialogService.Show(null, vm);
+        }
+
     }
 }

+ 8 - 3
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/ViewModels/PostViewModel.cs

@@ -1,4 +1,5 @@
-using System.Collections.ObjectModel;
+using HanumanInstitute.MvvmDialogs;
+using System.Collections.ObjectModel;
 using VeloeAvaloniaKemonoPartyApp.Models;
 
 namespace VeloeAvaloniaKemonoPartyApp.ViewModels
@@ -6,10 +7,12 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
     public class PostViewModel : ViewModelBase
     {
         private readonly Post _post;
+        private readonly IDialogService _dialogService;
 
-        public PostViewModel(Post post)
+        public PostViewModel(IDialogService dialogService, Post post)
         {
             _post = post;
+            _dialogService = dialogService;
 
             Images.Clear();
 
@@ -18,7 +21,9 @@ namespace VeloeAvaloniaKemonoPartyApp.ViewModels
                 if (attachment is null) continue;
 
                 if (attachment.Path.EndsWith(".jpg") || attachment.Path.EndsWith(".png") || attachment.Path.EndsWith(".jpeg"))
-                    Images.Add(new PostImageViewModel(attachment));
+                {
+                    Images.Add(new PostImageViewModel(_dialogService,attachment));
+                }
             }
         }
 

+ 18 - 8
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/CreatorPostsView.axaml

@@ -14,14 +14,24 @@
 	</Design.DataContext>
 	<DockPanel>
 		<ScrollViewer>
-			<ItemsControl ItemsSource="{Binding Posts}"
-					 Background="Transparent" Margin="0 20">
-				<ItemsControl.ItemsPanel>
-					<ItemsPanelTemplate>
-						<VirtualizingStackPanel />					
-					</ItemsPanelTemplate>
-				</ItemsControl.ItemsPanel>
-			</ItemsControl>
+			<StackPanel>
+				<ItemsControl 
+					ItemsSource="{Binding Posts}"
+					Background="Transparent"   
+					Margin="0 20">
+					<ItemsControl.ItemsPanel>
+						<ItemsPanelTemplate>
+							<VirtualizingStackPanel />					
+						</ItemsPanelTemplate>
+					</ItemsControl.ItemsPanel>
+				</ItemsControl>
+				<Button 
+					Command="{Binding LoadMorePosts}"
+					HorizontalContentAlignment="Center"
+					HorizontalAlignment="Stretch" 
+					IsEnabled="{Binding !IsBusy}">Load More
+				</Button>
+			</StackPanel>
 		</ScrollViewer>
 	</DockPanel>
 </UserControl>

+ 5 - 6
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/CreatorsView.axaml

@@ -13,7 +13,7 @@
 		<vm:CreatorsViewModel />
 	</Design.DataContext>
 	<DockPanel>
-		<StackPanel DockPanel.Dock="Top">
+		<StackPanel DockPanel.Dock="Top" Margin="10 10 10 0">
 			<TextBox Watermark="Search for creators..." Text="{Binding SearchText}"/>
 			<ProgressBar IsIndeterminate="True" IsVisible="{Binding IsBusy}"/>
 		</StackPanel>
@@ -21,13 +21,12 @@
 				 Background="Transparent" Margin="0 20" Gestures.PullGesture="ReloadCreatorsSource">
 			<ListBox.ItemsPanel>
 				<ItemsPanelTemplate>
-					<WrapPanel>
-						<WrapPanel.GestureRecognizers>
-							<PullGestureRecognizer PullDirection="TopToBottom"/>
-						</WrapPanel.GestureRecognizers>
-					</WrapPanel>
+					<StackPanel/>
 				</ItemsPanelTemplate>
 			</ListBox.ItemsPanel>
+			<ListBox.GestureRecognizers>
+				<PullGestureRecognizer PullDirection="TopToBottom"/>
+			</ListBox.GestureRecognizers>
 		</ListBox>
 	</DockPanel>
 </UserControl>

+ 23 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/ImageZoomView.axaml

@@ -0,0 +1,23 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             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:paz="using:Avalonia.Controls.PanAndZoom"
+             mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="854"
+             x:Class="VeloeAvaloniaKemonoPartyApp.Views.ImageZoomView"
+			 x:DataType="vm:ImageZoomViewModel">
+
+	<paz:ZoomBorder Name="ZoomBorder" Stretch="None" ZoomSpeed="1.2"
+                    Background="Black" ClipToBounds="True" Focusable="True"
+                    VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
+					Gestures.Pinch="ZoomImage" 
+					Gestures.PinchEnded="ZoomImageEnd" 
+					Gestures.DoubleTapped="ZoomImageToDefault">
+		<Image Source="{Binding Cover}">
+			<Image.GestureRecognizers>
+				<PinchGestureRecognizer/>
+			</Image.GestureRecognizers>
+		</Image>
+	</paz:ZoomBorder>
+</UserControl>

+ 32 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/ImageZoomView.axaml.cs

@@ -0,0 +1,32 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.PanAndZoom;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+
+namespace VeloeAvaloniaKemonoPartyApp.Views;
+
+public partial class ImageZoomView : UserControl
+{
+    public ImageZoomView()
+    {
+        InitializeComponent();
+    }
+
+    public void ZoomImage(object? source, PinchEventArgs args)
+    {
+        this.GetControl<ZoomBorder>("ZoomBorder").ZoomTo(args.Scale,args.ScaleOrigin.X,args.ScaleOrigin.Y);
+    }
+
+    public void ZoomImageEnd(object? source, PinchEndedEventArgs args) 
+    {
+
+    }
+
+    public void ZoomImageToDefault(object? source, RoutedEventArgs args) 
+    {
+        var zoomBorder = this.GetControl<ZoomBorder>("ZoomBorder");
+        zoomBorder.Uniform();
+    }
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Views/PostImageView.axaml


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

@@ -1,6 +1,8 @@
 using Avalonia;
 using Avalonia.Controls;
+using Avalonia.Interactivity;
 using Avalonia.Markup.Xaml;
+using VeloeAvaloniaKemonoPartyApp.ViewModels;
 
 namespace VeloeAvaloniaKemonoPartyApp.Views;
 
@@ -10,4 +12,9 @@ public partial class PostImageView : UserControl
     {
         InitializeComponent();
     }
+
+    public async void OnImageClick(object sender, RoutedEventArgs e)
+    {
+        await ((PostImageViewModel)this.DataContext).OnImageClick(sender, e);
+    }
 }

+ 10 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Windows/ImageZoomWindow.axaml

@@ -0,0 +1,10 @@
+<Window xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+		xmlns:views="clr-namespace:VeloeAvaloniaKemonoPartyApp.Views"
+        mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="854" Width="480" Height="854"
+        x:Class="VeloeAvaloniaKemonoPartyApp.Windows.ImageZoomWindow"
+        Title="ImageZoomWindow">
+	<views:ImageZoomView/>
+</Window>

+ 13 - 0
VeloeAvaloniaKemonoPartyApp/VeloeAvaloniaKemonoPartyApp/Windows/ImageZoomWindow.axaml.cs

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

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff