Compare commits

...

36 Commits

Author SHA1 Message Date
Robert McRackan
86efe631fe restore yaml 2022-12-07 13:49:05 -05:00
Robert McRackan
f5f1dc483b publish debugging. create new version 2022-12-07 13:34:30 -05:00
Robert McRackan
8aa4328c6c update dependencies 2022-12-07 13:09:02 -05:00
Robert McRackan
4b2387b621 update dependencies 2022-12-07 11:53:10 -05:00
Robert McRackan
74d16d8ef9 yaml releases don't run. comment out for now 2022-12-07 07:42:11 -05:00
rmcrackan
b1ea8f9fa7 Update GettingStarted.md
disclaimer: don't install in Program Files
2022-12-06 15:59:11 -05:00
rmcrackan
c666fdeaff document CLI set-status 2022-12-06 15:02:26 -05:00
Robert McRackan
7068782975 Merge branch 'master' of https://github.com/rmcrackan/Libation 2022-12-06 14:58:30 -05:00
Robert McRackan
c4cebbebe7 * #396 New feature : match download status to files
* UI: Visible Books \> Set 'Downloaded' status automatically. Visible books. Prompts before saving changes
  * CLI: Full library. No prompt
2022-12-06 14:58:22 -05:00
rmcrackan
53d43d9fa9 Merge pull request #401 from pixil98/master
Add validate and release workflows
2022-12-05 14:54:39 -05:00
Aaron Reisman
11d59beeed Rename happens before zipping 2022-11-28 13:08:57 -06:00
Aaron Reisman
ef71e297f4 Add special handling for classic build 2022-11-28 12:54:17 -06:00
Aaron Reisman
1e4d1d1973 Lowercase OS names in releaseindex 2022-11-28 12:44:48 -06:00
pixil98
893d99854b Merge branch 'master' into master 2022-11-25 00:20:51 -06:00
Aaron Reisman
db93980cd5 Rename publish to release 2022-11-24 23:54:49 -06:00
pixil98
34fac30b2b Merge official updates (#6)
Pull latest Libation updates, fix move to net7
2022-11-24 23:53:00 -06:00
pixil98
2fa0bcb765 Near final workflows
Updated workflows to release zips with the correct file names.
2022-11-23 15:48:37 -06:00
pixil98
78fd09aa91 Proper build
Builds all packages properly
2022-11-22 10:45:33 -06:00
Robert McRackan
a54516b4f5 Fix pubxml hierarchy 2022-11-21 13:51:30 -05:00
Robert McRackan
f193d6f376 AudibleApi fixed 2022-11-17 17:05:58 -05:00
pixil98
8a82c294a1 Fix publish workflow (#2)
* Add dotnet test workflow

* main -> master

* Try a different workflow

* Add working-directory

* use windows runner

* use env var

* Fix build and test order

* Specify configuration

* Specify sln instead of working dir

* Specify that DOTNET_SLN is an env var

* Add publish workflow

* Add env.DOTNET_SLN to publish workflow

* Add publish job

* Combine publish into one job

* Just create an artifact

* Remove unused nuget lines

* Add Publish job back

Co-authored-by: Aaron Reisman <areisman@epic.com>
2022-11-16 13:40:57 -06:00
Robert McRackan
9392cf4bf0 update dependencies 2022-11-16 13:36:23 -05:00
Robert McRackan
ec4deb9099 update db dependencies 2022-11-16 12:48:22 -05:00
Robert McRackan
cf0548aab9 update dependencies 2022-11-16 12:46:12 -05:00
pixil98
064801380b Add workflows (#1)
Adds basic workflows
2022-11-16 11:44:15 -06:00
Robert McRackan
9dc2a7424a DataLayer => .net7 2022-11-16 11:49:07 -05:00
Robert McRackan
4c8a56a5b9 Core, Utilities => .net7 2022-11-16 11:47:34 -05:00
Robert McRackan
9aad263996 Domain Internal Utilities => .net7 2022-11-16 11:46:26 -05:00
Robert McRackan
ce1ab7c20d Domain Utilities => .net7 2022-11-16 11:45:04 -05:00
Robert McRackan
c9217990cd applications => .net7 2022-11-16 11:43:35 -05:00
Robert McRackan
90cbf3b7a6 tests => .net7 2022-11-16 11:27:51 -05:00
Robert McRackan
c4f1b22ddf demos => .net7 2022-11-16 11:24:30 -05:00
Robert McRackan
fb612ea6ab Bug fix #394 : Scanning dir.s containing symlinks causes errors. Thanks @CharlieRussel 2022-11-14 16:22:29 -05:00
Robert McRackan
bce44b6f6d Fix string interpolation bugs 2022-11-14 15:16:22 -05:00
Robert McRackan
7575736991 Bugfix #389 : Handle corrupt cache file 2022-11-08 07:22:08 -05:00
Robert McRackan
06f8d055fc update dependencies 2022-11-02 16:24:14 -04:00
74 changed files with 1370 additions and 748 deletions

44
.github/workflows/dotnet-build.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
name: build
on:
workflow_call:
env:
DOTNET_CONFIGURATION: 'Release'
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
os: [Linux, MacOS, Windows]
ui: [Avalonia]
release_name: [chardonnay]
include:
- os: Windows
ui: WinForms
release_name: classic
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.x'
env:
NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build
working-directory: ./Source
run: |
dotnet publish -c ${{ env.DOTNET_CONFIGURATION }} -o bin\Publish\${{ matrix.os }}-${{ matrix.release_name }} Libation${{ matrix.ui }}\Libation${{ matrix.ui }}.csproj -p:PublishProfile=Libation${{ matrix.ui }}\Properties\PublishProfiles\${{ matrix.os }}Profile.pubxml
dotnet publish -c ${{ env.DOTNET_CONFIGURATION }} -o bin\Publish\${{ matrix.os }}-${{ matrix.release_name }} LoadByOS\${{ matrix.os }}ConfigApp\${{ matrix.os }}ConfigApp.csproj -p:PublishProfile=LoadByOS\Properties\${{ matrix.os }}ConfigApp\PublishProfiles\${{ matrix.os }}Profile.pubxml
dotnet publish -c ${{ env.DOTNET_CONFIGURATION }} -o bin\Publish\${{ matrix.os }}-${{ matrix.release_name }} LibationCli\LibationCli.csproj -p:PublishProfile=LibationCli\Properties\PublishProfiles\${{ matrix.os }}Profile.pubxml
dotnet publish -c ${{ env.DOTNET_CONFIGURATION }} -o bin\Publish\${{ matrix.os }}-${{ matrix.release_name }} Hangover${{ matrix.ui }}\Hangover${{ matrix.ui }}.csproj -p:PublishProfile=Hangover${{ matrix.ui }}\Properties\PublishProfiles\${{ matrix.os }}Profile.pubxml
- name: Publish artifact
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.os }}-${{ matrix.release_name }}
path: ./Source/bin/Publish/${{ matrix.os }}-${{ matrix.release_name }}/*
if-no-files-found: error

66
.github/workflows/dotnet-release.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
name: release
on:
push:
tags:
- 'v*'
env:
DOTNET_VERSION: '7' # The .NET SDK version to use
DOTNET_SOURCE: './Source'
DOTNET_CONFIGURATION: 'Release'
jobs:
build:
uses: ./.github/workflows/dotnet-build.yml
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Calculate version
id: version
run: |
export TAG=${{ github.ref_name }}
echo "version=${TAG#v}" >> $GITHUB_OUTPUT
- name: Download artifacts
uses: actions/download-artifact@v3
with:
path: artifacts
- name: Rename artifacts
id: rename
working-directory: ./artifacts
run: |
for FILENAME in *; do mv ${FILENAME} Libation.${{ steps.version.outputs.version }}-${FILENAME,,}; done
mv Libation.${{ steps.version.outputs.version }}-windows-classic Classic-Libation.${{ steps.version.outputs.version }}-windows-classic
- name: Zip assets
working-directory: ./artifacts
run: |
for FILENAME in *; do zip -r ${FILENAME}.zip ${FILENAME}; done
mkdir ./assets
mv *.zip ./assets
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: Libation ${{ steps.version.outputs.version }}
body: <Put a body here>
draft: true
prerelease: false
- name: Upload release assets
uses: dwenegar/upload-release-assets@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
release_id: ${{ steps.create_release.outputs.id }}
assets_path: ./artifacts/assets

19
.github/workflows/dotnet-validate.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
name: validate
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
DOTNET_VERSION: '7' # The .NET SDK version to use
DOTNET_SLN: './Source/Libation.sln'
DOTNET_CONFIGURATION: 'Release'
jobs:
build:
uses: ./.github/workflows/dotnet-build.yml

View File

@@ -1,6 +1,6 @@
{
"WindowsClassic": "Libation\\.\\d+\\.\\d+\\.\\d+-win-classic\\.zip",
"WindowsAvalonia":"Libation\\.\\d+\\.\\d+\\.\\d+-win-chardonnay\\.zip",
"WindowsClassic": "Libation\\.\\d+\\.\\d+\\.\\d+-windows-classic\\.zip",
"WindowsAvalonia":"Libation\\.\\d+\\.\\d+\\.\\d+-windows-chardonnay\\.zip",
"LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay",
"MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macos-chardonnay"
}

View File

@@ -71,4 +71,15 @@ export library to file
libationcli export -p "C:\foo\bar\my.csv" -c
libationcli export -p "C:\foo\bar\my.xlsx" --xlsx
libationcli export -p "C:\foo\bar\my.xlsx" -x
Set download statuses throughout library based on whether each book's audio file can be found.
Must include at least one flag: --downloaded , --not-downloaded.
Downloaded: If the audio file can be found, set download status to 'Downloaded'.
Not Downloaded: If the audio file cannot be found, set download status to 'Not Downloaded'
UI: Visible Books \> Set 'Downloaded' status automatically. Visible books. Prompts before saving changes
CLI: Full library. No prompt
libationcli set-status -d
libationcli set-status -n
libationcli set-status -d -n
```

View File

@@ -24,7 +24,7 @@
* Windows
Extract the zip file to a folder and then run `Libation.exe` from inside of that folder.
Extract the zip file to a folder and then run `Libation.exe` from inside of that folder. Do not put it in Program Files. The inability to edit files from there causes problems with configuration and updating.
* [Ubuntu Linux (beta)](InstallOnLinux.md)
* [MacOS (beta)](InstallOnMac.md)

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Version>8.5.0.1</Version>
<TargetFramework>net7.0</TargetFramework>
<Version>8.6.4.1</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Octokit" Version="4.0.0" />
<PackageReference Include="Octokit" Version="4.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ApplicationServices\ApplicationServices.csproj" />

View File

@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="29.0.0" />
<PackageReference Include="NPOI" Version="2.5.6" />
<PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="NPOI" Version="2.6.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DataLayer;
using Dinah.Core;
using LibationFileManager;
namespace ApplicationServices
{
public class BulkSetDownloadStatus
{
private List<(string message, LiberatedStatus newStatus, IEnumerable<Book> Books)> actionSets { get; } = new();
public int Count => actionSets.Count;
public IEnumerable<string> Messages => actionSets.Select(a => a.message);
public string AggregateMessage => $"Are you sure you want to set {Messages.Aggregate((a, b) => $"{a} and {b}")}?";
private List<LibraryBook> _libraryBooks;
private bool _setDownloaded;
private bool _setNotDownloaded;
public BulkSetDownloadStatus(List<LibraryBook> libraryBooks, bool setDownloaded, bool setNotDownloaded)
{
_libraryBooks = libraryBooks;
_setDownloaded = setDownloaded;
_setNotDownloaded = setNotDownloaded;
}
public int Discover()
{
var bookExistsList = _libraryBooks
.Select(libraryBook => new
{
libraryBook.Book,
FileExists = AudibleFileStorage.Audio.GetPath(libraryBook.Book.AudibleProductId) is not null
})
.ToList();
if (_setDownloaded)
{
var books2change = bookExistsList
.Where(a => a.FileExists && a.Book.UserDefinedItem.BookStatus != LiberatedStatus.Liberated)
.Select(a => a.Book)
.ToList();
if (books2change.Any())
actionSets.Add((
$"{"book".PluralizeWithCount(books2change.Count)} to 'Downloaded'",
LiberatedStatus.Liberated,
books2change));
}
if (_setNotDownloaded)
{
var books2change = bookExistsList
.Where(a => !a.FileExists && a.Book.UserDefinedItem.BookStatus != LiberatedStatus.NotLiberated)
.Select(a => a.Book)
.ToList();
if (books2change.Any())
actionSets.Add((
$"{"book".PluralizeWithCount(books2change.Count)} to 'Not Downloaded'",
LiberatedStatus.NotLiberated,
books2change));
}
return Count;
}
public void Execute()
{
foreach (var a in actionSets)
a.Books.UpdateBookStatus(a.newStatus);
}
}
}

View File

@@ -9,6 +9,7 @@ using Dinah.Core;
using DtoImporterService;
using LibationFileManager;
using Serilog;
using static System.Reflection.Metadata.BlobBuilder;
using static DtoImporterService.PerfLogger;
namespace ApplicationServices
@@ -366,74 +367,101 @@ namespace ApplicationServices
public static event EventHandler<IEnumerable<Book>> BookUserDefinedItemCommitted;
#region Update book details
public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus)
{
book.UserDefinedItem.BookStatus = bookStatus;
return UpdateUserDefinedItem(book);
}
public static int UpdatePdfStatus(this Book book, LiberatedStatus pdfStatus)
{
book.UserDefinedItem.PdfStatus = pdfStatus;
return UpdateUserDefinedItem(book);
}
public static int UpdateBook(
public static int UpdateUserDefinedItem(
this Book book,
string tags = null,
LiberatedStatus? bookStatus = null,
LiberatedStatus? pdfStatus = null)
=> UpdateBooks(tags, bookStatus, pdfStatus, book);
public static int UpdateBooks(
=> new[] { book }.UpdateUserDefinedItem(tags, bookStatus, pdfStatus);
public static int UpdateUserDefinedItem(
this IEnumerable<Book> books,
string tags = null,
LiberatedStatus? bookStatus = null,
LiberatedStatus? pdfStatus = null,
params Book[] books)
LiberatedStatus? pdfStatus = null)
=> updateUserDefinedItem(
books,
udi => {
// blank tags are expected. null tags are not
if (tags is not null && udi.Tags != tags)
udi.Tags = tags;
if (bookStatus is not null && udi.BookStatus != bookStatus.Value)
udi.BookStatus = bookStatus.Value;
// even though PdfStatus is nullable, there's no case where we'd actually overwrite with null
if (pdfStatus is not null && udi.PdfStatus != pdfStatus.Value)
udi.PdfStatus = pdfStatus.Value;
});
public static int UpdateBookStatus(this Book book, LiberatedStatus bookStatus)
=> book.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdateBookStatus(this IEnumerable<Book> books, LiberatedStatus bookStatus)
=> books.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdateBookStatus(this LibraryBook libraryBook, LiberatedStatus bookStatus)
=> libraryBook.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdateBookStatus(this IEnumerable<LibraryBook> libraryBooks, LiberatedStatus bookStatus)
=> libraryBooks.UpdateUserDefinedItem(udi => udi.BookStatus = bookStatus);
public static int UpdatePdfStatus(this Book book, LiberatedStatus pdfStatus)
=> book.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdatePdfStatus(this IEnumerable<Book> books, LiberatedStatus pdfStatus)
=> books.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdatePdfStatus(this LibraryBook libraryBook, LiberatedStatus pdfStatus)
=> libraryBook.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdatePdfStatus(this IEnumerable<LibraryBook> libraryBooks, LiberatedStatus pdfStatus)
=> libraryBooks.UpdateUserDefinedItem(udi => udi.PdfStatus = pdfStatus);
public static int UpdateTags(this Book book, string tags)
=> book.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateTags(this IEnumerable<Book> books, string tags)
=> books.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateTags(this LibraryBook libraryBook, string tags)
=> libraryBook.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateTags(this IEnumerable<LibraryBook> libraryBooks, string tags)
=> libraryBooks.UpdateUserDefinedItem(udi => udi.Tags = tags);
public static int UpdateUserDefinedItem(this LibraryBook libraryBook, Action<UserDefinedItem> action)
=> libraryBook.Book.updateUserDefinedItem(action);
public static int UpdateUserDefinedItem(this IEnumerable<LibraryBook> libraryBooks, Action<UserDefinedItem> action)
=> libraryBooks.Select(lb => lb.Book).updateUserDefinedItem(action);
public static int UpdateUserDefinedItem(this Book book, Action<UserDefinedItem> action) => book.updateUserDefinedItem(action);
public static int UpdateUserDefinedItem(this IEnumerable<Book> books, Action<UserDefinedItem> action) => books.updateUserDefinedItem(action);
private static int updateUserDefinedItem(this Book book, Action<UserDefinedItem> action) => new[] { book }.updateUserDefinedItem(action);
private static int updateUserDefinedItem(this IEnumerable<Book> books, Action<UserDefinedItem> action)
{
foreach (var book in books)
{
// blank tags are expected. null tags are not
if (tags is not null && book.UserDefinedItem.Tags != tags)
book.UserDefinedItem.Tags = tags;
try
{
if (books is null || !books.Any())
return 0;
if (bookStatus is not null && book.UserDefinedItem.BookStatus != bookStatus.Value)
book.UserDefinedItem.BookStatus = bookStatus.Value;
// even though PdfStatus is nullable, there's no case where we'd actually overwrite with null
if (pdfStatus is not null && book.UserDefinedItem.PdfStatus != pdfStatus.Value)
book.UserDefinedItem.PdfStatus = pdfStatus.Value;
}
return UpdateUserDefinedItem(books);
}
public static int UpdateUserDefinedItem(params Book[] books) => UpdateUserDefinedItem(books.ToList());
public static int UpdateUserDefinedItem(IEnumerable<Book> books)
{
try
{
if (books is null || !books.Any())
return 0;
using var context = DbContexts.GetContext();
// Attach() NoTracking entities before SaveChanges()
foreach (var book in books)
context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
action?.Invoke(book.UserDefinedItem);
var qtyChanges = context.SaveChanges();
if (qtyChanges > 0)
BookUserDefinedItemCommitted?.Invoke(null, books);
using var context = DbContexts.GetContext();
return qtyChanges;
}
catch (Exception ex)
{
Log.Logger.Error(ex, $"Error updating {nameof(Book.UserDefinedItem)}");
throw;
}
}
#endregion
// Attach() NoTracking entities before SaveChanges()
foreach (var book in books)
context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
// must be here instead of in db layer due to AaxcExists
public static LiberatedStatus Liberated_Status(Book book)
var qtyChanges = context.SaveChanges();
if (qtyChanges > 0)
BookUserDefinedItemCommitted?.Invoke(null, books);
return qtyChanges;
}
catch (Exception ex)
{
Log.Logger.Error(ex, $"Error updating {nameof(Book.UserDefinedItem)}");
throw;
}
}
#endregion
// must be here instead of in db layer due to AaxcExists
public static LiberatedStatus Liberated_Status(Book book)
=> book.Audio_Exists() ? book.UserDefinedItem.BookStatus
: AudibleFileStorage.AaxcExists(book.AudibleProductId) ? LiberatedStatus.PartialDownload
: LiberatedStatus.NotLiberated;

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AudibleApi" Version="4.6.5.1" />
<PackageReference Include="AudibleApi" Version="7.0.0.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
@@ -10,14 +10,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="5.2.1.1" />
<PackageReference Include="Dinah.EntityFrameworkCore" Version="5.0.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.10">
<PackageReference Include="Dinah.Core" Version="7.0.0.2" />
<PackageReference Include="Dinah.EntityFrameworkCore" Version="7.0.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.10">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="5.2.1.1" />
<PackageReference Include="Dinah.Core" Version="7.0.0.2" />
<PackageReference Include="Polly" Version="7.2.3" />
</ItemGroup>

View File

@@ -212,25 +212,23 @@ namespace FileManager
{
var foundFiles = Enumerable.Empty<LongPath>();
if (searchOption == SearchOption.AllDirectories)
try
{
try
if (searchOption == SearchOption.AllDirectories)
{
IEnumerable <LongPath> subDirs = Directory.EnumerateDirectories(path).Select(p => (LongPath)p);
IEnumerable<LongPath> subDirs = Directory.EnumerateDirectories(path).Select(p => (LongPath)p);
// Add files in subdirectories recursively to the list
foreach (string dir in subDirs)
foundFiles = foundFiles.Concat(SaferEnumerateFiles(dir, searchPattern, searchOption));
}
catch (UnauthorizedAccessException) { }
catch (PathTooLongException) { }
}
try
{
// Add files from the current directory
foundFiles = foundFiles.Concat(Directory.EnumerateFiles(path, searchPattern).Select(f => (LongPath)f));
}
catch (UnauthorizedAccessException) { }
catch (PathTooLongException) { }
// Symbolic links will result in DirectoryNotFoundException. Ohter logical directories might also. Just skip them. Don't want to risk (or have to handle) infinite recursion
catch (DirectoryNotFoundException) { }
return foundFiles;
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<!--Avalonia doesen't support TrimMode=link currently,but we are working on that https://github.com/AvaloniaUI/Avalonia/issues/6892 -->
<TrimMode>copyused</TrimMode>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
@@ -68,7 +68,7 @@
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.18" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\linux-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\macos-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\win-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>hangover.ico</ApplicationIcon>
<ImplicitUsings>enable</ImplicitUsings>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\classic</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -50,7 +50,7 @@ namespace LibationAvalonia.Dialogs
protected override void SaveAndClose()
{
LibraryBook.Book.UpdateBook(NewTags, bookStatus: BookLiberatedStatus, pdfStatus: PdfLiberatedStatus);
LibraryBook.Book.UpdateUserDefinedItem(NewTags, bookStatus: BookLiberatedStatus, pdfStatus: PdfLiberatedStatus);
base.SaveAndClose();
}

View File

@@ -0,0 +1,53 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchAutoDialog"
Title="Liberated status: Whether the book has been downloaded"
MinHeight="100" MaxHeight="165"
MinWidth="600" MaxWidth="800"
WindowStartupLocation="CenterOwner"
Icon="/Assets/libation.ico">
<Grid RowDefinitions="Auto,Auto,Auto">
<StackPanel
Grid.Row="0"
Orientation="Horizontal">
<CheckBox
Margin="0,0,0,10"
IsChecked="{Binding SetDownloaded, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="If the audio file can be found, set download status to 'Downloaded'" />
</CheckBox>
</StackPanel>
<StackPanel
Grid.Row="1"
Orientation="Horizontal">
<CheckBox
Margin="0,0,0,10"
IsChecked="{Binding SetNotDownloaded, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="If the audio file cannot be found, set download status to 'Not Downloaded'" />
</CheckBox>
</StackPanel>
<Button
Grid.Row="2"
Padding="30,0,30,0"
Margin="10,0,10,10"
HorizontalAlignment="Right"
Height="25"
Content="Save"
Click="SaveButton_Clicked"/>
</Grid>
</Window>

View File

@@ -0,0 +1,23 @@
using Avalonia.Markup.Xaml;
namespace LibationAvalonia.Dialogs
{
public partial class LiberatedStatusBatchAutoDialog : DialogWindow
{
public bool SetDownloaded { get; set; }
public bool SetNotDownloaded { get; set; }
public LiberatedStatusBatchAutoDialog()
{
InitializeComponent();
DataContext = this;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void SaveButton_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> SaveAndClose();
}
}

View File

@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchDialog"
x:Class="LibationAvalonia.Dialogs.LiberatedStatusBatchManualDialog"
Title="Liberated status: Whether the book has been downloaded"
MinWidth="400" MinHeight="120"
MaxWidth="400" MaxHeight="120"

View File

@@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace LibationAvalonia.Dialogs
{
public partial class LiberatedStatusBatchDialog : DialogWindow
public partial class LiberatedStatusBatchManualDialog : DialogWindow
{
private class liberatedComboBoxItem
{
@@ -34,7 +34,7 @@ namespace LibationAvalonia.Dialogs
new liberatedComboBoxItem { Status = LiberatedStatus.NotLiberated, Text = "Not Downloaded" },
};
public LiberatedStatusBatchDialog()
public LiberatedStatusBatchManualDialog()
{
InitializeComponent();
SelectedItem = BookStatuses[0] as liberatedComboBoxItem;

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<!--Avalonia doesen't support TrimMode=link currently,but we are working on that https://github.com/AvaloniaUI/Avalonia/issues/6892 -->
<TrimMode>copyused</TrimMode>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
@@ -92,6 +92,12 @@
</ItemGroup>
<ItemGroup>
<Compile Update="Dialogs\LiberatedStatusBatchAutoDialog.axaml.cs">
<DependentUpon>LiberatedStatusBatchAutoDialog.axaml</DependentUpon>
</Compile>
<Compile Update="Dialogs\LiberatedStatusBatchManualDialog.axaml.cs">
<DependentUpon>LiberatedStatusBatchManualDialog.axaml</DependentUpon>
</Compile>
<Compile Update="Views\ProcessBookControl.axaml.cs">
<DependentUpon>ProcessBookControl.axaml</DependentUpon>
</Compile>
@@ -129,7 +135,7 @@
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.18" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -102,7 +102,10 @@ Libation.
".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
public static async Task<DialogResult> ShowConfirmationDialog(Window owner, IEnumerable<LibraryBook> libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1)
/// <summary>
/// Note: the format field should use {0} and NOT use the `$` string interpolation. Formatting is done inside this method.
/// </summary>
public static async Task<DialogResult> ShowConfirmationDialog(Window owner, IEnumerable<LibraryBook> libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1)
{
if (libraryBooks is null || !libraryBooks.Any())
return DialogResult.Cancel;

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\linux-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\macos-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\win-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -247,7 +247,8 @@ namespace LibationAvalonia.ViewModels
var result = await MessageBox.ShowConfirmationDialog(
null,
libraryBooks,
$"Are you sure you want to remove {selectedBooks.Count} books from Libation's library?",
// do not use `$` string interpolation. See impl.
"Are you sure you want to remove {0} from Libation's library?",
"Remove books from Libation?");
if (result != DialogResult.Yes)

View File

@@ -1,6 +1,8 @@
using ApplicationServices;
using Avalonia.Threading;
using DataLayer;
using Dinah.Core;
using LibationFileManager;
using System;
using System.Linq;
using System.Threading.Tasks;
@@ -50,20 +52,19 @@ namespace LibationAvalonia.Views
var confirmationResult = await MessageBox.ShowConfirmationDialog(
this,
visibleLibraryBooks,
"Are you sure you want to replace tags in {0}?",
// do not use `$` string interpolation. See impl.
"Are you sure you want to replace tags in {0}?",
"Replace tags?");
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.Tags = dialog.NewTags;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
}
visibleLibraryBooks.UpdateTags(dialog.NewTags);
}
public async void setDownloadedToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
public async void setDownloadedManualToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{
var dialog = new Dialogs.LiberatedStatusBatchDialog();
var dialog = new Dialogs.LiberatedStatusBatchManualDialog();
var result = await dialog.ShowDialog<DialogResult>(this);
if (result != DialogResult.OK)
return;
@@ -73,25 +74,51 @@ namespace LibationAvalonia.Views
var confirmationResult = await MessageBox.ShowConfirmationDialog(
this,
visibleLibraryBooks,
"Are you sure you want to replace downloaded status in {0}?",
// do not use `$` string interpolation. See impl.
"Are you sure you want to replace downloaded status in {0}?",
"Replace downloaded status?");
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.BookStatus = dialog.BookLiberatedStatus;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
}
visibleLibraryBooks.UpdateBookStatus(dialog.BookLiberatedStatus);
}
public async void removeToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
public async void setDownloadedAutoToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{
var dialog = new Dialogs.LiberatedStatusBatchAutoDialog();
var result = await dialog.ShowDialog<DialogResult>(this);
if (result != DialogResult.OK)
return;
var bulkSetStatus = new BulkSetDownloadStatus(_viewModel.ProductsDisplay.GetVisibleBookEntries(), dialog.SetDownloaded, dialog.SetNotDownloaded);
var count = await Task.Run(() => bulkSetStatus.Discover());
if (count == 0)
return;
var confirmationResult = await MessageBox.Show(
bulkSetStatus.AggregateMessage,
"Replace downloaded status?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
if (confirmationResult != DialogResult.Yes)
return;
bulkSetStatus.Execute();
}
public async void removeToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{
var visibleLibraryBooks = _viewModel.ProductsDisplay.GetVisibleBookEntries();
var confirmationResult = await MessageBox.ShowConfirmationDialog(
this,
visibleLibraryBooks,
"Are you sure you want to remove {0} from Libation's library?",
// do not use `$` string interpolation. See impl.
"Are you sure you want to remove {0} from Libation's library?",
"Remove books from Libation?",
MessageBoxDefaultButton.Button2);

View File

@@ -110,7 +110,8 @@
</MenuItem.Styles>
<MenuItem Click="liberateVisible" Header="{Binding LiberateVisibleToolStripText_2}" IsEnabled="{Binding AnyVisibleNotLiberated}" />
<MenuItem Click="replaceTagsToolStripMenuItem_Click" Header="Replace _Tags..." />
<MenuItem Click="setDownloadedToolStripMenuItem_Click" Header="Set '_Downloaded' status..." />
<MenuItem Click="setDownloadedManualToolStripMenuItem_Click" Header="Set '_Downloaded' status manually..." />
<MenuItem Click="setDownloadedAutoToolStripMenuItem_Click" Header="Set '_Downloaded' status automatically..." />
<MenuItem Click="removeToolStripMenuItem_Click" Header="_Remove from library..." />
</MenuItem>

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<PublishReadyToRun>true</PublishReadyToRun>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
@@ -44,7 +44,7 @@
<PackageReference Include="CommandLineParser" Version="2.9.1" />
</ItemGroup>
<Target Name="SpicNSpan" AfterTargets="Clean">
<Target Name="SpicNSpan" AfterTargets="Clean">
<!-- Remove obj folder -->
<RemoveDir Directories="$(BaseIntermediateOutputPath)" />
<!-- Remove bin folder -->

View File

@@ -8,7 +8,7 @@ using CommandLine;
namespace LibationCli
{
[Verb("export", HelpText = "Must include path and flag for export file type: --xlsx , --csv , --json]")]
[Verb("export", HelpText = "Must include path and flag for export file type: --xlsx , --csv , --json")]
public class ExportOptions : OptionsBase
{
[Option(shortName: 'p', longName: "path", Required = true, HelpText = "Path to save file to.")]

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ApplicationServices;
using AudibleUtilities;
using CommandLine;
namespace LibationCli
{
[Verb("set-status", HelpText = """
Set download statuses throughout library based on whether each book's audio file can be found.
Must include at least one flag: --downloaded , --not-downloaded.
Downloaded: If the audio file can be found, set download status to 'Downloaded'.
Not Downloaded: If the audio file cannot be found, set download status to 'Not Downloaded'
""")]
public class SetDownloadStatusOptions : OptionsBase
{
[Option(shortName: 'd', longName: "downloaded", Required = true)]
public bool SetDownloaded { get; set; }
[Option(shortName: 'n', longName: "not-downloaded", Required = true)]
public bool SetNotDownloaded { get; set; }
protected override async Task ProcessAsync()
{
var libraryBooks = DbContexts.GetLibrary_Flat_NoTracking();
var bulkSetStatus = new BulkSetDownloadStatus(libraryBooks, SetDownloaded, SetNotDownloaded);
await Task.Run(() => bulkSetStatus.Discover());
bulkSetStatus.Execute();
foreach (var msg in bulkSetStatus.Messages)
Console.WriteLine(msg);
}
}
}

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\linux-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\macos-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\win-chardonnay</PublishDir>
<PublishDir>..\bin\Publish\Windows-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -113,6 +113,5 @@ namespace LibationFileManager
public void Refresh() => BookDirectoryFiles.RefreshFiles();
public LongPath GetPath(string productId) => GetFilePath(productId);
}
}

View File

@@ -24,23 +24,24 @@ namespace LibationFileManager
static FilePathCache()
{
// load json into memory. if file doesn't exist, nothing to do. save() will create if needed
if (File.Exists(jsonFile))
{
var list = JsonConvert.DeserializeObject<List<CacheEntry>>(File.ReadAllText(jsonFile));
if (!File.Exists(jsonFile))
return;
// file exists but deser is null. this will never happen when file is healthy
if (list is null)
{
lock (locker)
{
Serilog.Log.Logger.Error("Error deserializing file. Wrong format. Possibly corrupt. Deleting file. {@DebugInfo}", new { jsonFile });
File.Delete(jsonFile);
return;
}
}
try
{
var list = JsonConvert.DeserializeObject<List<CacheEntry>>(File.ReadAllText(jsonFile));
if (list is null)
throw new NullReferenceException("File exists but deserialize is null. This will never happen when file is healthy.");
cache = new Cache<CacheEntry>(list);
}
cache = new Cache<CacheEntry>(list);
}
catch (Exception ex)
{
Serilog.Log.Logger.Error(ex, "Error deserializing file. Wrong format. Possibly corrupt. Deleting file. {@DebugInfo}", new { jsonFile });
lock (locker)
File.Delete(jsonFile);
return;
}
}
public static bool Exists(string id, FileType type) => GetFirstPath(id, type) is not null;

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
</ItemGroup>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
@@ -9,7 +9,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="LuceneNet303r2" Version="3.0.3.4" />
<PackageReference Include="LuceneNet303r2" Version="3.0.3.5" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,108 @@
namespace LibationWinForms.Dialogs
{
partial class LiberatedStatusBatchAutoDialog
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.setDownloadedCb = new System.Windows.Forms.CheckBox();
this.setNotDownloadedCb = new System.Windows.Forms.CheckBox();
this.okBtn = new System.Windows.Forms.Button();
this.cancelBtn = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// setDownloadedCb
//
this.setDownloadedCb.AutoSize = true;
this.setDownloadedCb.Location = new System.Drawing.Point(12, 12);
this.setDownloadedCb.Name = "setDownloadedCb";
this.setDownloadedCb.Size = new System.Drawing.Size(379, 19);
this.setDownloadedCb.TabIndex = 0;
this.setDownloadedCb.Text = "If the audio file can be found, set download status to \'Downloaded\'";
this.setDownloadedCb.UseVisualStyleBackColor = true;
//
// setNotDownloadedCb
//
this.setNotDownloadedCb.AutoSize = true;
this.setNotDownloadedCb.Location = new System.Drawing.Point(12, 37);
this.setNotDownloadedCb.Name = "setNotDownloadedCb";
this.setNotDownloadedCb.Size = new System.Drawing.Size(412, 19);
this.setNotDownloadedCb.TabIndex = 1;
this.setNotDownloadedCb.Text = "If the audio file cannot be found, set download status to \'Not Downloaded\'";
this.setNotDownloadedCb.UseVisualStyleBackColor = true;
//
// okBtn
//
this.okBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.okBtn.Location = new System.Drawing.Point(346, 79);
this.okBtn.Name = "okBtn";
this.okBtn.Size = new System.Drawing.Size(88, 27);
this.okBtn.TabIndex = 2;
this.okBtn.Text = "OK";
this.okBtn.UseVisualStyleBackColor = true;
this.okBtn.Click += new System.EventHandler(this.okBtn_Click);
//
// cancelBtn
//
this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cancelBtn.Location = new System.Drawing.Point(464, 79);
this.cancelBtn.Name = "cancelBtn";
this.cancelBtn.Size = new System.Drawing.Size(88, 27);
this.cancelBtn.TabIndex = 3;
this.cancelBtn.Text = "Cancel";
this.cancelBtn.UseVisualStyleBackColor = true;
//
// LiberatedStatusBatchAutoDialog
//
this.AcceptButton = this.okBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.cancelBtn;
this.ClientSize = new System.Drawing.Size(564, 118);
this.Controls.Add(this.cancelBtn);
this.Controls.Add(this.okBtn);
this.Controls.Add(this.setNotDownloadedCb);
this.Controls.Add(this.setDownloadedCb);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "LiberatedStatusBatchAutoDialog";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Liberated status: Scan for files";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.CheckBox setDownloadedCb;
private System.Windows.Forms.CheckBox setNotDownloadedCb;
private System.Windows.Forms.Button okBtn;
private System.Windows.Forms.Button cancelBtn;
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Windows.Forms;
namespace LibationWinForms.Dialogs
{
public partial class LiberatedStatusBatchAutoDialog : Form
{
public bool SetDownloaded { get; private set; }
public bool SetNotDownloaded { get; private set; }
public LiberatedStatusBatchAutoDialog()
{
InitializeComponent();
this.SetLibationIcon();
}
private void okBtn_Click(object sender, EventArgs e)
{
SetDownloaded = this.setDownloadedCb.Checked;
SetNotDownloaded = this.setNotDownloadedCb.Checked;
this.DialogResult = DialogResult.OK;
}
}
}

View File

@@ -1,6 +1,6 @@
namespace LibationWinForms.Dialogs
{
partial class LiberatedStatusBatchDialog
partial class LiberatedStatusBatchManualDialog
{
/// <summary>
/// Required designer variable.
@@ -72,7 +72,6 @@
this.cancelBtn.TabIndex = 9;
this.cancelBtn.Text = "Cancel";
this.cancelBtn.UseVisualStyleBackColor = true;
this.cancelBtn.Click += new System.EventHandler(this.cancelBtn_Click);
//
// saveBtn
//
@@ -86,7 +85,7 @@
this.saveBtn.UseVisualStyleBackColor = true;
this.saveBtn.Click += new System.EventHandler(this.saveBtn_Click);
//
// LiberatedStatusBatchDialog
// LiberatedStatusBatchManualDialog
//
this.AcceptButton = this.saveBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
@@ -101,7 +100,7 @@
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "LiberatedStatusBatchDialog";
this.Name = "LiberatedStatusBatchManualDialog";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Liberated status: Whether the book has been downloaded";

View File

@@ -8,7 +8,7 @@ using LibationFileManager;
namespace LibationWinForms.Dialogs
{
public partial class LiberatedStatusBatchDialog : Form
public partial class LiberatedStatusBatchManualDialog : Form
{
public LiberatedStatus BookLiberatedStatus { get; private set; }
@@ -19,7 +19,7 @@ namespace LibationWinForms.Dialogs
public override string ToString() => Text;
}
public LiberatedStatusBatchDialog()
public LiberatedStatusBatchManualDialog()
{
InitializeComponent();
this.SetLibationIcon();
@@ -35,11 +35,5 @@ namespace LibationWinForms.Dialogs
BookLiberatedStatus = ((liberatedComboBoxItem)this.bookLiberatedCb.SelectedItem).Status;
this.DialogResult = DialogResult.OK;
}
private void cancelBtn_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<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:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

File diff suppressed because it is too large Load Diff

View File

@@ -80,20 +80,19 @@ namespace LibationWinForms
var confirmationResult = MessageBoxLib.ShowConfirmationDialog(
visibleLibraryBooks,
// do not use `$` string interpolation. See impl.
"Are you sure you want to replace tags in {0}?",
"Replace tags?");
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.Tags = dialog.NewTags;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
}
visibleLibraryBooks.UpdateTags(dialog.NewTags);
}
private void setDownloadedToolStripMenuItem_Click(object sender, EventArgs e)
private void setDownloadedManualToolStripMenuItem_Click(object sender, EventArgs e)
{
var dialog = new LiberatedStatusBatchDialog();
var dialog = new LiberatedStatusBatchManualDialog();
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
return;
@@ -102,24 +101,50 @@ namespace LibationWinForms
var confirmationResult = MessageBoxLib.ShowConfirmationDialog(
visibleLibraryBooks,
$"Are you sure you want to replace downloaded status in {0}?",
// do not use `$` string interpolation. See impl.
"Are you sure you want to replace downloaded status in {0}?",
"Replace downloaded status?");
if (confirmationResult != DialogResult.Yes)
return;
foreach (var libraryBook in visibleLibraryBooks)
libraryBook.Book.UserDefinedItem.BookStatus = dialog.BookLiberatedStatus;
LibraryCommands.UpdateUserDefinedItem(visibleLibraryBooks.Select(lb => lb.Book));
}
visibleLibraryBooks.UpdateBookStatus(dialog.BookLiberatedStatus);
}
private async void removeToolStripMenuItem_Click(object sender, EventArgs e)
private async void setDownloadedAutoToolStripMenuItem_Click(object sender, EventArgs e)
{
var dialog = new LiberatedStatusBatchAutoDialog();
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
return;
var bulkSetStatus = new BulkSetDownloadStatus(productsDisplay.GetVisible(), dialog.SetDownloaded, dialog.SetNotDownloaded);
var count = await Task.Run(() => bulkSetStatus.Discover());
if (count == 0)
return;
var confirmationResult = MessageBox.Show(
bulkSetStatus.AggregateMessage,
"Replace downloaded status?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
if (confirmationResult != DialogResult.Yes)
return;
bulkSetStatus.Execute();
}
private async void removeToolStripMenuItem_Click(object sender, EventArgs e)
{
var visibleLibraryBooks = productsDisplay.GetVisible();
var confirmationResult = MessageBoxLib.ShowConfirmationDialog(
visibleLibraryBooks,
$"Are you sure you want to remove {0} from Libation's library?",
// do not use `$` string interpolation. See impl.
"Are you sure you want to remove {0} from Libation's library?",
"Remove books from Libation?");
if (confirmationResult != DialogResult.Yes)

View File

@@ -128,7 +128,7 @@ namespace LibationWinForms.GridView
/// <summary>Save edits to the database</summary>
public void Commit(string newTags, LiberatedStatus bookStatus, LiberatedStatus? pdfStatus)
// MVVM pass-through
=> Book.UpdateBook(newTags, bookStatus: bookStatus, pdfStatus: pdfStatus);
=> Book.UpdateUserDefinedItem(newTags, bookStatus: bookStatus, pdfStatus: pdfStatus);
#endregion

View File

@@ -109,7 +109,8 @@ namespace LibationWinForms.GridView
var libraryBooks = selectedBooks.Select(rge => rge.LibraryBook).ToList();
var result = MessageBoxLib.ShowConfirmationDialog(
libraryBooks,
$"Are you sure you want to remove {selectedBooks.Count} books from Libation's library?",
// do not use `$` string interpolation. See impl.
"Are you sure you want to remove {0} from Libation's library?",
"Remove books from Libation?");
if (result != DialogResult.Yes)

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>libation.ico</ApplicationIcon>
<AssemblyName>Libation</AssemblyName>
@@ -43,8 +43,8 @@
<ItemGroup>
<PackageReference Include="Autoupdater.NET.Official" Version="1.7.5" />
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="5.2.3.1" />
<PackageReference Include="Autoupdater.NET.Official" Version="1.7.6" />
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="7.0.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -64,6 +64,9 @@ Libation.
".Trim(), "Verbose logging enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
/// <summary>
/// Note: the format field should use {0} and NOT use the `$` string interpolation. Formatting is done inside this method.
/// </summary>
public static DialogResult ShowConfirmationDialog(IEnumerable<LibraryBook> libraryBooks, string format, string title)
{
if (libraryBooks is null || !libraryBooks.Any())

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\bin\Publish\classic</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<PublishReadyToRun>true</PublishReadyToRun>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\..\bin\Publish\linux-chardonnay</PublishDir>
<PublishDir>..\..\bin\Publish\Linux-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<PublishReadyToRun>true</PublishReadyToRun>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>

View File

@@ -6,9 +6,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>..\..\bin\Publish\macos-chardonnay</PublishDir>
<PublishDir>..\..\bin\Publish\MacOS-chardonnay</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -8,7 +8,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Platform>Any CPU</Platform>
<PublishDir>..\..\bin\Publish\classic</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<PublishReadyToRun>true</PublishReadyToRun>
@@ -32,7 +32,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="5.2.3.1" />
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="7.0.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -2,22 +2,24 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\bin\Debug</OutputPath>
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\bin\Debug</OutputPath>
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\bin\Release</OutputPath>
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\bin\Release</OutputPath>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="5.2.1.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="7.0.0.2" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>

View File

@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Moq" Version="4.18.3" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.0" />
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.0" />
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.0" />
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.0" />
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageReference Include="Moq" Version="4.18.3" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.0" />
<PackageReference Include="coverlet.collector" Version="3.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>