diff --git a/src/ByteSync.Client/Assets/Resources/Resources.Designer.cs b/src/ByteSync.Client/Assets/Resources/Resources.Designer.cs
index 1d231fdac..008114591 100644
--- a/src/ByteSync.Client/Assets/Resources/Resources.Designer.cs
+++ b/src/ByteSync.Client/Assets/Resources/Resources.Designer.cs
@@ -2686,5 +2686,257 @@ public static string ConnectionStatus_Unkown {
return ResourceManager.GetString("ConnectionStatus_Unkown", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to The action cannot be applied to some items:.
+ ///
+ internal static string TargetedActionEditionGlobal_ActionIssues {
+ get {
+ return ResourceManager.GetString("TargetedActionEditionGlobal_ActionIssues", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Affected items:.
+ ///
+ internal static string TargetedActionEditionGlobal_AffectedItemsTooltip {
+ get {
+ return ResourceManager.GetString("TargetedActionEditionGlobal_AffectedItemsTooltip", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Target has analysis error.
+ ///
+ internal static string ValidationFailure_AtLeastOneTargetsHasAnalysisError {
+ get {
+ return ResourceManager.GetString("ValidationFailure_AtLeastOneTargetsHasAnalysisError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot delete item used elsewhere.
+ ///
+ internal static string ValidationFailure_CannotDeleteItemAlreadyUsedInAnotherAction {
+ get {
+ return ResourceManager.GetString("ValidationFailure_CannotDeleteItemAlreadyUsedInAnotherAction", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot operate on item being deleted.
+ ///
+ internal static string ValidationFailure_CannotOperateOnItemBeingDeleted {
+ get {
+ return ResourceManager.GetString("ValidationFailure_CannotOperateOnItemBeingDeleted", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot create files.
+ ///
+ internal static string ValidationFailure_CreateOperationOnFileNotAllowed {
+ get {
+ return ResourceManager.GetString("ValidationFailure_CreateOperationOnFileNotAllowed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Create requires directory target.
+ ///
+ internal static string ValidationFailure_CreateOperationRequiresDirectoryTarget {
+ get {
+ return ResourceManager.GetString("ValidationFailure_CreateOperationRequiresDirectoryTarget", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Destination already in use.
+ ///
+ internal static string ValidationFailure_DestinationAlreadyUsedByNonComplementaryAction {
+ get {
+ return ResourceManager.GetString("ValidationFailure_DestinationAlreadyUsedByNonComplementaryAction", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Destination conflicts with another action.
+ ///
+ internal static string ValidationFailure_DestinationCannotBeSourceOfAnotherAction {
+ get {
+ return ResourceManager.GetString("ValidationFailure_DestinationCannotBeSourceOfAnotherAction", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Destination required for create.
+ ///
+ internal static string ValidationFailure_DestinationRequiredForCreateOperation {
+ get {
+ return ResourceManager.GetString("ValidationFailure_DestinationRequiredForCreateOperation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Destination required for delete.
+ ///
+ internal static string ValidationFailure_DestinationRequiredForDeleteOperation {
+ get {
+ return ResourceManager.GetString("ValidationFailure_DestinationRequiredForDeleteOperation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Destination required for sync.
+ ///
+ internal static string ValidationFailure_DestinationRequiredForSynchronizeOperation {
+ get {
+ return ResourceManager.GetString("ValidationFailure_DestinationRequiredForSynchronizeOperation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Duplicate action not allowed.
+ ///
+ internal static string ValidationFailure_DuplicateActionNotAllowed {
+ get {
+ return ResourceManager.GetString("ValidationFailure_DuplicateActionNotAllowed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid source data.
+ ///
+ internal static string ValidationFailure_InvalidSourceCount {
+ get {
+ return ResourceManager.GetString("ValidationFailure_InvalidSourceCount", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot mix with do-nothing action.
+ ///
+ internal static string ValidationFailure_NonTargetedActionNotAllowedWithExistingDoNothingAction {
+ get {
+ return ResourceManager.GetString("ValidationFailure_NonTargetedActionNotAllowedWithExistingDoNothingAction", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Content already identical.
+ ///
+ internal static string ValidationFailure_NothingToCopyContentIdentical {
+ get {
+ return ResourceManager.GetString("ValidationFailure_NothingToCopyContentIdentical", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Content and date already identical.
+ ///
+ internal static string ValidationFailure_NothingToCopyContentAndDateIdentical {
+ get {
+ return ResourceManager.GetString("ValidationFailure_NothingToCopyContentAndDateIdentical", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Source conflicts with another action.
+ ///
+ internal static string ValidationFailure_SourceCannotBeDestinationOfAnotherAction {
+ get {
+ return ResourceManager.GetString("ValidationFailure_SourceCannotBeDestinationOfAnotherAction", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Source has analysis error.
+ ///
+ internal static string ValidationFailure_SourceHasAnalysisError {
+ get {
+ return ResourceManager.GetString("ValidationFailure_SourceHasAnalysisError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Source not allowed for create.
+ ///
+ internal static string ValidationFailure_SourceNotAllowedForCreateOperation {
+ get {
+ return ResourceManager.GetString("ValidationFailure_SourceNotAllowedForCreateOperation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Source not allowed for delete.
+ ///
+ internal static string ValidationFailure_SourceNotAllowedForDeleteOperation {
+ get {
+ return ResourceManager.GetString("ValidationFailure_SourceNotAllowedForDeleteOperation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Source required for sync.
+ ///
+ internal static string ValidationFailure_SourceRequiredForSynchronizeOperation {
+ get {
+ return ResourceManager.GetString("ValidationFailure_SourceRequiredForSynchronizeOperation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot sync directories.
+ ///
+ internal static string ValidationFailure_SynchronizeOperationOnDirectoryNotAllowed {
+ get {
+ return ResourceManager.GetString("ValidationFailure_SynchronizeOperationOnDirectoryNotAllowed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Target already exists.
+ ///
+ internal static string ValidationFailure_TargetAlreadyExistsForCreateOperation {
+ get {
+ return ResourceManager.GetString("ValidationFailure_TargetAlreadyExistsForCreateOperation", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Target file not found.
+ ///
+ internal static string ValidationFailure_TargetFileNotPresent {
+ get {
+ return ResourceManager.GetString("ValidationFailure_TargetFileNotPresent", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Target required for this operation.
+ ///
+ internal static string ValidationFailure_TargetRequiredForSynchronizeDateOrDelete {
+ get {
+ return ResourceManager.GetString("ValidationFailure_TargetRequiredForSynchronizeDateOrDelete", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to item:.
+ ///
+ internal static string ValidationFailure_ItemSingular {
+ get {
+ return ResourceManager.GetString("ValidationFailure_ItemSingular", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to items:.
+ ///
+ internal static string ValidationFailure_ItemPlural {
+ get {
+ return ResourceManager.GetString("ValidationFailure_ItemPlural", resourceCulture);
+ }
+ }
}
}
diff --git a/src/ByteSync.Client/Assets/Resources/Resources.fr.resx b/src/ByteSync.Client/Assets/Resources/Resources.fr.resx
index 90558c60a..abce0e595 100644
--- a/src/ByteSync.Client/Assets/Resources/Resources.fr.resx
+++ b/src/ByteSync.Client/Assets/Resources/Resources.fr.resx
@@ -1547,4 +1547,101 @@ Voulez-vous enregistrer ce nouveau Profil de Session avec ce nom ?
Ajouter un nouveau nœud de données à la session de synchronisation.
+
+
+
+ Impossible de synchroniser les dossiers
+
+
+ Impossible de créer des fichiers
+
+
+
+ Source requise pour la synchronisation
+
+
+ Source interdite pour la suppression
+
+
+ Source interdite pour la création
+
+
+
+ Destination requise pour la synchronisation
+
+
+ Destination requise pour la suppression
+
+
+ Destination requise pour la création
+
+
+
+ Données source invalides
+
+
+ Erreur d'analyse de la source
+
+
+
+ Fichier cible introuvable
+
+
+ Erreur d'analyse de la cible
+
+
+ Cible requise pour cette opération
+
+
+ La création nécessite un dossier cible
+
+
+ La cible existe déjà
+
+
+
+ Contenu et date déjà identiques
+
+
+ Contenu déjà identique
+
+
+
+ Impossible de mélanger avec une action "ne rien faire"
+
+
+
+ Source en conflit avec une autre action
+
+
+ Destination en conflit avec une autre action
+
+
+ Destination déjà utilisée
+
+
+
+ Impossible de supprimer un élément utilisé ailleurs
+
+
+ Impossible d'opérer sur un élément en cours de suppression
+
+
+
+ Action en double interdite
+
+
+
+ L'action ne peut pas être appliquée à certains éléments :
+
+
+ Éléments affectés :
+
+
+
+ élément :
+
+
+ éléments :
+
\ No newline at end of file
diff --git a/src/ByteSync.Client/Assets/Resources/Resources.resx b/src/ByteSync.Client/Assets/Resources/Resources.resx
index d9ce26d80..f2b09e239 100644
--- a/src/ByteSync.Client/Assets/Resources/Resources.resx
+++ b/src/ByteSync.Client/Assets/Resources/Resources.resx
@@ -1574,4 +1574,101 @@ Do you want to save this new Session Profile with this name?
Add a new data node to the synchronization session.
+
+
+
+ Cannot sync directories
+
+
+ Cannot create files
+
+
+
+ Source required for sync
+
+
+ Source not allowed for delete
+
+
+ Source not allowed for create
+
+
+
+ Destination required for sync
+
+
+ Destination required for delete
+
+
+ Destination required for create
+
+
+
+ Invalid source data
+
+
+ Source has analysis error
+
+
+
+ Target file not found
+
+
+ Target has analysis error
+
+
+ Target required for this operation
+
+
+ Create requires directory target
+
+
+ Target already exists
+
+
+
+ Content and date already identical
+
+
+ Content already identical
+
+
+
+ Cannot mix with do-nothing action
+
+
+
+ Source conflicts with another action
+
+
+ Destination conflicts with another action
+
+
+ Destination already in use
+
+
+
+ Cannot delete item used elsewhere
+
+
+ Cannot operate on item being deleted
+
+
+
+ Duplicate action not allowed
+
+
+
+ The action cannot be applied to some items:
+
+
+ Affected items:
+
+
+
+ item:
+
+
+ items:
+
\ No newline at end of file
diff --git a/src/ByteSync.Client/Business/Comparisons/AtomicActionConsistencyCheckCanAddResult.cs b/src/ByteSync.Client/Business/Comparisons/AtomicActionConsistencyCheckCanAddResult.cs
index de4f0098b..19d6f1f64 100644
--- a/src/ByteSync.Client/Business/Comparisons/AtomicActionConsistencyCheckCanAddResult.cs
+++ b/src/ByteSync.Client/Business/Comparisons/AtomicActionConsistencyCheckCanAddResult.cs
@@ -7,24 +7,38 @@ public class AtomicActionConsistencyCheckCanAddResult
public AtomicActionConsistencyCheckCanAddResult(ICollection comparisonItems)
{
ComparisonItems = comparisonItems;
-
- ValidComparisons = new HashSet();
-
- NonValidComparisons = new HashSet();
+ ValidationResults = new List();
}
public ICollection ComparisonItems { get; set; }
- public HashSet ValidComparisons { get; set; }
+ public List ValidationResults { get; set; }
+
+ public HashSet GetValidComparisonItems()
+ {
+ return ValidationResults.Where(r => r.IsValid).Select(r => r.ComparisonItem).ToHashSet();
+ }
+
+ public HashSet GetInvalidComparisonItems()
+ {
+ return ValidationResults.Where(r => !r.IsValid).Select(r => r.ComparisonItem).ToHashSet();
+ }
+
+ public List ValidValidations
+ {
+ get => ValidationResults.Where(r => r.IsValid).ToList();
+ }
- public HashSet NonValidComparisons { get; set; }
+ public List FailedValidations
+ {
+ get => ValidationResults.Where(r => !r.IsValid).ToList();
+ }
public bool IsOK
{
get
{
- bool isOK = ValidComparisons.Count == ComparisonItems.Count
- && NonValidComparisons.Count == 0
+ bool isOK = ValidationResults.All(r => r.IsValid)
&& ComparisonItems.Count != 0;
return isOK;
diff --git a/src/ByteSync.Client/Business/Comparisons/AtomicActionValidationFailureReason.cs b/src/ByteSync.Client/Business/Comparisons/AtomicActionValidationFailureReason.cs
new file mode 100644
index 000000000..cd825260f
--- /dev/null
+++ b/src/ByteSync.Client/Business/Comparisons/AtomicActionValidationFailureReason.cs
@@ -0,0 +1,48 @@
+namespace ByteSync.Business.Comparisons;
+
+public enum AtomicActionValidationFailureReason
+{
+ // Basic Consistency - Operation Type Compatibility
+ SynchronizeOperationOnDirectoryNotAllowed = 1,
+ CreateOperationOnFileNotAllowed = 2,
+
+ // Basic Consistency - Source Requirements
+ SourceRequiredForSynchronizeOperation = 10,
+ SourceNotAllowedForDeleteOperation = 11,
+ SourceNotAllowedForCreateOperation = 12,
+
+ // Basic Consistency - Destination Requirements
+ DestinationRequiredForSynchronizeOperation = 20,
+ DestinationRequiredForDeleteOperation = 21,
+ DestinationRequiredForCreateOperation = 22,
+
+ // Advanced Consistency - Source Issues
+ InvalidSourceCount = 30,
+ SourceHasAnalysisError = 31,
+
+ // Advanced Consistency - Target Issues
+ TargetFileNotPresent = 40,
+ AtLeastOneTargetsHasAnalysisError = 41,
+ TargetRequiredForSynchronizeDateOrDelete = 42,
+ CreateOperationRequiresDirectoryTarget = 43,
+ TargetAlreadyExistsForCreateOperation = 44,
+
+ // Advanced Consistency - Content Analysis
+ NothingToCopyContentAndDateIdentical = 50,
+ NothingToCopyContentIdentical = 51,
+
+ // Consistency Against Already Set Actions - Rule Conflicts
+ NonTargetedActionNotAllowedWithExistingDoNothingAction = 60,
+
+ // Consistency Against Already Set Actions - Source/Destination Conflicts
+ SourceCannotBeDestinationOfAnotherAction = 70,
+ DestinationCannotBeSourceOfAnotherAction = 71,
+ DestinationAlreadyUsedByNonComplementaryAction = 72,
+
+ // Consistency Against Already Set Actions - Delete Conflicts
+ CannotDeleteItemAlreadyUsedInAnotherAction = 80,
+ CannotOperateOnItemBeingDeleted = 81,
+
+ // Consistency Against Already Set Actions - Duplicate Actions
+ DuplicateActionNotAllowed = 90
+}
diff --git a/src/ByteSync.Client/Business/Comparisons/AtomicActionValidationResult.cs b/src/ByteSync.Client/Business/Comparisons/AtomicActionValidationResult.cs
new file mode 100644
index 000000000..ed19c9e50
--- /dev/null
+++ b/src/ByteSync.Client/Business/Comparisons/AtomicActionValidationResult.cs
@@ -0,0 +1,24 @@
+namespace ByteSync.Business.Comparisons;
+
+public class AtomicActionValidationResult
+{
+ private AtomicActionValidationResult(bool isValid, AtomicActionValidationFailureReason? failureReason)
+ {
+ IsValid = isValid;
+ FailureReason = failureReason;
+ }
+
+ public bool IsValid { get; }
+
+ public AtomicActionValidationFailureReason? FailureReason { get; }
+
+ public static AtomicActionValidationResult Success()
+ {
+ return new AtomicActionValidationResult(true, null);
+ }
+
+ public static AtomicActionValidationResult Failure(AtomicActionValidationFailureReason reason)
+ {
+ return new AtomicActionValidationResult(false, reason);
+ }
+}
diff --git a/src/ByteSync.Client/Business/Comparisons/ComparisonItemValidationResult.cs b/src/ByteSync.Client/Business/Comparisons/ComparisonItemValidationResult.cs
new file mode 100644
index 000000000..80ba52b43
--- /dev/null
+++ b/src/ByteSync.Client/Business/Comparisons/ComparisonItemValidationResult.cs
@@ -0,0 +1,24 @@
+using ByteSync.Models.Comparisons.Result;
+
+namespace ByteSync.Business.Comparisons;
+
+public class ComparisonItemValidationResult
+{
+ public ComparisonItemValidationResult(ComparisonItem comparisonItem, bool isValid)
+ {
+ ComparisonItem = comparisonItem;
+ IsValid = isValid;
+ FailureReason = null;
+ }
+
+ public ComparisonItemValidationResult(ComparisonItem comparisonItem, AtomicActionValidationFailureReason failureReason)
+ {
+ ComparisonItem = comparisonItem;
+ IsValid = false;
+ FailureReason = failureReason;
+ }
+
+ public ComparisonItem ComparisonItem { get; }
+ public bool IsValid { get; }
+ public AtomicActionValidationFailureReason? FailureReason { get; }
+}
diff --git a/src/ByteSync.Client/Business/Comparisons/DescriptionBuilderFactory.cs b/src/ByteSync.Client/Business/Comparisons/DescriptionBuilderFactory.cs
index 47ab65b95..885e02f3f 100644
--- a/src/ByteSync.Client/Business/Comparisons/DescriptionBuilderFactory.cs
+++ b/src/ByteSync.Client/Business/Comparisons/DescriptionBuilderFactory.cs
@@ -2,6 +2,7 @@
using ByteSync.Interfaces.Business.Actions;
using ByteSync.Interfaces.Converters;
using ByteSync.Interfaces.Factories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Services.Comparisons.DescriptionBuilders;
namespace ByteSync.Business.Comparisons;
diff --git a/src/ByteSync.Client/Business/Comparisons/ValidationFailureSummary.cs b/src/ByteSync.Client/Business/Comparisons/ValidationFailureSummary.cs
new file mode 100644
index 000000000..6c5d2c7f2
--- /dev/null
+++ b/src/ByteSync.Client/Business/Comparisons/ValidationFailureSummary.cs
@@ -0,0 +1,17 @@
+using ByteSync.Models.Comparisons.Result;
+
+namespace ByteSync.Business.Comparisons;
+
+public class ValidationFailureSummary
+{
+ public AtomicActionValidationFailureReason Reason { get; set; }
+
+ public int Count { get; set; }
+
+ public string LocalizedMessage { get; set; } = string.Empty;
+
+ public List AffectedItems { get; set; } = new();
+
+ public string AffectedItemsTooltip => string.Join("\n", AffectedItems.Select(item =>
+ item.PathIdentity.LinkingKeyValue));
+}
diff --git a/src/ByteSync.Client/Business/DataSources/DataSourceProxy.cs b/src/ByteSync.Client/Business/DataSources/DataSourceProxy.cs
index 4048824dd..4038b3698 100644
--- a/src/ByteSync.Client/Business/DataSources/DataSourceProxy.cs
+++ b/src/ByteSync.Client/Business/DataSources/DataSourceProxy.cs
@@ -5,6 +5,7 @@
using ByteSync.Common.Business.Inventories;
using ByteSync.Common.Interfaces;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/Factories/ViewModels/DateAndInventoryPartsViewModelFactory.cs b/src/ByteSync.Client/Factories/ViewModels/DateAndInventoryPartsViewModelFactory.cs
index e87d4b356..ba5829a8c 100644
--- a/src/ByteSync.Client/Factories/ViewModels/DateAndInventoryPartsViewModelFactory.cs
+++ b/src/ByteSync.Client/Factories/ViewModels/DateAndInventoryPartsViewModelFactory.cs
@@ -1,5 +1,6 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Factories.ViewModels;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ByteSync.Models.Inventories;
using ByteSync.ViewModels.Sessions.Comparisons.Results;
diff --git a/src/ByteSync.Client/Interfaces/Services/Localizations/IAtomicActionValidationFailureReasonService.cs b/src/ByteSync.Client/Interfaces/Services/Localizations/IAtomicActionValidationFailureReasonService.cs
new file mode 100644
index 000000000..39df38f4e
--- /dev/null
+++ b/src/ByteSync.Client/Interfaces/Services/Localizations/IAtomicActionValidationFailureReasonService.cs
@@ -0,0 +1,8 @@
+using ByteSync.Business.Comparisons;
+
+namespace ByteSync.Interfaces.Services.Localizations;
+
+public interface IAtomicActionValidationFailureReasonService
+{
+ string GetLocalizedMessage(AtomicActionValidationFailureReason reason);
+}
\ No newline at end of file
diff --git a/src/ByteSync.Client/Interfaces/ILocalizationService.cs b/src/ByteSync.Client/Interfaces/Services/Localizations/ILocalizationService.cs
similarity index 91%
rename from src/ByteSync.Client/Interfaces/ILocalizationService.cs
rename to src/ByteSync.Client/Interfaces/Services/Localizations/ILocalizationService.cs
index 5135ec908..da88a8f5e 100644
--- a/src/ByteSync.Client/Interfaces/ILocalizationService.cs
+++ b/src/ByteSync.Client/Interfaces/Services/Localizations/ILocalizationService.cs
@@ -2,7 +2,7 @@
using System.ComponentModel;
using ByteSync.Business;
-namespace ByteSync.Interfaces;
+namespace ByteSync.Interfaces.Services.Localizations;
public interface ILocalizationService : INotifyPropertyChanged
{
diff --git a/src/ByteSync.Client/Services/Bootstrappers/GraphicalUserInterfaceBootstrapper.cs b/src/ByteSync.Client/Services/Bootstrappers/GraphicalUserInterfaceBootstrapper.cs
index 40f12d1cf..d7a77c48c 100644
--- a/src/ByteSync.Client/Services/Bootstrappers/GraphicalUserInterfaceBootstrapper.cs
+++ b/src/ByteSync.Client/Services/Bootstrappers/GraphicalUserInterfaceBootstrapper.cs
@@ -9,6 +9,7 @@
using ByteSync.Interfaces.Controls.Themes;
using ByteSync.Interfaces.Announcements;
using ByteSync.Interfaces.Services.Communications;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Updates;
using Splat.Autofac;
diff --git a/src/ByteSync.Client/Services/Communications/WebAccessor.cs b/src/ByteSync.Client/Services/Communications/WebAccessor.cs
index 4712a56a8..e3450f244 100644
--- a/src/ByteSync.Client/Services/Communications/WebAccessor.cs
+++ b/src/ByteSync.Client/Services/Communications/WebAccessor.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Controls.Communications;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Communications;
diff --git a/src/ByteSync.Client/Services/Comparisons/AtomicActionConsistencyChecker.cs b/src/ByteSync.Client/Services/Comparisons/AtomicActionConsistencyChecker.cs
index 1c0193aea..e5621d159 100644
--- a/src/ByteSync.Client/Services/Comparisons/AtomicActionConsistencyChecker.cs
+++ b/src/ByteSync.Client/Services/Comparisons/AtomicActionConsistencyChecker.cs
@@ -28,13 +28,14 @@ public AtomicActionConsistencyCheckCanAddResult CheckCanAdd(AtomicAction atomicA
foreach (var comparisonItem in comparisonItems)
{
- if (CanApply(atomicAction, comparisonItem))
+ var validationResult = CanApply(atomicAction, comparisonItem);
+ if (validationResult.IsValid)
{
- result.ValidComparisons.Add(comparisonItem);
+ result.ValidationResults.Add(new ComparisonItemValidationResult(comparisonItem, true));
}
else
{
- result.NonValidComparisons.Add(comparisonItem);
+ result.ValidationResults.Add(new ComparisonItemValidationResult(comparisonItem, validationResult.FailureReason!.Value));
}
}
@@ -43,7 +44,7 @@ public AtomicActionConsistencyCheckCanAddResult CheckCanAdd(AtomicAction atomicA
public List GetApplicableActions(ICollection synchronizationRules)
{
- List appliableActions = new List();
+ List applicableActions = new List();
var allActions = new List();
foreach (var synchronizationRule in synchronizationRules)
@@ -55,103 +56,98 @@ public List GetApplicableActions(ICollection
if (doNothingAction != null)
{
// If one of the actions is a doNothing, we will only use that one
- appliableActions.Add(doNothingAction);
+ applicableActions.Add(doNothingAction);
}
else
{
// Otherwise, we look one by one
foreach (var atomicAction in allActions)
{
- if (CheckConsistencyAgainstAlreadySetActions(atomicAction, appliableActions))
+ if (CheckConsistencyAgainstAlreadySetActions(atomicAction, applicableActions).IsValid)
{
- appliableActions.Add(atomicAction);
+ applicableActions.Add(atomicAction);
}
}
}
- return appliableActions;
+ return applicableActions;
}
- private bool CanApply(AtomicAction atomicAction, ComparisonItem comparisonItem)
+ private AtomicActionValidationResult CanApply(AtomicAction atomicAction, ComparisonItem comparisonItem)
{
- var isBasicConsistencyOK = CheckBasicConsistency(atomicAction, comparisonItem);
- if (!isBasicConsistencyOK)
+ var basicConsistencyResult = CheckBasicConsistency(atomicAction, comparisonItem);
+ if (!basicConsistencyResult.IsValid)
{
- return false;
+ return basicConsistencyResult;
}
- var isAdvancedConsistencyOK = CheckAdvancedConsistency(atomicAction, comparisonItem);
- if (!isAdvancedConsistencyOK)
+ var advancedConsistencyResult = CheckAdvancedConsistency(atomicAction, comparisonItem);
+ if (!advancedConsistencyResult.IsValid)
{
- return false;
+ return advancedConsistencyResult;
}
- var isConsistencyAgainstAlreadySetActionsOK = CheckConsistencyAgainstAlreadySetActions(atomicAction, comparisonItem);
- if (!isConsistencyAgainstAlreadySetActionsOK)
+ var consistencyAgainstAlreadySetActionsResult = CheckConsistencyAgainstAlreadySetActions(atomicAction, comparisonItem);
+ if (!consistencyAgainstAlreadySetActionsResult.IsValid)
{
- return false;
+ return consistencyAgainstAlreadySetActionsResult;
}
- return true;
+ return AtomicActionValidationResult.Success();
}
- private bool CheckBasicConsistency(AtomicAction atomicAction, ComparisonItem comparisonItem)
+ private static AtomicActionValidationResult CheckBasicConsistency(AtomicAction atomicAction, ComparisonItem comparisonItem)
{
if (atomicAction.Operator.In(ActionOperatorTypes.SynchronizeContentAndDate, ActionOperatorTypes.SynchronizeContentOnly,
ActionOperatorTypes.SynchronizeDate))
{
if (comparisonItem.FileSystemType == FileSystemTypes.Directory)
{
- // These operators cannot be applied to a Directory
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.SynchronizeOperationOnDirectoryNotAllowed);
}
- // On a content and/or date copy, Source and Destination must be defined
if (atomicAction.Source == null)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.SourceRequiredForSynchronizeOperation);
}
if (atomicAction.Destination == null)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.DestinationRequiredForSynchronizeOperation);
}
}
else if (atomicAction.Operator == ActionOperatorTypes.DoNothing)
{
- // Do nothing: always OK
- return true;
+ // ReSharper disable once DuplicatedStatements
+ return AtomicActionValidationResult.Success();
}
else if (atomicAction.Operator == ActionOperatorTypes.Delete)
{
- // On a deletion, Source must always be null, Destination must always be defined
if (atomicAction.Source != null)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.SourceNotAllowedForDeleteOperation);
}
if (atomicAction.Destination == null)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.DestinationRequiredForDeleteOperation);
}
}
else if (atomicAction.Operator == ActionOperatorTypes.Create)
{
if (comparisonItem.FileSystemType == FileSystemTypes.File)
{
- // This operator cannot be applied to a File
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.CreateOperationOnFileNotAllowed);
}
- // On a creation, Source must always be null, Destination must always be defined
if (atomicAction.Source != null)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.SourceNotAllowedForCreateOperation);
}
if (atomicAction.Destination == null)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.DestinationRequiredForCreateOperation);
}
}
else
@@ -159,44 +155,37 @@ private bool CheckBasicConsistency(AtomicAction atomicAction, ComparisonItem com
throw new ApplicationException("AtomicActionConsistencyChecker: unknown action '{synchronizationAction.Action}'");
}
- return true;
+ return AtomicActionValidationResult.Success();
}
- private bool CheckAdvancedConsistency(AtomicAction atomicAction, ComparisonItem comparisonItem)
+ private static AtomicActionValidationResult CheckAdvancedConsistency(AtomicAction atomicAction, ComparisonItem comparisonItem)
{
if (atomicAction.Operator.In(ActionOperatorTypes.SynchronizeContentAndDate, ActionOperatorTypes.SynchronizeContentOnly,
ActionOperatorTypes.SynchronizeDate))
{
if (atomicAction.Source != null)
{
- // var contentIdentityViewsSource =
- // comparisonItemViewModel.GetContentIdentityViews(synchronizationAction.Source.GetAppliableInventory());
-
var sourceInventoryPart = atomicAction.Source.GetApplicableInventoryPart();
var contentIdentitiesSources = comparisonItem.GetContentIdentities(sourceInventoryPart);
if (contentIdentitiesSources.Count != 1)
{
- // No source or too many sources!
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.InvalidSourceCount);
}
var contentIdentitySource = contentIdentitiesSources.Single();
if (contentIdentitySource.HasAnalysisError)
{
- // If the source has an analysis error, we cannot proceed
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.SourceHasAnalysisError);
}
-
-
- var targetInventoryPart = atomicAction.Destination.GetApplicableInventoryPart();
+
+ var targetInventoryPart = atomicAction.Destination!.GetApplicableInventoryPart();
var contentIdentityViewsTargets = comparisonItem.GetContentIdentities(targetInventoryPart);
- // We cannot send to an InventoryPartTypes.File that is not present
if (contentIdentityViewsTargets.Count == 0 && targetInventoryPart.InventoryPartType == FileSystemTypes.File)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.TargetFileNotPresent);
}
if (contentIdentitySource.InventoryPartsByLastWriteTimes.Count == 1
@@ -206,61 +195,54 @@ private bool CheckAdvancedConsistency(AtomicAction atomicAction, ComparisonItem
&& ci.InventoryPartsByLastWriteTimes.Keys.Single()
.Equals(contentIdentitySource.InventoryPartsByLastWriteTimes.Keys.Single())))
{
- // In this case, the content is the same and there is only one date => there is nothing to copy
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.NothingToCopyContentAndDateIdentical);
}
- if (contentIdentityViewsTargets.Count > 0 && contentIdentityViewsTargets.All(t => t.HasAnalysisError))
+ if (contentIdentityViewsTargets.Count > 0 && contentIdentityViewsTargets.Any(t => t.HasAnalysisError))
{
- // If all targets have an analysis error, we cannot proceed
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.AtLeastOneTargetsHasAnalysisError);
}
- // If CopyContentOnly and no target or if a target with different content, it's OK
- // We invert the condition
if (atomicAction.IsSynchronizeContentOnly && contentIdentityViewsTargets.Count != 0 &&
contentIdentityViewsTargets.All(t => contentIdentitySource.Core!.Equals(t.Core!)))
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.NothingToCopyContentIdentical);
}
}
}
if (atomicAction.IsSynchronizeDate || atomicAction.IsDelete)
{
- var targetInventoryPart = atomicAction.Destination.GetApplicableInventoryPart();
+ var targetInventoryPart = atomicAction.Destination!.GetApplicableInventoryPart();
var contentIdentitiesTargets = comparisonItem.GetContentIdentities(targetInventoryPart);
if (contentIdentitiesTargets.Count == 0)
{
- // No destination, forbidden on a date or a deletion
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.TargetRequiredForSynchronizeDateOrDelete);
}
}
if (atomicAction.IsCreate)
{
- var targetInventoryPart = atomicAction.Destination.GetApplicableInventoryPart();
+ var targetInventoryPart = atomicAction.Destination!.GetApplicableInventoryPart();
- // We cannot do anything on a target of type InventoryPartTypes.File
if (targetInventoryPart.InventoryPartType == FileSystemTypes.File)
{
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.CreateOperationRequiresDirectoryTarget);
}
var contentIdentitiesTargets = comparisonItem.GetContentIdentities(targetInventoryPart);
if (contentIdentitiesTargets.Count != 0)
{
- // There is a destination, forbidden on a directory creation
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.TargetAlreadyExistsForCreateOperation);
}
}
- return true;
+ return AtomicActionValidationResult.Success();
}
- private bool CheckConsistencyAgainstAlreadySetActions(AtomicAction atomicAction, ComparisonItem comparisonItem)
+ private AtomicActionValidationResult CheckConsistencyAgainstAlreadySetActions(AtomicAction atomicAction, ComparisonItem comparisonItem)
{
List alreadySetAtomicActions = _atomicActionRepository.GetAtomicActions(comparisonItem);
@@ -274,34 +256,28 @@ private bool CheckConsistencyAgainstAlreadySetActions(AtomicAction atomicAction,
return CheckConsistencyAgainstAlreadySetActions(atomicAction, alreadySetAtomicActions);
}
- private bool CheckConsistencyAgainstAlreadySetActions(AtomicAction atomicAction, List alreadySetAtomicActions)
+ private AtomicActionValidationResult CheckConsistencyAgainstAlreadySetActions(AtomicAction atomicAction, List alreadySetAtomicActions)
{
if (alreadySetAtomicActions.Count == 0)
{
- return true;
+ return AtomicActionValidationResult.Success();
}
if (!atomicAction.IsTargeted && alreadySetAtomicActions.Any(a => a.IsDoNothing))
{
- // If the action is not Targeted and an action is already in DoNothing, we cannot register it
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.NonTargetedActionNotAllowedWithExistingDoNothingAction);
}
- // A source cannot be a destination
- // We cannot be a destination multiple times, but we can be a source multiple times
- // We cannot be deleted if we are the source or destination of another action
if (alreadySetAtomicActions.Any(ma =>
!atomicAction.IsDelete && // 16/02/2023: What is the purpose of this IsDelete?
Equals(ma.Destination, atomicAction.Source)))
{
- // A source cannot be the destination of another already registered action
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.SourceCannotBeDestinationOfAnotherAction);
}
if (alreadySetAtomicActions.Any(ma => Equals(ma.Source, atomicAction.Destination)))
{
- // A destination cannot be the source of another already registered action
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.DestinationCannotBeSourceOfAnotherAction);
}
if (alreadySetAtomicActions.Any(ma => Equals(ma.Destination, atomicAction.Destination)))
@@ -313,17 +289,12 @@ private bool CheckConsistencyAgainstAlreadySetActions(AtomicAction atomicAction,
if ((!alreadySetAtomicAction.IsSynchronizeDate || !atomicAction.IsSynchronizeContentOnly)
&& (!alreadySetAtomicAction.IsSynchronizeContentOnly || !atomicAction.IsSynchronizeDate))
{
- // We can be a destination multiple times if one is in IsSynchronizeDate and the other in IsSynchronizeContentOnly
- // Because they are complementary
-
- // Otherwise, it's not OK
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.DestinationAlreadyUsedByNonComplementaryAction);
}
}
else
{
- // We cannot be a destination multiple times => A destination cannot be the destination of another already registered action
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.DestinationAlreadyUsedByNonComplementaryAction);
}
}
@@ -332,24 +303,21 @@ private bool CheckConsistencyAgainstAlreadySetActions(AtomicAction atomicAction,
if (alreadySetAtomicActions.Any(ma =>
Equals(ma.Destination, atomicAction.Destination) || Equals(ma.Source, atomicAction.Destination)))
{
- // Impossible to register the deletion operation if the destination is already the source or destination of another action
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.CannotDeleteItemAlreadyUsedInAnotherAction);
}
}
if (alreadySetAtomicActions.Any(ma => ma.Operator == ActionOperatorTypes.Delete &&
(Equals(ma.Destination, atomicAction.Destination) || Equals(ma.Destination, atomicAction.Source))))
{
- // Impossible to register an operation if the Source or Destination are the destination of a deletion
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.CannotOperateOnItemBeingDeleted);
}
if (atomicAction.Operator != ActionOperatorTypes.DoNothing && alreadySetAtomicActions.Any(s => s.IsSimilarTo(atomicAction)))
{
- // Impossible to register a duplicate of an already registered action
- return false;
+ return AtomicActionValidationResult.Failure(AtomicActionValidationFailureReason.DuplicateActionNotAllowed);
}
- return true;
+ return AtomicActionValidationResult.Success();
}
}
\ No newline at end of file
diff --git a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AbstractDescriptionBuilder.cs b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AbstractDescriptionBuilder.cs
index 70e0597e4..f41f22280 100644
--- a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AbstractDescriptionBuilder.cs
+++ b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AbstractDescriptionBuilder.cs
@@ -2,6 +2,7 @@
using ByteSync.Assets.Resources;
using ByteSync.Common.Business.Actions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Comparisons.DescriptionBuilders;
diff --git a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicActionDescriptionBuilder.cs b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicActionDescriptionBuilder.cs
index 671171ed2..8ee76f8e1 100644
--- a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicActionDescriptionBuilder.cs
+++ b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicActionDescriptionBuilder.cs
@@ -2,6 +2,7 @@
using ByteSync.Common.Business.Actions;
using ByteSync.Common.Interfaces.Business;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Comparisons.DescriptionBuilders;
diff --git a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicConditionDescriptionBuilder.cs b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicConditionDescriptionBuilder.cs
index 71ee51c54..c9b9b0281 100644
--- a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicConditionDescriptionBuilder.cs
+++ b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/AtomicConditionDescriptionBuilder.cs
@@ -4,6 +4,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Business.Actions;
using ByteSync.Interfaces.Converters;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Comparisons.DescriptionBuilders;
diff --git a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedActionsGroupDescriptionBuilder.cs b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedActionsGroupDescriptionBuilder.cs
index b14978180..a9716433c 100644
--- a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedActionsGroupDescriptionBuilder.cs
+++ b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedActionsGroupDescriptionBuilder.cs
@@ -2,6 +2,7 @@
using ByteSync.Business.Actions.Shared;
using ByteSync.Common.Business.Actions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Comparisons.DescriptionBuilders;
diff --git a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedAtomicActionDescriptionBuilder.cs b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedAtomicActionDescriptionBuilder.cs
index 2f4ab53e2..24d9a6201 100644
--- a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedAtomicActionDescriptionBuilder.cs
+++ b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SharedAtomicActionDescriptionBuilder.cs
@@ -2,6 +2,7 @@
using ByteSync.Business.Actions.Shared;
using ByteSync.Common.Business.Actions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Comparisons.DescriptionBuilders;
diff --git a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SynchronizationRuleDescriptionBuilder.cs b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SynchronizationRuleDescriptionBuilder.cs
index ff46e44ba..d44ca81d6 100644
--- a/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SynchronizationRuleDescriptionBuilder.cs
+++ b/src/ByteSync.Client/Services/Comparisons/DescriptionBuilders/SynchronizationRuleDescriptionBuilder.cs
@@ -4,6 +4,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Business.Actions;
using ByteSync.Interfaces.Factories;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Comparisons.DescriptionBuilders;
diff --git a/src/ByteSync.Client/Services/Converters/BoolToDeploymentModeConverter.cs b/src/ByteSync.Client/Services/Converters/BoolToDeploymentModeConverter.cs
index f9a2e93b4..d4b34f0c1 100644
--- a/src/ByteSync.Client/Services/Converters/BoolToDeploymentModeConverter.cs
+++ b/src/ByteSync.Client/Services/Converters/BoolToDeploymentModeConverter.cs
@@ -4,6 +4,7 @@
using Avalonia.Data.Converters;
using ByteSync.Assets.Resources;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Converters;
diff --git a/src/ByteSync.Client/Services/Converters/ExecutionModeConverter.cs b/src/ByteSync.Client/Services/Converters/ExecutionModeConverter.cs
index aedd14851..7c5627989 100644
--- a/src/ByteSync.Client/Services/Converters/ExecutionModeConverter.cs
+++ b/src/ByteSync.Client/Services/Converters/ExecutionModeConverter.cs
@@ -3,6 +3,7 @@
using Avalonia.Controls;
using Avalonia.Data.Converters;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Converters;
diff --git a/src/ByteSync.Client/Services/Converters/FormatKbSizeConverter.cs b/src/ByteSync.Client/Services/Converters/FormatKbSizeConverter.cs
index 46075f8e8..d027c501d 100644
--- a/src/ByteSync.Client/Services/Converters/FormatKbSizeConverter.cs
+++ b/src/ByteSync.Client/Services/Converters/FormatKbSizeConverter.cs
@@ -6,6 +6,7 @@
using ByteSync.Common.Helpers;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Converters;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Converters;
diff --git a/src/ByteSync.Client/Services/Converters/ItemCountToLocalizedTextConverter.cs b/src/ByteSync.Client/Services/Converters/ItemCountToLocalizedTextConverter.cs
new file mode 100644
index 000000000..5e541bd81
--- /dev/null
+++ b/src/ByteSync.Client/Services/Converters/ItemCountToLocalizedTextConverter.cs
@@ -0,0 +1,50 @@
+using Avalonia.Controls;
+using Avalonia.Data.Converters;
+using Autofac;
+using ByteSync.Interfaces;
+using System.Globalization;
+using ByteSync.Interfaces.Services.Localizations;
+
+namespace ByteSync.Services.Converters;
+
+public class ItemCountToLocalizedTextConverter : IValueConverter
+{
+ private readonly ILocalizationService _localizationService;
+
+ // Constructor for DI (tests)
+ public ItemCountToLocalizedTextConverter(ILocalizationService localizationService)
+ {
+ _localizationService = localizationService;
+ }
+
+ // Parameterless constructor for XAML/Container resolution
+ public ItemCountToLocalizedTextConverter()
+ {
+ if (!Design.IsDesignMode)
+ {
+ _localizationService = ContainerProvider.Container.Resolve();
+ }
+ }
+
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (Design.IsDesignMode || _localizationService == null)
+ {
+ return "item:";
+ }
+
+ if (value is not int count)
+ {
+ // Fallback to singular form for invalid input
+ return _localizationService["ValidationFailure_ItemSingular"];
+ }
+
+ var key = count <= 1 ? "ValidationFailure_ItemSingular" : "ValidationFailure_ItemPlural";
+ return _localizationService[key];
+ }
+
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/ByteSync.Client/Services/Converters/LobbyMemberStatusConverter.cs b/src/ByteSync.Client/Services/Converters/LobbyMemberStatusConverter.cs
index 90818354d..27a9ea954 100644
--- a/src/ByteSync.Client/Services/Converters/LobbyMemberStatusConverter.cs
+++ b/src/ByteSync.Client/Services/Converters/LobbyMemberStatusConverter.cs
@@ -5,6 +5,7 @@
using ByteSync.Assets.Resources;
using ByteSync.Common.Business.Lobbies;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Converters;
diff --git a/src/ByteSync.Client/Services/Converters/LocalInventoryPartStatusToTextConverter.cs b/src/ByteSync.Client/Services/Converters/LocalInventoryPartStatusToTextConverter.cs
index f1b9ae0cf..7ee3da967 100644
--- a/src/ByteSync.Client/Services/Converters/LocalInventoryPartStatusToTextConverter.cs
+++ b/src/ByteSync.Client/Services/Converters/LocalInventoryPartStatusToTextConverter.cs
@@ -5,6 +5,7 @@
using ByteSync.Business.Inventories;
using ByteSync.Common.Helpers;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Converters;
diff --git a/src/ByteSync.Client/Services/Converters/ProfileTypeConverter.cs b/src/ByteSync.Client/Services/Converters/ProfileTypeConverter.cs
index c834b0582..768cc83ff 100644
--- a/src/ByteSync.Client/Services/Converters/ProfileTypeConverter.cs
+++ b/src/ByteSync.Client/Services/Converters/ProfileTypeConverter.cs
@@ -5,6 +5,7 @@
using ByteSync.Assets.Resources;
using ByteSync.Business.Profiles;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Converters;
diff --git a/src/ByteSync.Client/Services/Converters/SizeUnitConverter.cs b/src/ByteSync.Client/Services/Converters/SizeUnitConverter.cs
index aa8b588c9..093364490 100644
--- a/src/ByteSync.Client/Services/Converters/SizeUnitConverter.cs
+++ b/src/ByteSync.Client/Services/Converters/SizeUnitConverter.cs
@@ -4,6 +4,7 @@
using ByteSync.Common.Business.Misc;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Converters;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Converters;
diff --git a/src/ByteSync.Client/Services/Dialogs/MessageBoxViewModelFactory.cs b/src/ByteSync.Client/Services/Dialogs/MessageBoxViewModelFactory.cs
index ad09809af..ba1f30b58 100644
--- a/src/ByteSync.Client/Services/Dialogs/MessageBoxViewModelFactory.cs
+++ b/src/ByteSync.Client/Services/Dialogs/MessageBoxViewModelFactory.cs
@@ -1,5 +1,6 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Dialogs;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.ViewModels.Misc;
namespace ByteSync.Services.Dialogs;
diff --git a/src/ByteSync.Client/Services/Lobbies/LobbySynchronizationRuleViewModelFactory.cs b/src/ByteSync.Client/Services/Lobbies/LobbySynchronizationRuleViewModelFactory.cs
index a3de53902..86aba7350 100644
--- a/src/ByteSync.Client/Services/Lobbies/LobbySynchronizationRuleViewModelFactory.cs
+++ b/src/ByteSync.Client/Services/Lobbies/LobbySynchronizationRuleViewModelFactory.cs
@@ -3,6 +3,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Factories;
using ByteSync.Interfaces.Lobbies;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.ViewModels.Lobbies;
using CloudSessionProfileDetails = ByteSync.Business.Profiles.CloudSessionProfileDetails;
diff --git a/src/ByteSync.Client/Services/Localizations/AtomicActionValidationFailureReasonService.cs b/src/ByteSync.Client/Services/Localizations/AtomicActionValidationFailureReasonService.cs
new file mode 100644
index 000000000..44dfc70d7
--- /dev/null
+++ b/src/ByteSync.Client/Services/Localizations/AtomicActionValidationFailureReasonService.cs
@@ -0,0 +1,20 @@
+using ByteSync.Business.Comparisons;
+using ByteSync.Interfaces.Services.Localizations;
+
+namespace ByteSync.Services.Localizations;
+
+public class AtomicActionValidationFailureReasonService : IAtomicActionValidationFailureReasonService
+{
+ private readonly ILocalizationService _localizationService;
+
+ public AtomicActionValidationFailureReasonService(ILocalizationService localizationService)
+ {
+ _localizationService = localizationService;
+ }
+
+ public string GetLocalizedMessage(AtomicActionValidationFailureReason reason)
+ {
+ var key = $"ValidationFailure_{reason}";
+ return _localizationService[key];
+ }
+}
diff --git a/src/ByteSync.Client/Services/Localizations/LocExtension.cs b/src/ByteSync.Client/Services/Localizations/LocExtension.cs
index ad5f2b8a5..295c8d68c 100644
--- a/src/ByteSync.Client/Services/Localizations/LocExtension.cs
+++ b/src/ByteSync.Client/Services/Localizations/LocExtension.cs
@@ -5,6 +5,7 @@
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Services.Converters;
namespace ByteSync.Services.Localizations;
diff --git a/src/ByteSync.Client/Services/Localizations/LocalizationService.cs b/src/ByteSync.Client/Services/Localizations/LocalizationService.cs
index 5cdf465c4..b95e02d7a 100644
--- a/src/ByteSync.Client/Services/Localizations/LocalizationService.cs
+++ b/src/ByteSync.Client/Services/Localizations/LocalizationService.cs
@@ -9,6 +9,7 @@
using ByteSync.Business;
using ByteSync.Common.Helpers;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.Services.Localizations;
diff --git a/src/ByteSync.Client/ViewModels/AccountDetails/UsageStatisticsViewModel.cs b/src/ByteSync.Client/ViewModels/AccountDetails/UsageStatisticsViewModel.cs
index 4d62a15e5..9c8561b24 100644
--- a/src/ByteSync.Client/ViewModels/AccountDetails/UsageStatisticsViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/AccountDetails/UsageStatisticsViewModel.cs
@@ -8,6 +8,7 @@
using ByteSync.Common.Helpers;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Controls.Themes;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Services.Converters;
using ByteSync.ViewModels.Misc;
using LiveChartsCore;
diff --git a/src/ByteSync.Client/ViewModels/Announcements/AnnouncementViewModel.cs b/src/ByteSync.Client/ViewModels/Announcements/AnnouncementViewModel.cs
index 8cd38f8ef..5686d264b 100644
--- a/src/ByteSync.Client/ViewModels/Announcements/AnnouncementViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Announcements/AnnouncementViewModel.cs
@@ -3,6 +3,7 @@
using System.Reactive.Disposables;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Headers/ConnectionStatusViewModel.cs b/src/ByteSync.Client/ViewModels/Headers/ConnectionStatusViewModel.cs
index e88c1b83e..67d7e0943 100644
--- a/src/ByteSync.Client/ViewModels/Headers/ConnectionStatusViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Headers/ConnectionStatusViewModel.cs
@@ -7,6 +7,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Controls.Themes;
using ByteSync.Interfaces.Services.Communications;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Headers/HeaderViewModel.cs b/src/ByteSync.Client/ViewModels/Headers/HeaderViewModel.cs
index 72743999b..4fdbd18ba 100644
--- a/src/ByteSync.Client/ViewModels/Headers/HeaderViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Headers/HeaderViewModel.cs
@@ -10,6 +10,7 @@
using ByteSync.Interfaces.Dialogs;
using ByteSync.Interfaces.Factories.ViewModels;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.ViewModels.Misc;
using DynamicData;
using ReactiveUI;
diff --git a/src/ByteSync.Client/ViewModels/Headers/SoftwareVersionProxy.cs b/src/ByteSync.Client/ViewModels/Headers/SoftwareVersionProxy.cs
index f0d290f40..a8717cd72 100644
--- a/src/ByteSync.Client/ViewModels/Headers/SoftwareVersionProxy.cs
+++ b/src/ByteSync.Client/ViewModels/Headers/SoftwareVersionProxy.cs
@@ -1,6 +1,7 @@
using ByteSync.Assets.Resources;
using ByteSync.Common.Business.Versions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Services.Misc;
namespace ByteSync.ViewModels.Headers;
diff --git a/src/ByteSync.Client/ViewModels/Headers/UpdateDetailsViewModel.cs b/src/ByteSync.Client/ViewModels/Headers/UpdateDetailsViewModel.cs
index b2942f849..c4139fbeb 100644
--- a/src/ByteSync.Client/ViewModels/Headers/UpdateDetailsViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Headers/UpdateDetailsViewModel.cs
@@ -19,6 +19,7 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using ByteSync.Helpers;
+using ByteSync.Interfaces.Services.Localizations;
namespace ByteSync.ViewModels.Headers;
diff --git a/src/ByteSync.Client/ViewModels/Home/CreateCloudSessionViewModel.cs b/src/ByteSync.Client/ViewModels/Home/CreateCloudSessionViewModel.cs
index 49e8ed620..3094b2417 100644
--- a/src/ByteSync.Client/ViewModels/Home/CreateCloudSessionViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Home/CreateCloudSessionViewModel.cs
@@ -6,6 +6,7 @@
using ByteSync.Common.Business.Sessions.Cloud.Connections;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ByteSync.Interfaces.Services.Sessions.Connecting;
using ReactiveUI;
diff --git a/src/ByteSync.Client/ViewModels/Home/JoinCloudSessionViewModel.cs b/src/ByteSync.Client/ViewModels/Home/JoinCloudSessionViewModel.cs
index 187b60313..00927f3ea 100644
--- a/src/ByteSync.Client/ViewModels/Home/JoinCloudSessionViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Home/JoinCloudSessionViewModel.cs
@@ -8,6 +8,7 @@
using ByteSync.Common.Business.Sessions.Cloud.Connections;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions.Connecting;
using ByteSync.Interfaces.Services.Sessions.Connecting.Joining;
using ReactiveUI;
diff --git a/src/ByteSync.Client/ViewModels/Lobbies/LobbyMainViewModel.cs b/src/ByteSync.Client/ViewModels/Lobbies/LobbyMainViewModel.cs
index a84173867..d49f44b54 100644
--- a/src/ByteSync.Client/ViewModels/Lobbies/LobbyMainViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Lobbies/LobbyMainViewModel.cs
@@ -11,6 +11,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Factories.ViewModels;
using ByteSync.Interfaces.Lobbies;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Services.Lobbies;
using ByteSync.ViewModels.Sessions.Managing;
using ReactiveUI;
diff --git a/src/ByteSync.Client/ViewModels/Lobbies/LobbyMemberViewModel.cs b/src/ByteSync.Client/ViewModels/Lobbies/LobbyMemberViewModel.cs
index 2024adbda..45ec365a2 100644
--- a/src/ByteSync.Client/ViewModels/Lobbies/LobbyMemberViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Lobbies/LobbyMemberViewModel.cs
@@ -11,6 +11,7 @@
using ByteSync.Interfaces.Factories;
using ByteSync.Interfaces.Factories.Proxies;
using ByteSync.Interfaces.Lobbies;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Services.Lobbies;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Lobbies/LobbySynchronizationRuleViewModel.cs b/src/ByteSync.Client/ViewModels/Lobbies/LobbySynchronizationRuleViewModel.cs
index 83caf096d..a6a67845b 100644
--- a/src/ByteSync.Client/ViewModels/Lobbies/LobbySynchronizationRuleViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Lobbies/LobbySynchronizationRuleViewModel.cs
@@ -3,6 +3,7 @@
using ByteSync.Common.Business.Inventories;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Factories;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI.Fody.Helpers;
namespace ByteSync.ViewModels.Lobbies;
diff --git a/src/ByteSync.Client/ViewModels/Misc/ErrorViewModel.cs b/src/ByteSync.Client/ViewModels/Misc/ErrorViewModel.cs
index d429f484c..b105d3119 100644
--- a/src/ByteSync.Client/ViewModels/Misc/ErrorViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Misc/ErrorViewModel.cs
@@ -4,6 +4,7 @@
using ByteSync.Assets.Resources;
using ByteSync.Common.Helpers;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Misc/FlyoutContainerViewModel.cs b/src/ByteSync.Client/ViewModels/Misc/FlyoutContainerViewModel.cs
index ac6dc2030..5bfb094dd 100644
--- a/src/ByteSync.Client/ViewModels/Misc/FlyoutContainerViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Misc/FlyoutContainerViewModel.cs
@@ -8,6 +8,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Dialogs;
using ByteSync.Interfaces.Factories.ViewModels;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Misc/MessageBoxViewModel.cs b/src/ByteSync.Client/ViewModels/Misc/MessageBoxViewModel.cs
index 35b5417a7..e537b3881 100644
--- a/src/ByteSync.Client/ViewModels/Misc/MessageBoxViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Misc/MessageBoxViewModel.cs
@@ -4,6 +4,7 @@
using System.Threading.Tasks;
using ByteSync.Business;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Misc/SelectLocaleViewModel.cs b/src/ByteSync.Client/ViewModels/Misc/SelectLocaleViewModel.cs
index 121c0631a..27facccb5 100644
--- a/src/ByteSync.Client/ViewModels/Misc/SelectLocaleViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Misc/SelectLocaleViewModel.cs
@@ -4,6 +4,7 @@
using Avalonia.Controls.Mixins;
using ByteSync.Business;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/ImportRulesFromProfileViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/ImportRulesFromProfileViewModel.cs
index fd6ef070f..0f4274cf3 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/ImportRulesFromProfileViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/ImportRulesFromProfileViewModel.cs
@@ -3,7 +3,6 @@
using ByteSync.Assets.Resources;
using ByteSync.Business.Profiles;
using ByteSync.Common.Business.Sessions.Cloud;
-using ByteSync.Common.Helpers;
using ByteSync.Interfaces.Controls.Profiles;
using ByteSync.Interfaces.Lobbies;
using ByteSync.Interfaces.Profiles;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/SynchronizationRuleGlobalViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/SynchronizationRuleGlobalViewModel.cs
index d92a53d8c..4160ce3ad 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/SynchronizationRuleGlobalViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/SynchronizationRuleGlobalViewModel.cs
@@ -3,7 +3,6 @@
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
-using Avalonia.Controls.Mixins;
using ByteSync.Assets.Resources;
using ByteSync.Business.Actions.Local;
using ByteSync.Business.Sessions;
@@ -11,6 +10,7 @@
using ByteSync.Interfaces.Controls.Synchronizations;
using ByteSync.Interfaces.Dialogs;
using ByteSync.Interfaces.Factories.ViewModels;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ByteSync.ViewModels.Misc;
using ByteSync.ViewModels.Sessions.Comparisons.Actions.Misc;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/TargetedActionGlobalViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/TargetedActionGlobalViewModel.cs
index 19e33db41..d0a5e4fe8 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/TargetedActionGlobalViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Actions/TargetedActionGlobalViewModel.cs
@@ -3,7 +3,6 @@
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
-using Avalonia.Controls.Mixins;
using ByteSync.Assets.Resources;
using ByteSync.Business.Actions.Local;
using ByteSync.Business.Comparisons;
@@ -12,8 +11,10 @@
using ByteSync.Interfaces.Controls.Comparisons;
using ByteSync.Interfaces.Dialogs;
using ByteSync.Interfaces.Factories.ViewModels;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Models.Comparisons.Result;
using ByteSync.ViewModels.Misc;
+using ByteSync.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
@@ -28,8 +29,7 @@ public class TargetedActionGlobalViewModel : FlyoutElementViewModel
private readonly ITargetedActionsService _targetedActionsService;
private readonly IAtomicActionConsistencyChecker _atomicActionConsistencyChecker;
private readonly IActionEditViewModelFactory _actionEditViewModelFactory;
-
- public const string SYNCHRONIZATION_ACTION_PARAMETER = "SynchronizationAction";
+ private readonly IAtomicActionValidationFailureReasonService _failureReasonLocalizer;
public TargetedActionGlobalViewModel()
{
@@ -39,7 +39,8 @@ public TargetedActionGlobalViewModel()
public TargetedActionGlobalViewModel(List comparisonItems,
IDialogService dialogService, ILocalizationService localizationService,
ITargetedActionsService targetedActionsService, IAtomicActionConsistencyChecker atomicActionConsistencyChecker,
- IActionEditViewModelFactory actionEditViewModelFactory)
+ IActionEditViewModelFactory actionEditViewModelFactory,
+ IAtomicActionValidationFailureReasonService failureReasonLocalizer)
{
ComparisonItems = comparisonItems;
@@ -50,10 +51,13 @@ public TargetedActionGlobalViewModel(List comparisonItems,
_targetedActionsService = targetedActionsService;
_atomicActionConsistencyChecker = atomicActionConsistencyChecker;
_actionEditViewModelFactory = actionEditViewModelFactory;
+ _failureReasonLocalizer = failureReasonLocalizer;
+
+ // Initialize localized messages
+ ActionIssuesHeaderMessage = _localizationService[nameof(Resources.TargetedActionEditionGlobal_ActionIssues)];
+ AffectedItemsTooltipHeader = _localizationService[nameof(Resources.TargetedActionEditionGlobal_AffectedItemsTooltip)];
Actions = new ObservableCollection();
-
- // ComparisonResult = _sessionDataHolder.ComparisonResult;
var canSave = this
.WhenAnyValue(
@@ -114,7 +118,7 @@ public TargetedActionGlobalViewModel(List comparisonItems,
public bool CanEditAction => _canEditAction.Value;
[Reactive]
- public string SaveWarning { get; set; }
+ public string SaveWarning { get; set; } = string.Empty;
[Reactive]
public bool AreMissingFields { get; set; }
@@ -124,6 +128,14 @@ public TargetedActionGlobalViewModel(List comparisonItems,
[Reactive]
public bool IsInconsistentWithNoValidItems { get; set; }
+
+ public ObservableCollection FailureSummaries { get; set; } = new();
+
+ [Reactive]
+ public string ActionIssuesHeaderMessage { get; set; } = string.Empty;
+
+ [Reactive]
+ public string AffectedItemsTooltipHeader { get; set; } = string.Empty;
private void AddAction()
{
@@ -181,17 +193,12 @@ private void SaveValidItems()
ResetWarning();
- _targetedActionsService.AddTargetedAction(atomicAction, result.ValidComparisons);
+ _targetedActionsService.AddTargetedAction(atomicAction, result.GetValidComparisonItems());
_dialogService.CloseFlyout();
}
}
- private bool CanSave()
- {
- return !ShowWarning || !ShowSaveValidItemsCommand;
- }
-
private AtomicAction? Export()
{
var automaticActionsActionEditViewModel = Actions.Single(); // (AutomaticActionsActionEditViewModel)region.Views.Single();
@@ -262,6 +269,16 @@ private void Cancel()
private void OnLocaleChanged()
{
+ // Update localized messages when locale changes
+ ActionIssuesHeaderMessage = _localizationService[nameof(Resources.TargetedActionEditionGlobal_ActionIssues)];
+ AffectedItemsTooltipHeader = _localizationService[nameof(Resources.TargetedActionEditionGlobal_AffectedItemsTooltip)];
+
+ // Update localized messages in FailureSummaries if any
+ foreach (var summary in FailureSummaries)
+ {
+ summary.LocalizedMessage = _failureReasonLocalizer.GetLocalizedMessage(summary.Reason);
+ }
+
DoShowWarning();
}
@@ -270,18 +287,19 @@ private void ShowMissingFieldsWarning()
AreMissingFields = true;
IsInconsistentWithValidItems = null;
IsInconsistentWithNoValidItems = false;
+ FailureSummaries.Clear(); // Clear previous validation failure summaries
DoShowWarning();
}
private void ShowConsistencyWarning(AtomicActionConsistencyCheckCanAddResult checkCanAddResult)
{
- ShowSaveValidItemsCommand = checkCanAddResult.ValidComparisons.Count > 0;
+ ShowSaveValidItemsCommand = checkCanAddResult.GetValidComparisonItems().Count > 0;
if (ShowSaveValidItemsCommand)
{
- IsInconsistentWithValidItems = new Tuple(checkCanAddResult.ValidComparisons.Count,
- checkCanAddResult.NonValidComparisons.Count);
+ IsInconsistentWithValidItems = new Tuple(checkCanAddResult.GetValidComparisonItems().Count,
+ checkCanAddResult.GetInvalidComparisonItems().Count);
IsInconsistentWithNoValidItems = false;
}
else
@@ -290,6 +308,24 @@ private void ShowConsistencyWarning(AtomicActionConsistencyCheckCanAddResult che
IsInconsistentWithValidItems = null;
}
+ // Generate failure summaries with detailed information
+ FailureSummaries.Clear();
+ var summaries = checkCanAddResult.FailedValidations
+ .GroupBy(f => f.FailureReason!.Value)
+ .Select(g => new ValidationFailureSummary
+ {
+ Reason = g.Key,
+ Count = g.Count(),
+ LocalizedMessage = _failureReasonLocalizer.GetLocalizedMessage(g.Key),
+ AffectedItems = g.Select(f => f.ComparisonItem).ToList()
+ })
+ .OrderByDescending(s => s.Count); // Most frequent failures first
+
+ foreach (var summary in summaries)
+ {
+ FailureSummaries.Add(summary);
+ }
+
AreMissingFields = false;
DoShowWarning();
@@ -327,5 +363,6 @@ private void ResetWarning()
AreMissingFields = false;
IsInconsistentWithValidItems = null;
IsInconsistentWithNoValidItems = false;
+ FailureSummaries.Clear();
}
}
\ No newline at end of file
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/ComparisonResultViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/ComparisonResultViewModel.cs
index a8fc8d23b..fa712306c 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/ComparisonResultViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/ComparisonResultViewModel.cs
@@ -15,6 +15,7 @@
using ByteSync.Interfaces.Factories.ViewModels;
using ByteSync.Interfaces.Repositories;
using ByteSync.Interfaces.Services.Filtering;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ByteSync.Models.Comparisons.Result;
using ByteSync.ViewModels.Sessions.Comparisons.Results.Misc;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/ComparisonItemViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/ComparisonItemViewModel.cs
index e3f5fc13f..6d2dd197b 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/ComparisonItemViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/ComparisonItemViewModel.cs
@@ -9,6 +9,7 @@
using ByteSync.Interfaces.Converters;
using ByteSync.Interfaces.Factories.ViewModels;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Models.Comparisons.Result;
using ByteSync.Models.Inventories;
using DynamicData;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/DateAndInventoryPartsViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/DateAndInventoryPartsViewModel.cs
index be62d362b..cbdf42dfb 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/DateAndInventoryPartsViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/Misc/DateAndInventoryPartsViewModel.cs
@@ -3,6 +3,7 @@
using ByteSync.Business.Sessions;
using ByteSync.Common.Helpers;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ByteSync.Models.Inventories;
using ReactiveUI;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationActionViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationActionViewModel.cs
index da91c2396..d61a08c25 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationActionViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationActionViewModel.cs
@@ -7,6 +7,7 @@
using ByteSync.Interfaces.Controls.Comparisons;
using ByteSync.Interfaces.Controls.Synchronizations;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Services.Comparisons.DescriptionBuilders;
using ByteSync.ViewModels.Sessions.Comparisons.Results.Misc;
using ReactiveUI;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationRuleSummaryViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationRuleSummaryViewModel.cs
index d2fe3f2c7..36a041d31 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationRuleSummaryViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Comparisons/Results/SynchronizationRuleSummaryViewModel.cs
@@ -10,6 +10,7 @@
using ByteSync.Interfaces.Dialogs;
using ByteSync.Interfaces.Factories;
using ByteSync.Interfaces.Factories.ViewModels;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeHeaderViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeHeaderViewModel.cs
index 398c4812d..b85ca4a89 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeHeaderViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeHeaderViewModel.cs
@@ -12,6 +12,7 @@
using ByteSync.Interfaces.Controls.Inventories;
using ByteSync.Interfaces.Controls.Themes;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ByteSync.ViewModels.Misc;
using DynamicData;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeStatusViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeStatusViewModel.cs
index 1e27479f7..7bd1cf2ec 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeStatusViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/DataNodes/DataNodeStatusViewModel.cs
@@ -6,6 +6,7 @@
using ByteSync.Common.Business.Sessions;
using ByteSync.Interfaces;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Inventories/InventoryBeforeStartViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Inventories/InventoryBeforeStartViewModel.cs
index 4e0b33772..b9906bd00 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Inventories/InventoryBeforeStartViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Inventories/InventoryBeforeStartViewModel.cs
@@ -7,6 +7,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Controls.Inventories;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Managing/AnalysisModeViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Managing/AnalysisModeViewModel.cs
index 71e55e8a3..8081a5032 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Managing/AnalysisModeViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Managing/AnalysisModeViewModel.cs
@@ -1,5 +1,6 @@
using ByteSync.Business.Sessions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI.Fody.Helpers;
namespace ByteSync.ViewModels.Sessions.Managing;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Managing/DataTypeViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Managing/DataTypeViewModel.cs
index 69fab84a7..d1d60edc9 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Managing/DataTypeViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Managing/DataTypeViewModel.cs
@@ -1,5 +1,6 @@
using ByteSync.Business.Sessions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI.Fody.Helpers;
namespace ByteSync.ViewModels.Sessions.Managing;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Managing/LinkingKeyViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Managing/LinkingKeyViewModel.cs
index 49ab537a4..d4f559cd4 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Managing/LinkingKeyViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Managing/LinkingKeyViewModel.cs
@@ -1,6 +1,7 @@
using ByteSync.Assets.Resources;
using ByteSync.Business.Sessions;
using ByteSync.Interfaces;
+using ByteSync.Interfaces.Services.Localizations;
using ReactiveUI.Fody.Helpers;
namespace ByteSync.ViewModels.Sessions.Managing;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Managing/SessionSettingsEditViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Managing/SessionSettingsEditViewModel.cs
index 82742bcc5..807a511ec 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Managing/SessionSettingsEditViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Managing/SessionSettingsEditViewModel.cs
@@ -6,6 +6,7 @@
using ByteSync.Interfaces;
using ByteSync.Interfaces.Controls.Inventories;
using ByteSync.Interfaces.Factories.ViewModels;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
diff --git a/src/ByteSync.Client/ViewModels/Sessions/Synchronizations/SynchronizationMainViewModel.cs b/src/ByteSync.Client/ViewModels/Sessions/Synchronizations/SynchronizationMainViewModel.cs
index be60359eb..3365c5362 100644
--- a/src/ByteSync.Client/ViewModels/Sessions/Synchronizations/SynchronizationMainViewModel.cs
+++ b/src/ByteSync.Client/ViewModels/Sessions/Synchronizations/SynchronizationMainViewModel.cs
@@ -15,6 +15,7 @@
using ByteSync.Interfaces.Controls.TimeTracking;
using ByteSync.Interfaces.Dialogs;
using ByteSync.Interfaces.Repositories;
+using ByteSync.Interfaces.Services.Localizations;
using ByteSync.Interfaces.Services.Sessions;
using ByteSync.ViewModels.Misc;
using DynamicData;
diff --git a/src/ByteSync.Client/Views/Sessions/Comparisons/Actions/TargetedActionGlobalView.axaml b/src/ByteSync.Client/Views/Sessions/Comparisons/Actions/TargetedActionGlobalView.axaml
index 276c6d206..4ebb2e28a 100644
--- a/src/ByteSync.Client/Views/Sessions/Comparisons/Actions/TargetedActionGlobalView.axaml
+++ b/src/ByteSync.Client/Views/Sessions/Comparisons/Actions/TargetedActionGlobalView.axaml
@@ -6,6 +6,7 @@
xmlns:actions="clr-namespace:ByteSync.ViewModels.Sessions.Comparisons.Actions"
xmlns:misc="clr-namespace:ByteSync.Views.Misc"
xmlns:localizations="clr-namespace:ByteSync.Services.Localizations"
+ xmlns:converters="clr-namespace:ByteSync.Services.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
@@ -15,6 +16,10 @@
+
+
+
+
@@ -84,18 +89,55 @@
+ IsVisible="{Binding Path=ShowWarning}">
-