Refined version of the demo.
This commit is contained in:
Коммит
b56116bf15
|
@ -0,0 +1,7 @@
|
|||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
.DS_Store
|
||||
.idea
|
|
@ -0,0 +1,101 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using iTunesSearch.Library;
|
||||
|
||||
namespace Avalonia.MusicStore.Backend
|
||||
{
|
||||
public class Album
|
||||
{
|
||||
private static HttpClient s_httpClient = new();
|
||||
private static iTunesSearchManager s_SearchManager = new();
|
||||
|
||||
public Album(string artist, string title, string coverUrl)
|
||||
{
|
||||
Artist = artist;
|
||||
Title = title;
|
||||
CoverUrl = coverUrl;
|
||||
}
|
||||
|
||||
public string Artist { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string CoverUrl { get; set; }
|
||||
|
||||
private string CachePath => $"./Cache/{Artist} - {Title}";
|
||||
|
||||
public async Task<Stream> LoadCoverBitmapAsync()
|
||||
{
|
||||
if (File.Exists(CachePath + ".bmp"))
|
||||
{
|
||||
return File.OpenRead(CachePath + ".bmp");
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = await s_httpClient.GetByteArrayAsync(CoverUrl);
|
||||
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SaveAsync()
|
||||
{
|
||||
if (!Directory.Exists("./Cache"))
|
||||
{
|
||||
Directory.CreateDirectory("./Cache");
|
||||
}
|
||||
|
||||
using (var fs = File.OpenWrite(CachePath))
|
||||
{
|
||||
await SaveToStreamAsync(this, fs);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream SaveCoverBitmapSteam()
|
||||
{
|
||||
return File.OpenWrite(CachePath + ".bmp");
|
||||
}
|
||||
|
||||
private static async Task SaveToStreamAsync(Album data, Stream stream)
|
||||
{
|
||||
await JsonSerializer.SerializeAsync(stream, data).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<Album> LoadFromStream(Stream stream)
|
||||
{
|
||||
return (await JsonSerializer.DeserializeAsync<Album>(stream).ConfigureAwait(false))!;
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<Album>> LoadCachedAsync()
|
||||
{
|
||||
if (!Directory.Exists("./Cache"))
|
||||
{
|
||||
Directory.CreateDirectory("./Cache");
|
||||
}
|
||||
|
||||
var results = new List<Album>();
|
||||
|
||||
foreach (var file in Directory.EnumerateFiles("./Cache"))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(new DirectoryInfo(file).Extension)) continue;
|
||||
|
||||
await using var fs = File.OpenRead(file);
|
||||
results.Add(await Album.LoadFromStream(fs).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<Album>> SearchAsync(string searchTerm)
|
||||
{
|
||||
var query = await s_SearchManager.GetAlbumsAsync(searchTerm).ConfigureAwait(false);
|
||||
|
||||
return query.Albums.Select(x =>
|
||||
new Album(x.ArtistName, x.CollectionName, x.ArtworkUrl100.Replace("100x100bb", "600x600bb")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="iTunesSearch" Version="1.0.44" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MusicStore", "Avalonia.MusicStore\Avalonia.MusicStore.csproj", "{EE95FC68-9062-4CC2-8E9E-9F9B846E07C1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MusicStore.Backend", "Avalonia.MusicStore.Backend\Avalonia.MusicStore.Backend.csproj", "{6F986AEB-CA11-4E42-ACCF-CA3D1681B121}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EE95FC68-9062-4CC2-8E9E-9F9B846E07C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EE95FC68-9062-4CC2-8E9E-9F9B846E07C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE95FC68-9062-4CC2-8E9E-9F9B846E07C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE95FC68-9062-4CC2-8E9E-9F9B846E07C1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6F986AEB-CA11-4E42-ACCF-CA3D1681B121}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6F986AEB-CA11-4E42-ACCF-CA3D1681B121}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6F986AEB-CA11-4E42-ACCF-CA3D1681B121}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6F986AEB-CA11-4E42-ACCF-CA3D1681B121}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,8 @@
|
|||
.idea/
|
||||
.vscode/
|
||||
.vs/
|
||||
|
||||
bin/
|
||||
obj/
|
||||
|
||||
*.user
|
|
@ -0,0 +1,13 @@
|
|||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Avalonia.MusicStore"
|
||||
x:Class="Avalonia.MusicStore.App">
|
||||
<Application.DataTemplates>
|
||||
<local:ViewLocator/>
|
||||
</Application.DataTemplates>
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme Mode="Dark"/>
|
||||
<StyleInclude Source="avares://Avalonia.MusicStore/Icons.axaml" />
|
||||
</Application.Styles>
|
||||
</Application>
|
|
@ -0,0 +1,29 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.MusicStore.ViewModels;
|
||||
using Avalonia.MusicStore.Views;
|
||||
|
||||
namespace Avalonia.MusicStore
|
||||
{
|
||||
public class App : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new MainWindowViewModel(),
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
}
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 172 KiB |
|
@ -0,0 +1,19 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.0" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.0" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Avalonia.MusicStore.Backend\Avalonia.MusicStore.Backend.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,20 @@
|
|||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Avalonia.MusicStore
|
||||
{
|
||||
class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.LogToTrace()
|
||||
.UseReactiveUI();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.MusicStore.ViewModels;
|
||||
|
||||
namespace Avalonia.MusicStore
|
||||
{
|
||||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
public bool SupportsRecycling => false;
|
||||
|
||||
public IControl Build(object data)
|
||||
{
|
||||
var name = data.GetType().FullName!.Replace("ViewModel", "View");
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control) Activator.CreateInstance(type)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TextBlock {Text = "Not Found: " + name};
|
||||
}
|
||||
}
|
||||
|
||||
public bool Match(object data)
|
||||
{
|
||||
return data is ViewModelBase;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.MusicStore.Backend;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Avalonia.MusicStore.ViewModels
|
||||
{
|
||||
public class AlbumViewModel : ViewModelBase
|
||||
{
|
||||
private Bitmap? _cover;
|
||||
private readonly Album _album;
|
||||
|
||||
public AlbumViewModel(Album album)
|
||||
{
|
||||
_album = album;
|
||||
}
|
||||
|
||||
public string Artist => _album.Artist;
|
||||
|
||||
public string Title => _album.Title;
|
||||
|
||||
public Bitmap? Cover
|
||||
{
|
||||
get => _cover;
|
||||
private set => this.RaiseAndSetIfChanged(ref _cover, value);
|
||||
}
|
||||
|
||||
public async Task LoadCover()
|
||||
{
|
||||
await using (var imageStream =await _album.LoadCoverBitmapAsync())
|
||||
{
|
||||
Cover = await Task.Run(() => Bitmap.DecodeToWidth(imageStream, 400));
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<AlbumViewModel>> LoadCached()
|
||||
{
|
||||
return (await Album.LoadCachedAsync()).Select(x => new AlbumViewModel(x));
|
||||
}
|
||||
|
||||
public async Task SaveToDiskAsync()
|
||||
{
|
||||
await _album.SaveAsync();
|
||||
|
||||
if (Cover != null)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
using (var fs = _album.SaveCoverBitmapSteam())
|
||||
{
|
||||
Cover.Save(fs);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Avalonia.MusicStore.ViewModels
|
||||
{
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
ShowDialog = new Interaction<MusicStoreViewModel, AlbumViewModel?>();
|
||||
|
||||
BuyMusicCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
var store = new MusicStoreViewModel();
|
||||
|
||||
var result = await ShowDialog.Handle(store);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
Albums.Add(result);
|
||||
}
|
||||
});
|
||||
|
||||
RxApp.MainThreadScheduler.Schedule(LoadAlbums);
|
||||
}
|
||||
|
||||
private async void LoadAlbums()
|
||||
{
|
||||
var albums = await AlbumViewModel.LoadCached();
|
||||
|
||||
foreach (var album in albums)
|
||||
{
|
||||
Albums.Add(album);
|
||||
}
|
||||
|
||||
LoadCovers();
|
||||
}
|
||||
|
||||
private async void LoadCovers()
|
||||
{
|
||||
foreach (var album in Albums.ToList())
|
||||
{
|
||||
await album.LoadCover();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<AlbumViewModel> Albums { get; } = new();
|
||||
|
||||
public ICommand BuyMusicCommand { get; }
|
||||
|
||||
public Interaction<MusicStoreViewModel, AlbumViewModel?> ShowDialog { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using Avalonia.MusicStore.Backend;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Avalonia.MusicStore.ViewModels
|
||||
{
|
||||
public class MusicStoreViewModel : ViewModelBase
|
||||
{
|
||||
private string? _searchText;
|
||||
private bool _isBusy;
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private AlbumViewModel? _selectedAlbum;
|
||||
|
||||
public MusicStoreViewModel()
|
||||
{
|
||||
this.WhenAnyValue(x => x.SearchText)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Throttle(TimeSpan.FromMilliseconds(400))
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(DoSearch!);
|
||||
|
||||
BuyMusicCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
if (SelectedAlbum is { })
|
||||
{
|
||||
await SelectedAlbum.SaveToDiskAsync();
|
||||
return SelectedAlbum;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public string? SearchText
|
||||
{
|
||||
get => _searchText;
|
||||
set => this.RaiseAndSetIfChanged(ref _searchText, value);
|
||||
}
|
||||
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set => this.RaiseAndSetIfChanged(ref _isBusy, value);
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, AlbumViewModel?> BuyMusicCommand { get; }
|
||||
|
||||
public ObservableCollection<AlbumViewModel> SearchResults { get; } = new();
|
||||
|
||||
public AlbumViewModel? SelectedAlbum
|
||||
{
|
||||
get => _selectedAlbum;
|
||||
set => this.RaiseAndSetIfChanged(ref _selectedAlbum, value);
|
||||
}
|
||||
|
||||
private async void DoSearch(string s)
|
||||
{
|
||||
IsBusy = true;
|
||||
SearchResults.Clear();
|
||||
|
||||
_cancellationTokenSource?.Cancel();
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var albums = await Album.SearchAsync(s);
|
||||
|
||||
foreach (var album in albums)
|
||||
{
|
||||
var vm = new AlbumViewModel(album);
|
||||
|
||||
SearchResults.Add(vm);
|
||||
}
|
||||
|
||||
if (!_cancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
LoadCovers(_cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
private async void LoadCovers(CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var album in SearchResults.ToList())
|
||||
{
|
||||
await album.LoadCover();
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Avalonia.MusicStore.ViewModels
|
||||
{
|
||||
public class ViewModelBase : ReactiveObject
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<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"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Avalonia.MusicStore.Views.AlbumView">
|
||||
<StackPanel Spacing="5" Width="200">
|
||||
<Border CornerRadius="10" ClipToBounds="True">
|
||||
<Panel Background="#7FFF22DD">
|
||||
<Image Width="200" Stretch="Uniform" Source="{Binding Cover}" />
|
||||
<Panel Height="200" IsVisible="{Binding Cover, Converter={x:Static ObjectConverters.IsNull}}">
|
||||
<PathIcon Height="75" Width="75" Data="{StaticResource music_regular}" />
|
||||
</Panel>
|
||||
</Panel>
|
||||
</Border>
|
||||
<TextBlock Text="{Binding Title}" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="{Binding Artist}" HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
|
@ -0,0 +1,19 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Avalonia.MusicStore.Views
|
||||
{
|
||||
public class AlbumView : UserControl
|
||||
{
|
||||
public AlbumView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:Avalonia.MusicStore.ViewModels"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Avalonia.MusicStore.Views.MainWindow"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="Transparent"
|
||||
TransparencyLevelHint="AcrylicBlur"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
Icon="/Assets/avalonia-logo.ico"
|
||||
Title="Avalonia.MusicStore">
|
||||
|
||||
<Design.DataContext>
|
||||
<vm:MainWindowViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Panel>
|
||||
<ExperimentalAcrylicBorder IsHitTestVisible="False">
|
||||
<ExperimentalAcrylicBorder.Material>
|
||||
<ExperimentalAcrylicMaterial
|
||||
BackgroundSource="Digger"
|
||||
TintColor="Black"
|
||||
TintOpacity="1"
|
||||
MaterialOpacity="0.65" />
|
||||
</ExperimentalAcrylicBorder.Material>
|
||||
</ExperimentalAcrylicBorder>
|
||||
|
||||
<Panel Margin="40">
|
||||
<Button Command="{Binding BuyMusicCommand}" HorizontalAlignment="Right" VerticalAlignment="Top">
|
||||
<PathIcon Data="{StaticResource store_microsoft_regular}" />
|
||||
</Button>
|
||||
|
||||
<ItemsControl Items="{Binding Albums}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
</Panel>
|
||||
|
||||
</Panel>
|
||||
</Window>
|
|
@ -0,0 +1,37 @@
|
|||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.MusicStore.ViewModels;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Avalonia.MusicStore.Views
|
||||
{
|
||||
public class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
|
||||
this.WhenActivated(d => d(ViewModel.ShowDialog.RegisterHandler(DoShowDialogAsync)));
|
||||
}
|
||||
|
||||
private async Task DoShowDialogAsync(InteractionContext<MusicStoreViewModel, AlbumViewModel?> interaction)
|
||||
{
|
||||
var dialog = new MusicStoreWindow();
|
||||
dialog.DataContext = interaction.Input;
|
||||
|
||||
var result = await dialog.ShowDialog<AlbumViewModel?>(this);
|
||||
interaction.SetOutput(result);
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<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"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Avalonia.MusicStore.Views.MusicStoreView">
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Top">
|
||||
<TextBox Text="{Binding SearchText}" Watermark="Search for Albums...." />
|
||||
<ProgressBar IsIndeterminate="True" IsVisible="{Binding IsBusy}" />
|
||||
</StackPanel>
|
||||
<Button Command="{Binding BuyMusicCommand}" Content="Buy Album" DockPanel.Dock="Bottom" HorizontalAlignment="Center" />
|
||||
<ListBox Items="{Binding SearchResults}" SelectedItem="{Binding SelectedAlbum}" Background="Transparent" Margin="0 20">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</UserControl>
|
|
@ -0,0 +1,19 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Avalonia.MusicStore.Views
|
||||
{
|
||||
public class MusicStoreView : UserControl
|
||||
{
|
||||
public MusicStoreView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<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"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Avalonia.MusicStore.Views.MusicStoreWindow"
|
||||
xmlns:local="using:Avalonia.MusicStore.Views"
|
||||
Width="1000" Height="550" WindowStartupLocation="CenterOwner"
|
||||
Background="Transparent"
|
||||
TransparencyLevelHint="AcrylicBlur"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
Title="MusicStoreWindow">
|
||||
<Panel>
|
||||
<ExperimentalAcrylicBorder IsHitTestVisible="False">
|
||||
<ExperimentalAcrylicBorder.Material>
|
||||
<ExperimentalAcrylicMaterial
|
||||
BackgroundSource="Digger"
|
||||
TintColor="Black"
|
||||
TintOpacity="1"
|
||||
MaterialOpacity="0.65" />
|
||||
</ExperimentalAcrylicBorder.Material>
|
||||
</ExperimentalAcrylicBorder>
|
||||
|
||||
<Panel Margin="40">
|
||||
<local:MusicStoreView />
|
||||
</Panel>
|
||||
</Panel>
|
||||
</Window>
|
|
@ -0,0 +1,26 @@
|
|||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.MusicStore.ViewModels;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
|
||||
namespace Avalonia.MusicStore.Views
|
||||
{
|
||||
public class MusicStoreWindow : ReactiveWindow<MusicStoreViewModel>
|
||||
{
|
||||
public MusicStoreWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
|
||||
this.WhenActivated(d => d(ViewModel.BuyMusicCommand.Subscribe(Close)));
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче