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}"> -