Merge pull request #603 from Mbucari/master

New searches, new linux release, new Avalonia build
This commit is contained in:
rmcrackan 2023-05-19 14:23:05 -04:00 committed by GitHub
commit 2c91de1b3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 605 additions and 831 deletions

View File

@ -15,6 +15,21 @@ on:
description: 'Skip running unit tests' description: 'Skip running unit tests'
required: false required: false
default: true default: true
runs_on:
type: string
description: 'The GitHub hosted runner to use'
required: true
OS:
type: string
description: >
The operating system targeted by the build.
There must be a corresponding Bundle_$OS.sh script file in ./Scripts
required: true
architecture:
type: string
description: 'CPU architecture targeted by the build.'
required: true
env: env:
DOTNET_CONFIGURATION: 'Release' DOTNET_CONFIGURATION: 'Release'
@ -23,11 +38,8 @@ env:
jobs: jobs:
build: build:
runs-on: ${{ matrix.os }} name: '${{ inputs.OS }}-${{ inputs.architecture }}'
strategy: runs-on: ${{ inputs.runs_on }}
matrix:
os: [ubuntu-latest, macos-latest]
arch: [x64, arm64]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup .NET - name: Setup .NET
@ -48,6 +60,7 @@ jobs:
version="$(grep -Eio -m 1 '<Version>.*</Version>' ./Source/AppScaffolding/AppScaffolding.csproj | sed -r 's/<\/?Version>//g')" version="$(grep -Eio -m 1 '<Version>.*</Version>' ./Source/AppScaffolding/AppScaffolding.csproj | sed -r 's/<\/?Version>//g')"
fi fi
echo "version=${version}" >> "${GITHUB_OUTPUT}" echo "version=${version}" >> "${GITHUB_OUTPUT}"
- name: Unit test - name: Unit test
if: ${{ inputs.run_unit_tests }} if: ${{ inputs.run_unit_tests }}
working-directory: ./Source working-directory: ./Source
@ -56,52 +69,64 @@ jobs:
- name: Publish - name: Publish
id: publish id: publish
working-directory: ./Source working-directory: ./Source
run: | run: |
os=${{ matrix.os }} if [[ "${{ inputs.OS }}" == "MacOS" ]]
target_os="$(echo ${os/-latest/} | sed 's/ubuntu/linux/')" then
display_os="$(echo ${target_os/macos/macOS} | sed 's/linux/Linux/')" display_os="macOS"
RUNTIME_ID="osx-${{ inputs.architecture }}"
else
display_os="Linux"
RUNTIME_ID="linux-${{ inputs.architecture }}"
fi
OUTPUT="bin/Publish/${display_os}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }}"
echo "display_os=${display_os}" >> $GITHUB_OUTPUT echo "display_os=${display_os}" >> $GITHUB_OUTPUT
RUNTIME_IDENTIFIER="$(echo ${target_os/macos/osx})-${{ matrix.arch }}" echo "Runtime Identifier: $RUNTIME_ID"
echo "$RUNTIME_IDENTIFIER" echo "Output Directory: $OUTPUT"
dotnet publish \ dotnet publish \
LibationAvalonia/LibationAvalonia.csproj \ LibationAvalonia/LibationAvalonia.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output $OUTPUT \
-p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml -p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \ dotnet publish \
LoadByOS/${display_os}ConfigApp/${display_os}ConfigApp.csproj \ LoadByOS/${display_os}ConfigApp/${display_os}ConfigApp.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output $OUTPUT \
-p:PublishProfile=LoadByOS/Properties/${display_os}ConfigApp/PublishProfiles/${display_os}Profile.pubxml -p:PublishProfile=LoadByOS/Properties/${display_os}ConfigApp/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \ dotnet publish \
LibationCli/LibationCli.csproj \ LibationCli/LibationCli.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output $OUTPUT \
-p:PublishProfile=LibationCli/Properties/PublishProfiles/${display_os}Profile.pubxml -p:PublishProfile=LibationCli/Properties/PublishProfiles/${display_os}Profile.pubxml
dotnet publish \ dotnet publish \
HangoverAvalonia/HangoverAvalonia.csproj \ HangoverAvalonia/HangoverAvalonia.csproj \
--runtime "$RUNTIME_IDENTIFIER" \ --runtime $RUNTIME_ID \
--configuration ${{ env.DOTNET_CONFIGURATION }} \ --configuration ${{ env.DOTNET_CONFIGURATION }} \
--output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ --output $OUTPUT \
-p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml -p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml
- name: Build bundle - name: Build bundle
id: bundle id: bundle
working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }}
run: | run: |
BUNDLE_DIR=$(pwd) BUNDLE_DIR=$(pwd)
echo "Bundle dir: ${BUNDLE_DIR}" echo "Bundle dir: ${BUNDLE_DIR}"
cd .. cd ..
SCRIPT=../../../Scripts/Bundle_${{ steps.publish.outputs.display_os }}.sh SCRIPT=../../../Scripts/Bundle_${{ inputs.OS }}.sh
chmod +rx ${SCRIPT} chmod +rx ${SCRIPT}
${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ matrix.arch }}" ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ inputs.architecture }}"
artifact=$(ls ./bundle) artifact=$(ls ./bundle)
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}" echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
- name: Publish bundle - name: Publish bundle
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: ${{ steps.bundle.outputs.artifact }} name: ${{ steps.bundle.outputs.artifact }}
path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }} path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }}
if-no-files-found: error if-no-files-found: error
retention-days: 7

View File

@ -22,6 +22,7 @@ env:
jobs: jobs:
build: build:
name: '${{ matrix.os }}-${{ matrix.release_name }}'
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
matrix: matrix:
@ -110,4 +111,4 @@ jobs:
name: ${{ steps.zip.outputs.artifact }}.zip name: ${{ steps.zip.outputs.artifact }}.zip
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip
if-no-files-found: error if-no-files-found: error
retention-days: 7

View File

@ -17,14 +17,34 @@ on:
default: true default: true
jobs: jobs:
windows: windows:
uses: ./.github/workflows/build-windows.yml uses: ./.github/workflows/build-windows.yml
with: with:
version_override: ${{ inputs.version_override }} version_override: ${{ inputs.version_override }}
run_unit_tests: ${{ inputs.run_unit_tests }} run_unit_tests: ${{ inputs.run_unit_tests }}
linux: linux:
strategy:
matrix:
OS: [Redhat, Debian]
architecture: [x64, arm64]
uses: ./.github/workflows/build-linux.yml uses: ./.github/workflows/build-linux.yml
with: with:
version_override: ${{ inputs.version_override }} version_override: ${{ inputs.version_override }}
runs_on: ubuntu-latest
OS: ${{ matrix.OS }}
architecture: ${{ matrix.architecture }}
run_unit_tests: ${{ inputs.run_unit_tests }}
macos:
strategy:
matrix:
architecture: [x64, arm64]
uses: ./.github/workflows/build-linux.yml
with:
version_override: ${{ inputs.version_override }}
runs_on: macos-latest
OS: MacOS
architecture: ${{ matrix.architecture }}
run_unit_tests: ${{ inputs.run_unit_tests }} run_unit_tests: ${{ inputs.run_unit_tests }}

View File

@ -1,8 +1,10 @@
{ {
"WindowsClassic": "Classic-Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-classic\\.zip", "WindowsClassic": "Classic-Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-classic\\.zip",
"WindowsAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-chardonnay\\.zip", "WindowsAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-chardonnay\\.zip",
"LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.deb", "LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.deb",
"MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-x64\\.tgz", "LinuxAvalonia_RPM": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.rpm",
"LinuxAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.deb", "MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-x64\\.tgz",
"MacOSAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-arm64\\.tgz" "LinuxAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.deb",
"LinuxAvalonia_Arm64_RPM": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.rpm",
"MacOSAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-arm64\\.tgz"
} }

140
Scripts/Bundle_Redhat.sh Normal file
View File

@ -0,0 +1,140 @@
#!/bin/bash
BIN_DIR=$1; shift
VERSION=$1; shift
ARCH=$1; shift
if [ -z "$BIN_DIR" ]
then
echo "This script must be called with a the Libation Linux bins directory as an argument."
exit
fi
if [ ! -d "$BIN_DIR" ]
then
echo "The directory \"$BIN_DIR\" does not exist."
exit
fi
if [ -z "$VERSION" ]
then
echo "This script must be called with the Libation version number as an argument."
exit
fi
if [ -z "$ARCH" ]
then
echo "This script must be called with the Libation cpu architecture as an argument."
exit
fi
contains() { case "$1" in *"$2"*) true ;; *) false ;; esac }
if ! contains "$BIN_DIR" "$ARCH"
then
echo "This script must be called with a Libation binaries for ${ARCH}."
exit
fi
BASEDIR=$(pwd)
delfiles=('libmp3lame.arm64.dylib' 'libmp3lame.x64.dylib' 'libmp3lame.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.arm64.dylib' 'ffmpegaac.x64.dylib' 'ffmpegaac.x64.dll' 'ffmpegaac.x86.dll' 'LinuxConfigApp' 'LinuxConfigApp.deps.json' 'LinuxConfigApp.runtimeconfig.json')
if [[ "$ARCH" == "x64" ]]
then
delfiles+=('libmp3lame.arm64.so' 'ffmpegaac.arm64.so')
ARCH_RPM="x86_64"
ARCH="amd64"
else
delfiles+=('libmp3lame.x64.so' 'ffmpegaac.x64.so')
ARCH_RPM="aarch64"
fi
notinstalled=('libcoreclrtraceptprovider.so' 'libation_glass.svg' 'Libation.desktop')
mkdir -p ~/rpmbuild/SPECS
mkdir ~/rpmbuild/BUILD
mkdir ~/rpmbuild/RPMS
echo "Name: libation
Version: ${VERSION}
Release: 1
Summary: Liberate your Audible Library
License: GPLv3+
URL: https://github.com/rmcrackan/Libation
Source0: https://github.com/rmcrackan/Libation
Requires: bash
%define __os_install_post %{nil}
%description
Liberate your Audible Library
%install
mkdir -p %{buildroot}%{_libdir}/%{name}
mkdir -p %{buildroot}%{_datadir}/icons/hicolor/scalable/apps
mkdir -p %{buildroot}%{_datadir}/applications
if test -f 'libcoreclrtraceptprovider.so'; then
rm 'libcoreclrtraceptprovider.so'
fi
touch appsettings.json
chmod 666 appsettings.json
install -m 666 libation_glass.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/libation.svg
install -m 666 Libation.desktop %{buildroot}%{_datadir}/applications/Libation.desktop
rm libation_glass.svg
rm Libation.desktop
install * %{buildroot}%{_libdir}/%{name}/
%post
ln -s %{_libdir}/%{name}/Libation %{_bindir}/libation
ln -s %{_libdir}/%{name}/Hangover %{_bindir}/hangover
ln -s %{_libdir}/%{name}/LibationCli %{_bindir}/libationcli
gtk-update-icon-cache -f %{_datadir}/icons/hicolor/
%postun
rm %{_bindir}/libation
rm %{_bindir}/hangover
rm %{_bindir}/libationcli
if ! grep -q 'fs.inotify.max_user_instances=524288' /etc/sysctl.conf; then
echo fs.inotify.max_user_instances=524288 | tee -a /etc/sysctl.conf && sysctl -p
fi
%files
%{_datadir}/icons/hicolor/scalable/apps/libation.svg
%{_datadir}/applications/Libation.desktop
%{_libdir}/%{name}/appsettings.json" >> ~/rpmbuild/SPECS/libation.spec
cd "$BIN_DIR"
for f in *; do
if [[ " ${delfiles[*]} " =~ " ${f} " ]]; then
echo "Deleting $f"
elif [[ ! " ${notinstalled[*]} " =~ " ${f} " ]]; then
echo "%{_libdir}/%{name}/${f}" >> ~/rpmbuild/SPECS/libation.spec
cp $f ~/rpmbuild/BUILD/
else
cp $f ~/rpmbuild/BUILD/
fi
done
cd ~/rpmbuild/SPECS/
rpmbuild -bb --target $ARCH_RPM libation.spec
cd $BASEDIR
RPM_FILE=$(ls ~/rpmbuild/RPMS/${ARCH_RPM})
mkdir bundle
mv ~/rpmbuild/RPMS/${ARCH_RPM}/$RPM_FILE "./bundle/Libation.${VERSION}-linux-chardonnay-${ARCH}.rpm"

View File

@ -330,7 +330,18 @@ namespace AppScaffolding
//Download the release index //Download the release index
var bts = await gitHubClient.Repository.Content.GetRawContent(ownerAccount, repoName, ".releaseindex.json"); var bts = await gitHubClient.Repository.Content.GetRawContent(ownerAccount, repoName, ".releaseindex.json");
var releaseIndex = JObject.Parse(System.Text.Encoding.ASCII.GetString(bts)); var releaseIndex = JObject.Parse(System.Text.Encoding.ASCII.GetString(bts));
var regexPattern = releaseIndex.Value<string>(ReleaseIdentifier.ToString());
string regexPattern;
try
{
regexPattern = releaseIndex.Value<string>(InteropFactory.Create().ReleaseIdString);
}
catch
{
regexPattern = releaseIndex.Value<string>(ReleaseIdentifier.ToString());
}
var regex = new System.Text.RegularExpressions.Regex(regexPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase); var regex = new System.Text.RegularExpressions.Regex(regexPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
//https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#get-the-latest-release //https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#get-the-latest-release

View File

@ -249,8 +249,26 @@ namespace AudibleUtilities
} }
} }
foreach (var child in children) int lastEpNum = -1, dupeCount = 0;
foreach (var child in children.OrderBy(i => i.EpisodeNumber).ThenBy(i => i.PublicationDateTime))
{ {
string sequence;
if (child.EpisodeNumber is null)
{
// This should properly be Single() not FirstOrDefault(), but FirstOrDefault is defensive for malformed data from audible
sequence = parent.Relationships.FirstOrDefault(r => r.Asin == child.Asin)?.Sort?.ToString() ?? "0";
}
else
{
//multipart episodes may have the same episode number
if (child.EpisodeNumber == lastEpNum)
dupeCount++;
else
lastEpNum = child.EpisodeNumber.Value;
sequence = (lastEpNum + dupeCount).ToString();
}
// use parent's 'DateAdded'. DateAdded is just a convenience prop for: PurchaseDate.UtcDateTime // use parent's 'DateAdded'. DateAdded is just a convenience prop for: PurchaseDate.UtcDateTime
child.PurchaseDate = parent.PurchaseDate; child.PurchaseDate = parent.PurchaseDate;
// parent is essentially a series // parent is essentially a series
@ -259,8 +277,7 @@ namespace AudibleUtilities
new Series new Series
{ {
Asin = parent.Asin, Asin = parent.Asin,
// This should properly be Single() not FirstOrDefault(), but FirstOrDefault is defensive for malformed data from audible Sequence = sequence,
Sequence = parent.Relationships.FirstOrDefault(r => r.Asin == child.Asin)?.Sort?.ToString() ?? "0",
Title = parent.TitleWithSubtitle Title = parent.TitleWithSubtitle
} }
}; };

View File

@ -24,7 +24,7 @@
<ItemsRepeater IsVisible="True" <ItemsRepeater IsVisible="True"
VerticalCacheLength="1.2" VerticalCacheLength="1.2"
HorizontalCacheLength="1" HorizontalCacheLength="1"
Items="{Binding CheckboxItems}" ItemsSource="{Binding CheckboxItems}"
ItemTemplate="{StaticResource elementFactory}" /> ItemTemplate="{StaticResource elementFactory}" />
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@ -66,13 +66,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview8" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.--> <!--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.0-preview6" /> <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview8" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" /> <ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />

View File

@ -53,15 +53,15 @@
</ResourceDictionary> </ResourceDictionary>
</ResourceDictionary.ThemeDictionaries> </ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</ResourceDictionary>
</Application.Resources> </Application.Resources>
<Application.Styles> <Application.Styles>
<FluentTheme /> <FluentTheme />
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentTheme.xaml"/> <StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentTheme.xaml"/>
<StyleInclude Source="/Assets/DataGridFluentTheme.xaml"/> <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
<StyleInclude Source="/Assets/LibationVectorIcons.xaml"/> <StyleInclude Source="/Assets/LibationVectorIcons.xaml"/>
<StyleInclude Source="/Assets/DataGridColumnHeader.xaml"/>
<Style Selector="TextBox[IsReadOnly=true]"> <Style Selector="TextBox[IsReadOnly=true]">
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}" /> <Setter Property="Background" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}" />

View File

@ -0,0 +1,104 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="using:Avalonia.Collections">
<Styles.Resources>
<!--
Based on Fluent template from v11.0.0-preview8
Modified sort arrow positioning to make more room for header text
-->
<ControlTheme x:Key="{x:Type DataGridColumnHeader}" TargetType="DataGridColumnHeader">
<Setter Property="Foreground" Value="{DynamicResource DataGridColumnHeaderForegroundBrush}" />
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderBackgroundBrush}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="SeparatorBrush" Value="{DynamicResource DataGridGridLinesBrush}" />
<Setter Property="Padding" Value="8,0,0,0" />
<Setter Property="FontSize" Value="12" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="HeaderBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid Name="PART_ColumnHeaderRoot" ColumnDefinitions="*,Auto">
<Grid Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Path Name="SortIcon"
IsVisible="False"
Grid.Column="1"
Height="12"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Fill="{TemplateBinding Foreground}"
Stretch="Uniform" />
</Grid>
<Rectangle Name="VerticalSeparator"
Grid.Column="1"
Width="1"
VerticalAlignment="Stretch"
Fill="{TemplateBinding SeparatorBrush}"
IsVisible="{TemplateBinding AreSeparatorsVisible}" />
<Grid x:Name="FocusVisual" IsHitTestVisible="False"
IsVisible="False">
<Rectangle x:Name="FocusVisualPrimary"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
StrokeThickness="2" />
<Rectangle x:Name="FocusVisualSecondary"
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
StrokeThickness="1" />
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:focus-visible /template/ Grid#FocusVisual">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^:pointerover /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderHoveredBackgroundBrush}" />
</Style>
<Style Selector="^:pressed /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderPressedBackgroundBrush}" />
</Style>
<Style Selector="^:dragIndicator">
<Setter Property="Opacity" Value="0.5" />
</Style>
<Style Selector="^:sortascending /template/ Path#SortIcon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{StaticResource DataGridSortIconAscendingPath}" />
</Style>
<Style Selector="^:sortdescending /template/ Path#SortIcon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{StaticResource DataGridSortIconDescendingPath}" />
</Style>
</ControlTheme>
</Styles.Resources>
</Styles>

View File

@ -1,588 +0,0 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="using:Avalonia.Collections">
<Styles.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridGridLinesBrush" Opacity="0.4" Color="{DynamicResource SystemBaseMediumLowColor}" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
</ResourceDictionary>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="DataGridColumnHeaderForegroundBrush" Color="{DynamicResource SystemBaseMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{DynamicResource SystemAltHighColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridColumnHeaderDraggedBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderBackgroundBrush" Color="{DynamicResource SystemChromeMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderPressedBackgroundBrush" Color="{DynamicResource SystemListMediumColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderForegroundBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowHoveredBackgroundColor" Color="{DynamicResource SystemListLowColor}" />
<SolidColorBrush x:Key="DataGridRowInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush" Color="{DynamicResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush" Color="{DynamicResource SystemAltMediumColor}" />
<SolidColorBrush x:Key="DataGridCellInvalidBrush" Color="{DynamicResource SystemErrorTextColor}" />
<SolidColorBrush x:Key="DataGridGridLinesBrush" Opacity="0.4" Color="{DynamicResource SystemBaseMediumLowColor}" />
<SolidColorBrush x:Key="DataGridDetailsPresenterBackgroundBrush" Color="{DynamicResource SystemChromeMediumLowColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<x:Double x:Key="ListAccentLowOpacity">0.6</x:Double>
<x:Double x:Key="ListAccentMediumOpacity">0.8</x:Double>
<StreamGeometry x:Key="DataGridSortIconDescendingPath">M1875 1011l-787 787v-1798h-128v1798l-787 -787l-90 90l941 941l941 -941z</StreamGeometry>
<StreamGeometry x:Key="DataGridSortIconAscendingPath">M1965 947l-941 -941l-941 941l90 90l787 -787v1798h128v-1798l787 787z</StreamGeometry>
<StreamGeometry x:Key="DataGridRowGroupHeaderIconClosedPath">M515 93l930 931l-930 931l90 90l1022 -1021l-1022 -1021z</StreamGeometry>
<StreamGeometry x:Key="DataGridRowGroupHeaderIconOpenedPath">M109 486 19 576 1024 1581 2029 576 1939 486 1024 1401z</StreamGeometry>
<StaticResource x:Key="DataGridRowBackgroundBrush" ResourceKey="SystemControlTransparentBrush" />
<SolidColorBrush x:Key="DataGridRowSelectedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedHoveredBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedHoveredBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedUnfocusedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedUnfocusedBackgroundOpacity" ResourceKey="ListAccentLowOpacity" />
<SolidColorBrush x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundBrush" Color="{DynamicResource SystemAccentColor}" />
<StaticResource x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundOpacity" ResourceKey="ListAccentMediumOpacity" />
<StaticResource x:Key="DataGridCellBackgroundBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="DataGridCurrencyVisualPrimaryBrush" ResourceKey="SystemControlTransparentBrush" />
<StaticResource x:Key="DataGridFillerColumnGridLinesBrush" ResourceKey="SystemControlTransparentBrush" />
<ControlTheme x:Key="DataGridCellTextBlockTheme" TargetType="TextBlock">
<Setter Property="Margin" Value="12,0,12,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</ControlTheme>
<ControlTheme x:Key="DataGridCellTextBoxTheme" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Style Selector="^ /template/ DataValidationErrors">
<Setter Property="Theme" Value="{StaticResource TooltipDataValidationErrors}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type DataGridCell}" TargetType="DataGridCell">
<Setter Property="Background" Value="{DynamicResource DataGridCellBackgroundBrush}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="FontSize" Value="15" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="CellBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid x:Name="PART_CellRoot" ColumnDefinitions="*,Auto">
<Rectangle x:Name="CurrencyVisual"
IsVisible="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCurrencyVisualPrimaryBrush}"
StrokeThickness="1" />
<Grid Grid.Column="0" x:Name="FocusVisual" IsHitTestVisible="False"
IsVisible="False">
<Rectangle HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
StrokeThickness="2" />
<Rectangle Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
StrokeThickness="1" />
</Grid>
<ContentPresenter Grid.Column="0" Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Foreground="{TemplateBinding Foreground}" />
<Rectangle Grid.Column="0" x:Name="InvalidVisualElement"
IsVisible="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellInvalidBrush}"
StrokeThickness="1" />
<Rectangle Name="PART_RightGridLine"
Grid.Column="1"
Width="1"
VerticalAlignment="Stretch"
Fill="{DynamicResource DataGridFillerColumnGridLinesBrush}" />
</Grid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:current /template/ Rectangle#CurrencyVisual">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^:focus /template/ Grid#FocusVisual">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^:invalid /template/ Rectangle#InvalidVisualElement">
<Setter Property="IsVisible" Value="True" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type DataGridColumnHeader}" TargetType="DataGridColumnHeader">
<Setter Property="Foreground" Value="{DynamicResource DataGridColumnHeaderForegroundBrush}" />
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderBackgroundBrush}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Focusable" Value="False" />
<Setter Property="SeparatorBrush" Value="{DynamicResource DataGridGridLinesBrush}" />
<Setter Property="Padding" Value="8,0,0,0" />
<Setter Property="FontSize" Value="12" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="HeaderBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid Name="PART_ColumnHeaderRoot" ColumnDefinitions="*,Auto">
<Grid Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Path Name="SortIcon"
IsVisible="False"
Grid.Column="1"
Height="12"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Fill="{TemplateBinding Foreground}"
Stretch="Uniform" />
</Grid>
<Rectangle Name="VerticalSeparator"
Grid.Column="1"
Width="1"
VerticalAlignment="Stretch"
Fill="{TemplateBinding SeparatorBrush}"
IsVisible="{TemplateBinding AreSeparatorsVisible}" />
<Grid x:Name="FocusVisual" IsHitTestVisible="False"
IsVisible="False">
<Rectangle x:Name="FocusVisualPrimary"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
StrokeThickness="2" />
<Rectangle x:Name="FocusVisualSecondary"
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
StrokeThickness="1" />
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:focus-visible /template/ Grid#FocusVisual">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^:pointerover /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderHoveredBackgroundBrush}" />
</Style>
<Style Selector="^:pressed /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource DataGridColumnHeaderPressedBackgroundBrush}" />
</Style>
<Style Selector="^:dragIndicator">
<Setter Property="Opacity" Value="0.5" />
</Style>
<Style Selector="^:sortascending /template/ Path#SortIcon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{StaticResource DataGridSortIconAscendingPath}" />
</Style>
<Style Selector="^:sortdescending /template/ Path#SortIcon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{StaticResource DataGridSortIconDescendingPath}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="DataGridTopLeftColumnHeader" TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="Template">
<ControlTemplate>
<Grid x:Name="TopLeftHeaderRoot"
RowDefinitions="*,*,Auto">
<Border Grid.RowSpan="2"
BorderThickness="0,0,1,0"
BorderBrush="{DynamicResource DataGridGridLinesBrush}" />
<Rectangle Grid.Row="0" Grid.RowSpan="2"
VerticalAlignment="Bottom"
StrokeThickness="1"
Height="1"
Fill="{DynamicResource DataGridGridLinesBrush}" />
</Grid>
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="{x:Type DataGridRowHeader}" TargetType="DataGridRowHeader">
<Setter Property="Focusable" Value="False" />
<Setter Property="SeparatorBrush" Value="{DynamicResource DataGridGridLinesBrush}" />
<Setter Property="AreSeparatorsVisible" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Grid x:Name="PART_Root"
RowDefinitions="*,*,Auto"
ColumnDefinitions="Auto,*">
<Border Grid.RowSpan="3"
Grid.ColumnSpan="2"
BorderBrush="{TemplateBinding SeparatorBrush}"
BorderThickness="0,0,1,0">
<Grid Background="{TemplateBinding Background}">
<Rectangle x:Name="RowInvalidVisualElement"
Opacity="0"
Fill="{DynamicResource DataGridRowInvalidBrush}"
Stretch="Fill" />
<Rectangle x:Name="BackgroundRectangle"
Fill="{DynamicResource DataGridRowBackgroundBrush}"
Stretch="Fill" />
</Grid>
</Border>
<Rectangle x:Name="HorizontalSeparator"
Grid.Row="2"
Grid.ColumnSpan="2"
Height="1"
Margin="1,0,1,0"
HorizontalAlignment="Stretch"
Fill="{TemplateBinding SeparatorBrush}"
IsVisible="{TemplateBinding AreSeparatorsVisible}" />
<ContentPresenter Grid.RowSpan="2"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="{x:Type DataGridRow}" TargetType="DataGridRow">
<Setter Property="Focusable" Value="False" />
<Setter Property="Background" Value="{Binding $parent[DataGrid].RowBackground}" />
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="RowBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<DataGridFrozenGrid Name="PART_Root"
ColumnDefinitions="Auto,*"
RowDefinitions="*,Auto,Auto">
<Rectangle Name="BackgroundRectangle"
Fill="{DynamicResource DataGridRowBackgroundBrush}"
Grid.RowSpan="2"
Grid.ColumnSpan="2" />
<Rectangle x:Name="InvalidVisualElement"
Opacity="0"
Grid.ColumnSpan="2"
Fill="{DynamicResource DataGridRowInvalidBrush}" />
<DataGridRowHeader Name="PART_RowHeader"
Grid.RowSpan="3"
DataGridFrozenGrid.IsFrozen="True" />
<DataGridCellsPresenter Name="PART_CellsPresenter"
Grid.Column="1"
DataGridFrozenGrid.IsFrozen="True" />
<DataGridDetailsPresenter Name="PART_DetailsPresenter"
Grid.Row="1"
Grid.Column="1"
Background="{DynamicResource DataGridDetailsPresenterBackgroundBrush}" />
<Rectangle Name="PART_BottomGridLine"
Grid.Row="2"
Grid.Column="1"
Height="1"
HorizontalAlignment="Stretch" />
</DataGridFrozenGrid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:invalid">
<Style Selector="^ /template/ Rectangle#InvalidVisualElement">
<Setter Property="Opacity" Value="0.4" />
</Style>
<Style Selector="^ /template/ Rectangle#BackgroundRectangle">
<Setter Property="Opacity" Value="0" />
</Style>
</Style>
<Style Selector="^:pointerover /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource DataGridRowHoveredBackgroundColor}" />
</Style>
<Style Selector="^:selected">
<Style Selector="^ /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource DataGridRowSelectedUnfocusedBackgroundBrush}" />
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedUnfocusedBackgroundOpacity}" />
</Style>
<Style Selector="^:pointerover /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource DataGridRowSelectedHoveredUnfocusedBackgroundBrush}" />
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity}" />
</Style>
<Style Selector="^:focus /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource DataGridRowSelectedBackgroundBrush}" />
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedBackgroundOpacity}" />
</Style>
<Style Selector="^:pointerover:focus /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource DataGridRowSelectedHoveredBackgroundBrush}" />
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedHoveredBackgroundOpacity}" />
</Style>
</Style>
</ControlTheme>
<ControlTheme x:Key="FluentDataGridRowGroupExpanderButtonTheme" TargetType="ToggleButton">
<Setter Property="Template">
<ControlTemplate>
<Border Width="12"
Height="12"
Background="Transparent"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Path Fill="{TemplateBinding Foreground}"
Data="{StaticResource DataGridRowGroupHeaderIconClosedPath}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Stretch="Uniform" />
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:checked /template/ Path">
<Setter Property="Data" Value="{StaticResource DataGridRowGroupHeaderIconOpenedPath}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type DataGridRowGroupHeader}" TargetType="DataGridRowGroupHeader">
<Setter Property="Focusable" Value="False" />
<Setter Property="Foreground" Value="{DynamicResource DataGridRowGroupHeaderForegroundBrush}" />
<Setter Property="Background" Value="{DynamicResource DataGridRowGroupHeaderBackgroundBrush}" />
<Setter Property="FontSize" Value="15" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Template">
<ControlTemplate x:DataType="collections:DataGridCollectionViewGroup">
<DataGridFrozenGrid Name="PART_Root"
Background="{TemplateBinding Background}"
MinHeight="{TemplateBinding MinHeight}"
ColumnDefinitions="Auto,Auto,Auto,Auto,*"
RowDefinitions="*,Auto">
<Rectangle Name="PART_IndentSpacer"
Grid.Column="1" />
<ToggleButton Name="PART_ExpanderButton"
Grid.Column="2"
Width="12"
Height="12"
Margin="12,0,0,0"
Theme="{StaticResource FluentDataGridRowGroupExpanderButtonTheme}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}"
Focusable="False"
Foreground="{TemplateBinding Foreground}" />
<StackPanel Grid.Column="3"
Orientation="Horizontal"
VerticalAlignment="Center"
Margin="12,0,0,0">
<TextBlock Name="PART_PropertyNameElement"
Margin="4,0,0,0"
IsVisible="{TemplateBinding IsPropertyNameVisible}"
Foreground="{TemplateBinding Foreground}" />
<TextBlock Margin="4,0,0,0"
Text="{Binding Key}"
Foreground="{TemplateBinding Foreground}" />
<TextBlock Name="PART_ItemCountElement"
Margin="4,0,0,0"
IsVisible="{TemplateBinding IsItemCountVisible}"
Foreground="{TemplateBinding Foreground}" />
</StackPanel>
<Rectangle x:Name="CurrencyVisual"
Grid.ColumnSpan="5"
IsVisible="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCurrencyVisualPrimaryBrush}"
StrokeThickness="1" />
<Grid x:Name="FocusVisual"
Grid.ColumnSpan="5"
IsVisible="False"
IsHitTestVisible="False">
<Rectangle HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
StrokeThickness="2" />
<Rectangle Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
IsHitTestVisible="False"
Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
StrokeThickness="1" />
</Grid>
<DataGridRowHeader Name="PART_RowHeader"
Grid.RowSpan="2"
DataGridFrozenGrid.IsFrozen="True" />
<Rectangle x:Name="PART_BottomGridLine"
Grid.Row="1"
Grid.ColumnSpan="5"
Height="1" />
</DataGridFrozenGrid>
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="{x:Type DataGrid}" TargetType="DataGrid">
<Setter Property="RowBackground" Value="Transparent" />
<Setter Property="HeadersVisibility" Value="Column" />
<Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="SelectionMode" Value="Extended" />
<Setter Property="GridLinesVisibility" Value="None" />
<Setter Property="HorizontalGridLinesBrush" Value="{DynamicResource DataGridGridLinesBrush}" />
<Setter Property="VerticalGridLinesBrush" Value="{DynamicResource DataGridGridLinesBrush}" />
<Setter Property="DropLocationIndicatorTemplate">
<Template>
<Rectangle Fill="{DynamicResource DataGridDropLocationIndicatorBackground}"
Width="2" />
</Template>
</Setter>
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="DataGridBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid ColumnDefinitions="Auto,*,Auto"
RowDefinitions="Auto,*,Auto,Auto"
ClipToBounds="True">
<DataGridColumnHeader Name="PART_TopLeftCornerHeader"
Theme="{StaticResource DataGridTopLeftColumnHeader}" />
<DataGridColumnHeadersPresenter Name="PART_ColumnHeadersPresenter"
Grid.Column="1"
Grid.Row="0" Grid.ColumnSpan="2" />
<Rectangle Name="PART_ColumnHeadersAndRowsSeparator"
Grid.Row="0" Grid.ColumnSpan="3" Grid.Column="0"
VerticalAlignment="Bottom"
Height="1"
Fill="{DynamicResource DataGridGridLinesBrush}" />
<DataGridRowsPresenter Name="PART_RowsPresenter"
Grid.Row="1"
Grid.RowSpan="2"
Grid.ColumnSpan="3" Grid.Column="0">
<DataGridRowsPresenter.GestureRecognizers>
<ScrollGestureRecognizer CanHorizontallyScroll="True" CanVerticallyScroll="True" />
</DataGridRowsPresenter.GestureRecognizers>
</DataGridRowsPresenter>
<Rectangle Name="PART_BottomRightCorner"
Fill="{DynamicResource DataGridScrollBarsSeparatorBackground}"
Grid.Column="2"
Grid.Row="2" />
<ScrollBar Name="PART_VerticalScrollbar"
Orientation="Vertical"
Grid.Column="2"
Grid.Row="1"
Width="{DynamicResource ScrollBarSize}" />
<Grid Grid.Column="1"
Grid.Row="2"
ColumnDefinitions="Auto,*">
<Rectangle Name="PART_FrozenColumnScrollBarSpacer" />
<ScrollBar Name="PART_HorizontalScrollbar"
Grid.Column="1"
Orientation="Horizontal"
Height="{DynamicResource ScrollBarSize}" />
</Grid>
<Border x:Name="PART_DisabledVisualElement"
Grid.ColumnSpan="3" Grid.Column="0"
Grid.Row="0" Grid.RowSpan="4"
IsHitTestVisible="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CornerRadius="2"
Background="{DynamicResource DataGridDisabledVisualElementBackground}"
IsVisible="{Binding !$parent[DataGrid].IsEnabled}" />
</Grid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:empty-columns">
<Style Selector="^ /template/ DataGridColumnHeader#PART_TopLeftCornerHeader">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ DataGridColumnHeadersPresenter#PART_ColumnHeadersPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ Rectangle#PART_ColumnHeadersAndRowsSeparator">
<Setter Property="IsVisible" Value="False" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>
</Styles.Resources>
</Styles>

View File

@ -24,7 +24,7 @@
<ItemsRepeater IsVisible="True" <ItemsRepeater IsVisible="True"
VerticalCacheLength="1.2" VerticalCacheLength="1.2"
HorizontalCacheLength="1" HorizontalCacheLength="1"
Items="{Binding CheckboxItems}" ItemsSource="{Binding CheckboxItems}"
ItemTemplate="{StaticResource elementFactory}" /> ItemTemplate="{StaticResource elementFactory}" />
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@ -23,7 +23,7 @@
CanUserSortColumns="False" CanUserSortColumns="False"
AutoGenerateColumns="False" AutoGenerateColumns="False"
IsReadOnly="False" IsReadOnly="False"
Items="{Binding Accounts}" ItemsSource="{Binding Accounts}"
GridLinesVisibility="All"> GridLinesVisibility="All">
<DataGrid.Columns> <DataGrid.Columns>
@ -64,14 +64,11 @@
<DataGridCheckBoxColumn <DataGridCheckBoxColumn
Binding="{Binding LibraryScan, Mode=TwoWay}" Binding="{Binding LibraryScan, Mode=TwoWay}"
Header="Include in&#xa;library scan?"/> Header="Include in&#xa;library scan?"/>
<DataGridTemplateColumn Width="2*" Header="Audible&#xa;email/login"> <DataGridTextColumn
<DataGridTemplateColumn.CellTemplate> Width="2*"
<DataTemplate> Binding="{Binding AccountId, Mode=TwoWay}"
<TextBox Text="{Binding AccountId, Mode=TwoWay}" /> Header="Audible&#xa;email/login"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="Auto" Header="Locale"> <DataGridTemplateColumn Width="Auto" Header="Locale">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
@ -96,13 +93,10 @@
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<DataGridTemplateColumn Width="3*" Header="Account Nickname&#xa;(optional)"> <DataGridTextColumn
<DataGridTemplateColumn.CellTemplate> Width="Auto"
<DataTemplate> Binding="{Binding AccountName, Mode=TwoWay}"
<TextBox Text="{Binding AccountName, Mode=TwoWay}" /> Header="Account Nickname&#xa;(optional)"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>

View File

@ -24,7 +24,7 @@
CanUserSortColumns="True" CanUserSortColumns="True"
AutoGenerateColumns="False" AutoGenerateColumns="False"
IsReadOnly="False" IsReadOnly="False"
Items="{Binding DataGridCollectionView}" ItemsSource="{Binding DataGridCollectionView}"
GridLinesVisibility="All"> GridLinesVisibility="All">
<DataGrid.Styles> <DataGrid.Styles>

View File

@ -41,9 +41,9 @@ namespace LibationAvalonia.Dialogs
} }
protected virtual void SaveAndClose() => Close(DialogResult.OK); protected virtual void SaveAndClose() => Close(DialogResult.OK);
protected virtual Task SaveAndCloseAsync() => Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(SaveAndClose); protected virtual async Task SaveAndCloseAsync() => await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(SaveAndClose);
protected virtual void CancelAndClose() => Close(DialogResult.Cancel); protected virtual void CancelAndClose() => Close(DialogResult.Cancel);
protected virtual Task CancelAndCloseAsync() => Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(CancelAndClose); protected virtual async Task CancelAndCloseAsync() => await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(CancelAndClose);
private async void DialogWindow_KeyDown(object sender, Avalonia.Input.KeyEventArgs e) private async void DialogWindow_KeyDown(object sender, Avalonia.Input.KeyEventArgs e)
{ {

View File

@ -23,7 +23,7 @@
CanUserSortColumns="False" CanUserSortColumns="False"
AutoGenerateColumns="False" AutoGenerateColumns="False"
IsReadOnly="False" IsReadOnly="False"
Items="{Binding Filters}" ItemsSource="{Binding Filters}"
GridLinesVisibility="All"> GridLinesVisibility="All">
<DataGrid.Columns> <DataGrid.Columns>
@ -44,14 +44,11 @@
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="Filter"> <DataGridTextColumn
<DataGridTemplateColumn.CellTemplate> Width="*"
<DataTemplate> IsReadOnly="False"
<TextBox Text="{Binding FilterString, Mode=TwoWay}" /> Binding="{Binding FilterString, Mode=TwoWay}"
</DataTemplate> Header="Filter"/>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Move&#xa;Up"> <DataGridTemplateColumn Header="Move&#xa;Up">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>

View File

@ -24,7 +24,7 @@
BeginningEdit="ReplacementGrid_BeginningEdit" BeginningEdit="ReplacementGrid_BeginningEdit"
CellEditEnding="ReplacementGrid_CellEditEnding" CellEditEnding="ReplacementGrid_CellEditEnding"
KeyDown="ReplacementGrid_KeyDown" KeyDown="ReplacementGrid_KeyDown"
Items="{Binding replacements}"> ItemsSource="{Binding replacements}">
<DataGrid.Columns> <DataGrid.Columns>

View File

@ -45,7 +45,7 @@
GridLinesVisibility="All" GridLinesVisibility="All"
AutoGenerateColumns="False" AutoGenerateColumns="False"
DoubleTapped="EditTemplateViewModel_DoubleTapped" DoubleTapped="EditTemplateViewModel_DoubleTapped"
Items="{Binding ListItems}" > ItemsSource="{Binding ListItems}" >
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTemplateColumn Width="Auto" Header="Tag"> <DataGridTemplateColumn Width="Auto" Header="Tag">

View File

@ -53,7 +53,7 @@ namespace LibationAvalonia.Dialogs.Login
public async void CopyUrlToClipboard_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public async void CopyUrlToClipboard_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> await Application.Current.Clipboard.SetTextAsync(ExternalLoginUrl); => await App.MainWindow.Clipboard.SetTextAsync(ExternalLoginUrl);
public void LaunchInBrowser_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void LaunchInBrowser_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> Go.To.Url(ExternalLoginUrl); => Go.To.Url(ExternalLoginUrl);

View File

@ -2,10 +2,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="950" d:DesignHeight="650" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650"
MinWidth="950" MinHeight="650" MinWidth="800" MinHeight="650"
MaxWidth="950" MaxHeight="650" MaxWidth="800" MaxHeight="650"
Width="950" Height="650" Width="800" Height="650"
x:Class="LibationAvalonia.Dialogs.SearchSyntaxDialog" x:Class="LibationAvalonia.Dialogs.SearchSyntaxDialog"
Title="Filter Options" Title="Filter Options"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
@ -16,48 +16,55 @@
RowDefinitions="Auto,Auto,*" RowDefinitions="Auto,Auto,*"
ColumnDefinitions="Auto,Auto,Auto,Auto"> ColumnDefinitions="Auto,Auto,Auto,Auto">
<TextBlock Margin="10" <Grid.Styles>
<Style Selector="TextBlock">
<Setter Property="FontSize" Value="12" />
<Setter Property="Margin" Value="10" />
</Style>
</Grid.Styles>
<TextBlock
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="4" Grid.ColumnSpan="4"
Text="Full Lucene query syntax is supported&#xa;Fields with similar names are synomyns (eg: Author, Authors, AuthorNames)&#xa;&#xa;TAG FORMAT: [tagName]" /> Text="Full Lucene query syntax is supported&#xa;Fields with similar names are synomyns (eg: Author, Authors, AuthorNames)&#xa;&#xa;TAG FORMAT: [tagName]" />
<TextBlock Margin="10" <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Text="STRING FIELDS" /> Text="STRING FIELDS" />
<TextBlock Margin="10" <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Text="NUMBER FIELDS" /> Text="NUMBER FIELDS" />
<TextBlock Margin="10" <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="2" Grid.Column="2"
Text="BOOLEAN (TRUE/FALSE) FIELDS" /> Text="BOOLEAN (TRUE/FALSE) FIELDS" />
<TextBlock Margin="10" <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="3" Grid.Column="3"
Text="ID FIELDS" /> Text="ID FIELDS" />
<TextBlock Margin="10" <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Text="{Binding StringFields}" /> Text="{Binding StringFields}" />
<TextBlock Margin="10" <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Text="{Binding NumberFields}" /> Text="{Binding NumberFields}" />
<TextBlock Margin="10" <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Text="{Binding BoolFields}" /> Text="{Binding BoolFields}" />
<TextBlock Margin="10" <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="3" Grid.Column="3"
Text="{Binding IdFields}" /> Text="{Binding IdFields}" />

View File

@ -25,6 +25,9 @@ Find books between 1-100 minutes long
length:[1 TO 100] length:[1 TO 100]
Find books exactly 1 hr long Find books exactly 1 hr long
length:60 length:60
Find books published from 2020-1-1 to
2023-12-31
datepublished:[20200101 TO 20231231]
" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchNumberFields()); " + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchNumberFields());

View File

@ -1,6 +1,7 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
using LibationFileManager; using LibationFileManager;
using System; using System;
using System.Linq; using System.Linq;
@ -111,12 +112,12 @@ namespace LibationAvalonia
public static void HideMinMaxBtns(this Window form) public static void HideMinMaxBtns(this Window form)
{ {
if (Design.IsDesignMode || !Configuration.IsWindows) if (Design.IsDesignMode || !Configuration.IsWindows || form.TryGetPlatformHandle() is not IPlatformHandle handle)
return; return;
var handle = form.PlatformImpl.Handle.Handle;
var currentStyle = GetWindowLong(handle, GWL_STYLE);
SetWindowLong(handle, GWL_STYLE, currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX); var currentStyle = GetWindowLong(handle.Handle, GWL_STYLE);
SetWindowLong(handle.Handle, GWL_STYLE, currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
} }
const long WS_MINIMIZEBOX = 0x00020000L; const long WS_MINIMIZEBOX = 0x00020000L;

View File

@ -32,8 +32,8 @@
<ItemGroup> <ItemGroup>
<AvaloniaResource Include="Assets\**" /> <AvaloniaResource Include="Assets\**" />
<None Remove=".gitignore" /> <None Remove=".gitignore" />
<None Remove="Assets\DataGridFluentTheme.xaml" /> <None Remove="Assets\DataGridColumnHeader.xaml" />
<None Remove="Assets\img-coverart-prod-unavailable_300x300.jpg" /> <None Remove="Assets\img-coverart-prod-unavailable_300x300.jpg" />
<None Remove="Assets\img-coverart-prod-unavailable_500x500.jpg" /> <None Remove="Assets\img-coverart-prod-unavailable_500x500.jpg" />
<None Remove="Assets\img-coverart-prod-unavailable_80x80.jpg" /> <None Remove="Assets\img-coverart-prod-unavailable_80x80.jpg" />
@ -70,13 +70,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.0-preview6" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" /> <PackageReference Include="Avalonia.Diagnostics" Version="11.0.0-preview8" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
<PackageReference Include="Avalonia" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview8" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview6" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview8" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -46,7 +46,7 @@
VerticalCacheLength="1.2" VerticalCacheLength="1.2"
HorizontalCacheLength="1" HorizontalCacheLength="1"
Background="Transparent" Background="Transparent"
Items="{Binding Items}" ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource elementFactory}" /> ItemTemplate="{StaticResource elementFactory}" />
</ScrollViewer> </ScrollViewer>
</Border> </Border>
@ -81,7 +81,7 @@
</TabItem.Header> </TabItem.Header>
<Grid ColumnDefinitions="*" RowDefinitions="*,40"> <Grid ColumnDefinitions="*" RowDefinitions="*,40">
<Border Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="{DynamicResource SystemBaseMediumColor}" Background="{DynamicResource SystemChromeMediumLowColor}"> <Border Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="{DynamicResource SystemBaseMediumColor}" Background="{DynamicResource SystemChromeMediumLowColor}">
<DataGrid AutoGenerateColumns="False" Items="{Binding LogEntries}"> <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding LogEntries}">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn SortMemberPath="LogDate" Header="Timestamp" CanUserSort="True" Binding="{Binding LogDateString}" Width="90"/> <DataGridTextColumn SortMemberPath="LogDate" Header="Timestamp" CanUserSort="True" Binding="{Binding LogDateString}" Width="90"/>
<DataGridTemplateColumn SortMemberPath="LogMessage" Width="*" Header="Message" CanUserSort="True"> <DataGridTemplateColumn SortMemberPath="LogMessage" Width="*" Header="Message" CanUserSort="True">

View File

@ -130,7 +130,7 @@ namespace LibationAvalonia.Views
private async void LogCopyBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) private async void LogCopyBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{ {
string logText = string.Join("\r\n", _viewModel.LogEntries.Select(r => $"{r.LogDate.ToShortDateString()} {r.LogDate.ToShortTimeString()}\t{r.LogMessage}")); string logText = string.Join("\r\n", _viewModel.LogEntries.Select(r => $"{r.LogDate.ToShortDateString()} {r.LogDate.ToShortTimeString()}\t{r.LogMessage}"));
await Application.Current.Clipboard.SetTextAsync(logText); await App.MainWindow.Clipboard.SetTextAsync(logText);
} }
private async void cancelAllBtn_Click(object sender, EventArgs e) private async void cancelAllBtn_Click(object sender, EventArgs e)

View File

@ -15,7 +15,7 @@
ClipboardCopyMode="IncludeHeader" ClipboardCopyMode="IncludeHeader"
GridLinesVisibility="All" GridLinesVisibility="All"
AutoGenerateColumns="False" AutoGenerateColumns="False"
Items="{Binding GridEntries}" ItemsSource="{Binding GridEntries}"
CanUserSortColumns="True" BorderThickness="3" CanUserSortColumns="True" BorderThickness="3"
CanUserReorderColumns="True"> CanUserReorderColumns="True">

View File

@ -231,7 +231,7 @@ namespace LibationAvalonia.Views
var menuItem = new MenuItem { Header = "_Copy Cell Contents" }; var menuItem = new MenuItem { Header = "_Copy Cell Contents" };
menuItem.Click += async (s, e) menuItem.Click += async (s, e)
=> await Application.Current.Clipboard.SetTextAsync(args.CellClipboardContents); => await App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents);
args.ContextMenuItems.Add(menuItem); args.ContextMenuItems.Add(menuItem);
} }

View File

@ -11,7 +11,7 @@
ClipboardCopyMode="IncludeHeader" ClipboardCopyMode="IncludeHeader"
GridLinesVisibility="All" GridLinesVisibility="All"
AutoGenerateColumns="False" AutoGenerateColumns="False"
Items="{Binding SeriesEntries}" ItemsSource="{Binding SeriesEntries}"
CanUserSortColumns="True" CanUserSortColumns="True"
CanUserReorderColumns="True" CanUserReorderColumns="True"
BorderThickness="3"> BorderThickness="3">

View File

@ -16,6 +16,7 @@ namespace LibationFileManager
Process RunAsRoot(string exe, string args); Process RunAsRoot(string exe, string args);
void InstallUpgrade(string upgradeBundle); void InstallUpgrade(string upgradeBundle);
bool CanUpgrade { get; } bool CanUpgrade { get; }
string ReleaseIdString { get; }
} }
public class WebViewNavigationEventArgs : EventArgs public class WebViewNavigationEventArgs : EventArgs

View File

@ -15,6 +15,7 @@ namespace LibationFileManager
public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException(); public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException();
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException(); public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
public bool CanUpgrade => throw new PlatformNotSupportedException(); public bool CanUpgrade => throw new PlatformNotSupportedException();
public string ReleaseIdString => throw new PlatformNotSupportedException();
public Process RunAsRoot(string exe, string args) => throw new PlatformNotSupportedException(); public Process RunAsRoot(string exe, string args) => throw new PlatformNotSupportedException();
public void InstallUpgrade(string updateBundle) => throw new PlatformNotSupportedException(); public void InstallUpgrade(string updateBundle) => throw new PlatformNotSupportedException();
} }

View File

@ -37,6 +37,8 @@ namespace LibationSearchEngine
internal static string ToLuceneString(this float f) => ((double)f).ToLuceneString(); internal static string ToLuceneString(this float f) => ((double)f).ToLuceneString();
internal static string ToLuceneString(this DateTime dt) internal static string ToLuceneString(this DateTime dt)
=> dt.ToString("yyyyMMdd") + DECIMAL_PRECISION; => dt.ToString("yyyyMMdd") + DECIMAL_PRECISION;
internal static string ToLuceneString(this DateTime? dt)
=> dt?.ToLuceneString() ?? "";
internal static string ToLuceneString(this double d) internal static string ToLuceneString(this double d)
=> d.ToString("0" + DECIMAL_PRECISION).PadLeft(PAD_DIGITS + DECIMAL_PRECISION.Length, '0'); => d.ToString("0" + DECIMAL_PRECISION).PadLeft(PAD_DIGITS + DECIMAL_PRECISION.Length, '0');
} }

View File

@ -46,9 +46,6 @@ namespace LibationSearchEngine
= new ReadOnlyDictionary<string, Func<LibraryBook, string>>( = new ReadOnlyDictionary<string, Func<LibraryBook, string>>(
new Dictionary<string, Func<LibraryBook, string>> new Dictionary<string, Func<LibraryBook, string>>
{ {
[nameof(LibraryBook.DateAdded)] = lb => lb.DateAdded.ToLuceneString(),
[nameof(Book.DatePublished)] = lb => lb.Book.DatePublished?.ToLuceneString(),
[nameof(Book.Title)] = lb => lb.Book.Title, [nameof(Book.Title)] = lb => lb.Book.Title,
[ALL_AUTHOR_NAMES] = lb => lb.Book.AuthorNames(), [ALL_AUTHOR_NAMES] = lb => lb.Book.AuthorNames(),
["Author"] = lb => lb.Book.AuthorNames(), ["Author"] = lb => lb.Book.AuthorNames(),
@ -91,7 +88,13 @@ namespace LibationSearchEngine
["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), ["ProductRating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(), ["Rating"] = lb => lb.Book.Rating.OverallRating.ToLuceneString(),
["UserRating"] = lb => userOverallRating(lb.Book), ["UserRating"] = lb => userOverallRating(lb.Book),
["MyRating"] = lb => userOverallRating(lb.Book) ["MyRating"] = lb => userOverallRating(lb.Book),
[nameof(LibraryBook.DateAdded)] = lb => lb.DateAdded.ToLuceneString(),
[nameof(Book.DatePublished)] = lb => lb.Book.DatePublished?.ToLuceneString(),
["LastDownload"] = lb => lb.Book.UserDefinedItem.LastDownloaded.ToLuceneString(),
["LastDownloaded"] = lb => lb.Book.UserDefinedItem.LastDownloaded.ToLuceneString()
} }
); );
@ -127,6 +130,9 @@ namespace LibationSearchEngine
["Episode"] = lb => lb.Book.IsEpisodeChild(), ["Episode"] = lb => lb.Book.IsEpisodeChild(),
["Episodes"] = lb => lb.Book.IsEpisodeChild(), ["Episodes"] = lb => lb.Book.IsEpisodeChild(),
["IsEpisode"] = lb => lb.Book.IsEpisodeChild(), ["IsEpisode"] = lb => lb.Book.IsEpisodeChild(),
["Absent"] = lb => lb.AbsentFromLastScan,
["AbsentFromLastScan"] = lb => lb.AbsentFromLastScan,
} }
); );
@ -287,7 +293,13 @@ namespace LibationSearchEngine
var v2 = liberatedError(book); var v2 = liberatedError(book);
d.RemoveField("liberatederror"); d.RemoveField("liberatederror");
d.AddBool("LiberatedError", v2); d.AddBool("LiberatedError", v2);
});
var v3 = book.UserDefinedItem.LastDownloaded?.ToLuceneString() ?? "";
d.RemoveField("LastDownload");
d.AddNotAnalyzed("LastDownload", v3);
d.RemoveField("LastDownloaded");
d.AddNotAnalyzed("LastDownloaded", v3);
});
public void UpdateUserRatings(Book book) public void UpdateUserRatings(Book book)
=>updateDocument( =>updateDocument(

View File

@ -1,132 +1,135 @@
namespace LibationWinForms.Dialogs namespace LibationWinForms.Dialogs
{ {
partial class SearchSyntaxDialog partial class SearchSyntaxDialog
{ {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.
/// </summary> /// </summary>
private System.ComponentModel.IContainer components = null; private System.ComponentModel.IContainer components = null;
/// <summary> /// <summary>
/// Clean up any resources being used. /// Clean up any resources being used.
/// </summary> /// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing && (components != null)) if (disposing && (components != null))
{ {
components.Dispose(); components.Dispose();
} }
base.Dispose(disposing); base.Dispose(disposing);
} }
#region Windows Form Designer generated code #region Windows Form Designer generated code
/// <summary> /// <summary>
/// Required method for Designer support - do not modify /// Required method for Designer support - do not modify
/// the contents of this method with the code editor. /// the contents of this method with the code editor.
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
this.label1 = new System.Windows.Forms.Label(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SearchSyntaxDialog));
this.label2 = new System.Windows.Forms.Label(); label1 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label(); label2 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label(); label3 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label(); label4 = new System.Windows.Forms.Label();
this.closeBtn = new System.Windows.Forms.Button(); label5 = new System.Windows.Forms.Label();
this.SuspendLayout(); closeBtn = new System.Windows.Forms.Button();
// SuspendLayout();
// label1 //
// // label1
this.label1.AutoSize = true; //
this.label1.Location = new System.Drawing.Point(12, 9); label1.AutoSize = true;
this.label1.Name = "label1"; label1.Location = new System.Drawing.Point(14, 10);
this.label1.Size = new System.Drawing.Size(358, 52); label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.TabIndex = 0; label1.Name = "label1";
this.label1.Text = "Full Lucene query syntax is supported\r\nFields with similar names are synomyns (eg" + label1.Size = new System.Drawing.Size(410, 60);
": Author, Authors, AuthorNames)\r\n\r\nTAG FORMAT: [tagName]"; label1.TabIndex = 0;
// label1.Text = "Full Lucene query syntax is supported\r\nFields with similar names are synomyns (eg: Author, Authors, AuthorNames)\r\n\r\nTAG FORMAT: [tagName]";
// label2 //
// // label2
this.label2.AutoSize = true; //
this.label2.Location = new System.Drawing.Point(12, 71); label2.AutoSize = true;
this.label2.Name = "label2"; label2.Location = new System.Drawing.Point(14, 82);
this.label2.Size = new System.Drawing.Size(118, 65); label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label2.TabIndex = 1; label2.Name = "label2";
this.label2.Text = "STRING FIELDS\r\n\r\nSearch for wizard of oz:\r\n title:oz\r\n title:\"wizard of o" + label2.Size = new System.Drawing.Size(129, 75);
"z\""; label2.TabIndex = 1;
// label2.Text = "STRING FIELDS\r\n\r\nSearch for wizard of oz:\r\n title:oz\r\n title:\"wizard of oz\"";
// label3 //
// // label3
this.label3.AutoSize = true; //
this.label3.Location = new System.Drawing.Point(233, 71); label3.AutoSize = true;
this.label3.Name = "label3"; label3.Location = new System.Drawing.Point(272, 82);
this.label3.Size = new System.Drawing.Size(195, 78); label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label3.TabIndex = 2; label3.Name = "label3";
this.label3.Text = "NUMBER FIELDS\r\n\r\nFind books between 1-100 minutes long\r\n length:[1 TO 100]\r\nF" + label3.Size = new System.Drawing.Size(224, 135);
"ind books exactly 1 hr long\r\n length:60"; label3.TabIndex = 2;
// label3.Text = resources.GetString("label3.Text");
// label4 //
// // label4
this.label4.AutoSize = true; //
this.label4.Location = new System.Drawing.Point(454, 71); label4.AutoSize = true;
this.label4.Name = "label4"; label4.Location = new System.Drawing.Point(530, 82);
this.label4.Size = new System.Drawing.Size(168, 52); label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label4.TabIndex = 3; label4.Name = "label4";
this.label4.Text = "BOOLEAN (TRUE/FALSE) FIELDS\r\n\r\nFind books that you haven\'t rated:\r\n -IsRated"; label4.Size = new System.Drawing.Size(187, 60);
// label4.TabIndex = 3;
// label5 label4.Text = "BOOLEAN (TRUE/FALSE) FIELDS\r\n\r\nFind books that you haven't rated:\r\n -IsRated";
// //
this.label5.AutoSize = true; // label5
this.label5.Location = new System.Drawing.Point(673, 71); //
this.label5.Name = "label5"; label5.AutoSize = true;
this.label5.Size = new System.Drawing.Size(257, 78); label5.Location = new System.Drawing.Point(785, 82);
this.label5.TabIndex = 4; label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label5.Text = "ID FIELDS\r\n\r\nAlice\'s Adventures in Wonderland (ID: B015D78L0U)\r\n id:B015D78L0" + label5.Name = "label5";
"U\r\n\r\nAll of these are synonyms for the ID field"; label5.Size = new System.Drawing.Size(278, 90);
// label5.TabIndex = 4;
// closeBtn label5.Text = "ID FIELDS\r\n\r\nAlice's Adventures in Wonderland (ID: B015D78L0U)\r\n id:B015D78L0U\r\n\r\nAll of these are synonyms for the ID field";
// //
this.closeBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); // closeBtn
this.closeBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; //
this.closeBtn.Location = new System.Drawing.Point(890, 465); closeBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
this.closeBtn.Name = "closeBtn"; closeBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.closeBtn.Size = new System.Drawing.Size(75, 23); closeBtn.Location = new System.Drawing.Point(1038, 537);
this.closeBtn.TabIndex = 5; closeBtn.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.closeBtn.Text = "Close"; closeBtn.Name = "closeBtn";
this.closeBtn.UseVisualStyleBackColor = true; closeBtn.Size = new System.Drawing.Size(88, 27);
this.closeBtn.Click += new System.EventHandler(this.CloseBtn_Click); closeBtn.TabIndex = 5;
// closeBtn.Text = "Close";
// SearchSyntaxDialog closeBtn.UseVisualStyleBackColor = true;
// closeBtn.Click += CloseBtn_Click;
this.AcceptButton = this.closeBtn; //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); // SearchSyntaxDialog
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; //
this.CancelButton = this.closeBtn; AcceptButton = closeBtn;
this.ClientSize = new System.Drawing.Size(977, 500); AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.Controls.Add(this.closeBtn); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.label5); CancelButton = closeBtn;
this.Controls.Add(this.label4); ClientSize = new System.Drawing.Size(1140, 577);
this.Controls.Add(this.label3); Controls.Add(closeBtn);
this.Controls.Add(this.label2); Controls.Add(label5);
this.Controls.Add(this.label1); Controls.Add(label4);
this.MaximizeBox = false; Controls.Add(label3);
this.MinimizeBox = false; Controls.Add(label2);
this.Name = "SearchSyntaxDialog"; Controls.Add(label1);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
this.Text = "Filter options"; MaximizeBox = false;
this.ResumeLayout(false); MinimizeBox = false;
this.PerformLayout(); Name = "SearchSyntaxDialog";
StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Text = "Filter options";
ResumeLayout(false);
PerformLayout();
}
} #endregion
#endregion private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label4; private System.Windows.Forms.Button closeBtn;
private System.Windows.Forms.Label label5; }
private System.Windows.Forms.Button closeBtn;
}
} }

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <root>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
@ -58,4 +57,15 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="label3.Text" xml:space="preserve">
<value>NUMBER FIELDS
Find books between 1-100 minutes long
length:[1 TO 100]
Find books exactly 1 hr long
length:60
Find books published from 2020-1-1 to
2023-12-31
datepublished:[20200101 TO 20231231]</value>
</data>
</root> </root>

View File

@ -1,4 +1,5 @@
using LibationFileManager; using AppScaffolding;
using LibationFileManager;
using System.Diagnostics; using System.Diagnostics;
namespace LinuxConfigApp namespace LinuxConfigApp
@ -24,12 +25,17 @@ namespace LinuxConfigApp
public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException(); public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException();
public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException(); public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException();
public string ReleaseIdString => LibationScaffolding.ReleaseIdentifier.ToString() + (File.Exists("/bin/yum") ? "_RPM" : "");
//only run the auto upgrader if the current app was installed from the //only run the auto upgrader if the current app was installed from the
//.deb package. Try to detect this by checking if the symlink exists. //.deb or .rpm package. Try to detect this by checking if the symlink exists.
public bool CanUpgrade => Directory.Exists("/usr/lib/libation"); public bool CanUpgrade => Directory.Exists("/usr/lib/libation");
public void InstallUpgrade(string upgradeBundle) public void InstallUpgrade(string upgradeBundle)
{ {
RunAsRoot("apt", $"install '{upgradeBundle}'"); if (File.Exists("/bin/yum"))
RunAsRoot("yum", $"install '{upgradeBundle}'");
else
RunAsRoot("apt", $"install '{upgradeBundle}'");
} }
public Process RunAsRoot(string exe, string args) public Process RunAsRoot(string exe, string args)

View File

@ -24,6 +24,8 @@ namespace MacOSConfigApp
//the running process, so don't upgrade unless it's "installed" in /Applications //the running process, so don't upgrade unless it's "installed" in /Applications
public bool CanUpgrade => Directory.Exists(AppPath); public bool CanUpgrade => Directory.Exists(AppPath);
public string ReleaseIdString => AppScaffolding.LibationScaffolding.ReleaseIdentifier.ToString();
public void InstallUpgrade(string upgradeBundle) public void InstallUpgrade(string upgradeBundle)
{ {
Serilog.Log.Information($"Extracting upgrade bundle to {AppPath}"); Serilog.Log.Information($"Extracting upgrade bundle to {AppPath}");

View File

@ -25,6 +25,9 @@ namespace WindowsConfigApp
=> new DirectoryInfo(directory)?.DeleteIcon(); => new DirectoryInfo(directory)?.DeleteIcon();
public bool CanUpgrade => true; public bool CanUpgrade => true;
public string ReleaseIdString => AppScaffolding.LibationScaffolding.ReleaseIdentifier.ToString();
public void InstallUpgrade(string upgradeBundle) public void InstallUpgrade(string upgradeBundle)
{ {
var thisExe = Environment.ProcessPath; var thisExe = Environment.ProcessPath;