Use DataGridMyRatingColumn for both user and product ratings.
This commit is contained in:
parent
b823f5fa00
commit
fb18940a5c
@ -2,14 +2,24 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using DataLayer;
|
||||
using LibationAvalonia.ViewModels;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
|
||||
namespace LibationAvalonia.Controls
|
||||
{
|
||||
public class StarStringConverter : Avalonia.Data.Converters.IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
=> value is Rating rating ? rating.ToStarString() : string.Empty;
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
=> throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public class DataGridMyRatingColumn : DataGridBoundColumn
|
||||
{
|
||||
[Avalonia.Data.AssignBinding]
|
||||
public Avalonia.Data.IBinding BackgroundBinding { get; set; }
|
||||
private static Rating DefaultRating => new Rating(0, 0, 0);
|
||||
public DataGridMyRatingColumn()
|
||||
{
|
||||
@ -24,29 +34,20 @@ namespace LibationAvalonia.Controls
|
||||
IsEditingMode = false
|
||||
};
|
||||
|
||||
ToolTip.SetTip(myRatingElement, "Click to change ratings");
|
||||
cell?.AttachContextMenu();
|
||||
|
||||
if (!IsReadOnly)
|
||||
ToolTip.SetTip(myRatingElement, "Click to change ratings");
|
||||
|
||||
if (Binding != null)
|
||||
{
|
||||
myRatingElement.Bind(BindingTarget, Binding);
|
||||
}
|
||||
|
||||
void setControlBackground(object dataContext)
|
||||
if (BackgroundBinding != null)
|
||||
{
|
||||
if (dataContext is GridEntry ge)
|
||||
myRatingElement.Background = ge.BackgroundBrush;
|
||||
myRatingElement.Bind(MyRatingCellEditor.BackgroundProperty, BackgroundBinding);
|
||||
}
|
||||
|
||||
setControlBackground(cell?.DataContext);
|
||||
|
||||
var subscriber =
|
||||
cell
|
||||
?.ObservableForProperty(g => g.DataContext)
|
||||
?.Subscribe(ctx => setControlBackground(ctx?.Value));
|
||||
|
||||
myRatingElement.DetachedFromVisualTree += (_, _) => subscriber?.Dispose();
|
||||
|
||||
return myRatingElement;
|
||||
}
|
||||
|
||||
@ -57,6 +58,10 @@ namespace LibationAvalonia.Controls
|
||||
Name = "CellMyRatingEditor",
|
||||
IsEditingMode = true
|
||||
};
|
||||
if (BackgroundBinding != null)
|
||||
{
|
||||
myRatingElement.Bind(MyRatingCellEditor.BackgroundProperty, BackgroundBinding);
|
||||
}
|
||||
|
||||
return myRatingElement;
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
</Grid.Styles>
|
||||
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Name="tblockOverall" Text="Overall:" />
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" Name="tblockPerform" Text="Perform:" />
|
||||
<TextBlock Grid.Column="0" Grid.Row="1" Name="tblockPerform" Text="Perform: " />
|
||||
<TextBlock Grid.Column="0" Grid.Row="2" Name="tblockStory" Text="Story:" />
|
||||
|
||||
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="0">
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using DataLayer;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibationAvalonia.Controls
|
||||
@ -9,6 +11,7 @@ namespace LibationAvalonia.Controls
|
||||
{
|
||||
private const string SOLID_STAR = "★";
|
||||
private const string HOLLOW_STAR = "☆";
|
||||
private const string HALF_STAR = "½";
|
||||
|
||||
public static readonly StyledProperty<Rating> RatingProperty =
|
||||
AvaloniaProperty.Register<MyRatingCellEditor, Rating>(nameof(Rating));
|
||||
@ -19,39 +22,41 @@ namespace LibationAvalonia.Controls
|
||||
public MyRatingCellEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var subscriber = this.ObservableForProperty(p => p.Rating).Subscribe(o => DisplayStarRating(o.Value ?? new Rating(0, 0, 0)));
|
||||
Unloaded += (_, _) => subscriber.Dispose();
|
||||
|
||||
if (Design.IsDesignMode)
|
||||
Rating = new Rating(5, 4, 3);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
if (change.Property.Name == nameof(Rating) && Rating is not null)
|
||||
private void DisplayStarRating(Rating rating)
|
||||
{
|
||||
var blankValue = IsEditingMode ? HOLLOW_STAR : string.Empty;
|
||||
|
||||
int rating = 0;
|
||||
string getStar(float score, int starIndex)
|
||||
=> Math.Floor(score) > starIndex ? SOLID_STAR
|
||||
: score < starIndex ? blankValue
|
||||
: score - starIndex < 0.25 ? blankValue
|
||||
: score - starIndex > 0.75 ? SOLID_STAR
|
||||
: HALF_STAR;
|
||||
|
||||
int starIndex = 0;
|
||||
foreach (TextBlock star in panelOverall.Children)
|
||||
star.Tag = star.Text = Rating.OverallRating > rating++ ? SOLID_STAR : blankValue;
|
||||
star.Tag = star.Text = getStar(rating.OverallRating, starIndex++);
|
||||
|
||||
rating = 0;
|
||||
starIndex = 0;
|
||||
foreach (TextBlock star in panelPerform.Children)
|
||||
star.Tag = star.Text = Rating.PerformanceRating > rating++ ? SOLID_STAR : blankValue;
|
||||
star.Tag = star.Text = getStar(rating.PerformanceRating, starIndex++);
|
||||
|
||||
rating = 0;
|
||||
starIndex = 0;
|
||||
foreach (TextBlock star in panelStory.Children)
|
||||
star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue;
|
||||
star.Tag = star.Text = getStar(rating.StoryRating, starIndex++);
|
||||
|
||||
SetVisible();
|
||||
}
|
||||
base.OnPropertyChanged(change);
|
||||
}
|
||||
|
||||
private void SetVisible()
|
||||
{
|
||||
ratingsGrid.IsEnabled = IsEditingMode;
|
||||
tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || Rating?.OverallRating > 0;
|
||||
tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || Rating?.PerformanceRating > 0;
|
||||
tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || Rating?.StoryRating > 0;
|
||||
tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || rating.OverallRating > 0;
|
||||
tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || rating.PerformanceRating > 0;
|
||||
tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || rating.StoryRating > 0;
|
||||
}
|
||||
|
||||
public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e)
|
||||
|
||||
@ -44,8 +44,7 @@ namespace LibationAvalonia.ViewModels
|
||||
public string Category { get; protected set; }
|
||||
public string Misc { get; protected set; }
|
||||
public string Description { get; protected set; }
|
||||
public string ProductRating { get; protected set; }
|
||||
public string MyRatingString => MyRating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||
public Rating ProductRating { get; protected set; }
|
||||
protected Rating _myRating;
|
||||
public Rating MyRating
|
||||
{
|
||||
@ -68,7 +67,6 @@ namespace LibationAvalonia.ViewModels
|
||||
public abstract bool IsSeries { get; }
|
||||
public abstract bool IsEpisode { get; }
|
||||
public abstract bool IsBook { get; }
|
||||
public abstract double Opacity { get; }
|
||||
public IBrush BackgroundBrush => IsEpisode ? App.SeriesEntryGridBackgroundBrush : Brushes.Transparent;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -53,7 +53,6 @@ namespace LibationAvalonia.ViewModels
|
||||
public override bool IsSeries => false;
|
||||
public override bool IsEpisode => Parent is not null;
|
||||
public override bool IsBook => Parent is null;
|
||||
public override double Opacity => Book.UserDefinedItem.Tags.ToLower().Contains("hidden") ? 0.4 : 1;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -69,7 +68,7 @@ namespace LibationAvalonia.ViewModels
|
||||
//the reference doesn't change. Clone the rating so that it updates within Avalonia properly.
|
||||
_myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating);
|
||||
PurchaseDate = libraryBook.DateAdded.ToString("d");
|
||||
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||
ProductRating = Book.Rating ?? new Rating(0, 0, 0);
|
||||
Authors = Book.AuthorNames();
|
||||
Narrators = Book.NarratorNames();
|
||||
Category = string.Join(" > ", Book.CategoriesNames());
|
||||
@ -102,7 +101,6 @@ namespace LibationAvalonia.ViewModels
|
||||
case nameof(udi.Tags):
|
||||
Book.UserDefinedItem.Tags = udi.Tags;
|
||||
this.RaisePropertyChanged(nameof(BookTags));
|
||||
this.RaisePropertyChanged(nameof(Opacity));
|
||||
break;
|
||||
case nameof(udi.BookStatus):
|
||||
Book.UserDefinedItem.BookStatus = udi.BookStatus;
|
||||
|
||||
@ -49,7 +49,6 @@ namespace LibationAvalonia.ViewModels
|
||||
public override bool IsSeries => true;
|
||||
public override bool IsEpisode => false;
|
||||
public override bool IsBook => false;
|
||||
public override double Opacity => 1;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -71,7 +70,7 @@ namespace LibationAvalonia.ViewModels
|
||||
//Ratings are changed using Update(), which is a problem for Avalonia data bindings because
|
||||
//the reference doesn't change. Clone the rating so that it updates within Avalonia properly.
|
||||
_myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating);
|
||||
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
||||
ProductRating = Book.Rating ?? new Rating(0, 0, 0);
|
||||
Authors = Book.AuthorNames();
|
||||
Narrators = Book.NarratorNames();
|
||||
Category = string.Join(" > ", Book.CategoriesNames());
|
||||
|
||||
@ -19,10 +19,12 @@
|
||||
CanUserReorderColumns="True">
|
||||
|
||||
<DataGrid.Styles>
|
||||
<Style Selector="DataGridCell > Panel">
|
||||
<Setter Property="Margin" Value="0,1,0,1"/>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="Height" Value="80"/>
|
||||
</Style>
|
||||
<Style Selector="DataGridCell > Panel">
|
||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||
</Style>
|
||||
<Style Selector="DataGridCell > Panel > TextBlock">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
@ -31,6 +33,10 @@
|
||||
</Style>
|
||||
</DataGrid.Styles>
|
||||
|
||||
<DataGrid.Resources>
|
||||
<controls:StarStringConverter x:Key="starStringConverter" />
|
||||
</DataGrid.Resources>
|
||||
|
||||
<DataGrid.Columns>
|
||||
|
||||
<DataGridTemplateColumn
|
||||
@ -73,7 +79,7 @@
|
||||
<controls:DataGridTemplateColumnExt MinWidth="150" Width="2*" Header="Title" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding Title}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
@ -83,7 +89,7 @@
|
||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Authors" CanUserSort="True" SortMemberPath="Authors" ClipboardContentBinding="{Binding Authors}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding Authors}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
@ -93,7 +99,7 @@
|
||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Narrators" CanUserSort="True" SortMemberPath="Narrators" ClipboardContentBinding="{Binding Narrators}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding Narrators}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
@ -103,7 +109,7 @@
|
||||
<controls:DataGridTemplateColumnExt Width="90" Header="Length" CanUserSort="True" SortMemberPath="Length" ClipboardContentBinding="{Binding Length}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding Length}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
@ -113,7 +119,7 @@
|
||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Series" CanUserSort="True" SortMemberPath="Series" ClipboardContentBinding="{Binding Series}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding Series}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
@ -123,7 +129,7 @@
|
||||
<controls:DataGridTemplateColumnExt MinWidth="100" Width="1*" Header="Description" CanUserSort="True" SortMemberPath="Description" ClipboardContentBinding="{Binding LongDescription}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
||||
<Panel Background="{Binding BackgroundBrush}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
||||
<TextBlock Text="{Binding Description}" FontSize="11" VerticalAlignment="Top" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
@ -133,39 +139,45 @@
|
||||
<controls:DataGridTemplateColumnExt Width="100" Header="Category" CanUserSort="True" SortMemberPath="Category" ClipboardContentBinding="{Binding Category}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding Category}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</controls:DataGridTemplateColumnExt>
|
||||
|
||||
<controls:DataGridTemplateColumnExt Width="115" Header="Product
Rating" CanUserSort="True" SortMemberPath="ProductRating" ClipboardContentBinding="{Binding ProductRating}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<TextBlock Text="{Binding ProductRating}" TextWrapping="NoWrap" FontSize="11" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</controls:DataGridTemplateColumnExt>
|
||||
<controls:DataGridMyRatingColumn
|
||||
Header="Product
Rating"
|
||||
IsReadOnly="true"
|
||||
Width="115"
|
||||
SortMemberPath="ProductRating" CanUserSort="True"
|
||||
BackgroundBinding="{Binding BackgroundBrush}"
|
||||
ClipboardContentBinding="{Binding ProductRating, Converter={StaticResource starStringConverter}}"
|
||||
Binding="{Binding ProductRating}" />
|
||||
|
||||
<controls:DataGridTemplateColumnExt Width="90" Header="Purchase
Date" CanUserSort="True" SortMemberPath="PurchaseDate" ClipboardContentBinding="{Binding PurchaseDate}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding PurchaseDate}" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</controls:DataGridTemplateColumnExt>
|
||||
|
||||
<controls:DataGridMyRatingColumn IsReadOnly="false" Width="115" Header="My Rating" CanUserSort="True" SortMemberPath="MyRating" ClipboardContentBinding="{Binding MyRatingString}" Binding="{Binding MyRating, Mode=TwoWay}" />
|
||||
<controls:DataGridMyRatingColumn
|
||||
Header="My Rating"
|
||||
IsReadOnly="false"
|
||||
Width="115"
|
||||
SortMemberPath="MyRating" CanUserSort="True"
|
||||
BackgroundBinding="{Binding BackgroundBrush}"
|
||||
ClipboardContentBinding="{Binding MyRating, Converter={StaticResource starStringConverter}}"
|
||||
Binding="{Binding MyRating, Mode=TwoWay}" />
|
||||
|
||||
<controls:DataGridTemplateColumnExt Width="135" Header="Misc" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
||||
<Panel Background="{Binding BackgroundBrush}">
|
||||
<TextBlock Text="{Binding Misc}" TextWrapping="WrapWithOverflow" FontSize="10" />
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
@ -187,6 +199,5 @@
|
||||
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@ -273,13 +273,13 @@ namespace LibationAvalonia.Views
|
||||
|
||||
#region Button Click Handlers
|
||||
|
||||
public void LiberateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
|
||||
public async void LiberateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
|
||||
{
|
||||
var button = args.Source as Button;
|
||||
|
||||
if (button.DataContext is SeriesEntry sEntry)
|
||||
{
|
||||
_viewModel.ToggleSeriesExpanded(sEntry);
|
||||
await _viewModel.ToggleSeriesExpanded(sEntry);
|
||||
|
||||
//Expanding and collapsing reset the list, which will cause focus to shift
|
||||
//to the topright cell. Reset focus onto the clicked button's cell.
|
||||
|
||||
@ -208,11 +208,7 @@
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TextBox releaseNotesTbox;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.LinkLabel linkLabel3;
|
||||
private System.Windows.Forms.LinkLabel linkLabel2;
|
||||
private System.Windows.Forms.LinkLabel packageDlLink;
|
||||
private System.Windows.Forms.Button dontRemindBtn;
|
||||
private System.Windows.Forms.Button yesBtn;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user