600 lines
No EOL
23 KiB
C#
600 lines
No EOL
23 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
using JD.Adobe.Service.API;
|
|
using Plume.Core.Logging;
|
|
using Plume.Interfaces.Services;
|
|
using Shuttle.Api.AfterEffectsDTO;
|
|
using Shuttle.Api.AfterEffectsDTO.Items;
|
|
using Shuttle.Api.AfterEffectsDTO.Render;
|
|
using Shuttle.Api.AfterEffectsDTO.UpdatedData;
|
|
using Shuttle.Api.CommunicationDTO;
|
|
using Shuttle.Api.ServerAPI;
|
|
using Shuttle.Servers;
|
|
using Shuttle.Servers.Managers.Items;
|
|
using Shuttle.Servers.Managers.Notifications;
|
|
|
|
namespace JD.Adobe.Service.Implementation
|
|
{
|
|
/// <summary>
|
|
/// Service to interact with After Effects.
|
|
/// </summary>
|
|
public class AfterEffectsService : AdobeService, IAfterEffectsService
|
|
{
|
|
private IAfterEffectsOperationExecutor _operationExecutor;
|
|
private IAfterEffectsItemsProvider _itemProvider;
|
|
private const int RootItemId = 0;
|
|
|
|
public AfterEffectsService(ILogger logger)
|
|
: base(logger, ServerConstants.ShuttleServerUrl)
|
|
{
|
|
}
|
|
|
|
protected override void InitializeImpl(IServiceContext context)
|
|
{
|
|
if (_isInitialized)
|
|
{
|
|
throw new InvalidOperationException($"{nameof(AdobeService)} is already initialized.");
|
|
}
|
|
|
|
_itemProvider = new AfterEffectsItemProvider(Logger, _clientManager, _asyncProvider);
|
|
_operationExecutor = new AfterEffectsOperationExecutor(Logger, _clientManager, _asyncProvider);
|
|
|
|
_isInitialized = true;
|
|
}
|
|
|
|
public override async Task<TargetAppInfo> StartNewInstance(AdobeApplicationType appType)
|
|
{
|
|
string requestToken = _asyncProvider.CreateResourceRequest("start-new-instance");
|
|
|
|
// define a local function to capture the token and avoid keeping a state in the service
|
|
void EnsureEmptyProject(TargetAppInfo targetAppInfo)
|
|
{
|
|
if (targetAppInfo.AppType != appType)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string currentFilePath = this.GetCurrentProjectFilePath(targetAppInfo).GetAwaiter().GetResult(); // make the call synchronously because the event itself will be raised in a Task
|
|
if (currentFilePath == string.Empty)
|
|
{
|
|
// the new instance just connected :)
|
|
_asyncProvider.DepositResource(requestToken, targetAppInfo);
|
|
}
|
|
else
|
|
{
|
|
Logger.Debug($"{targetAppInfo} connected but didn't have an empty project file: {currentFilePath}");
|
|
}
|
|
}
|
|
|
|
_clientManager.OnTargetConnection += EnsureEmptyProject;
|
|
|
|
try
|
|
{
|
|
if (!_adobeExecutableManager.TryStartNewInstance(appType))
|
|
{
|
|
throw new ArgumentException($"Couldn't start a new instance of {appType}. Are you sure this Adobe application is installed on your machine?");
|
|
}
|
|
|
|
int waitingTime = 60_000;
|
|
bool success = await _asyncProvider.Wait(requestToken, waitingTime);
|
|
if (!success)
|
|
{
|
|
throw new TimeoutException($"{appType} took more than {waitingTime}ms to launch and establish a connection. " +
|
|
$"You may need to disable the Home startup menu from Edit > Preferences > General.");
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_clientManager.OnTargetConnection -= EnsureEmptyProject;
|
|
}
|
|
|
|
TargetAppInfo startedAppInfo = _asyncProvider.GetResource<TargetAppInfo>(requestToken);
|
|
return startedAppInfo;
|
|
}
|
|
|
|
// TASKS
|
|
|
|
public async Task PurgeCache(TargetAppInfo target)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
await _operationExecutor.PurgeMemoryAsync(target.ConnectionId);
|
|
}
|
|
|
|
public async Task Save(TargetAppInfo target)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
await _operationExecutor.SaveProjectAsync(target.ConnectionId);
|
|
}
|
|
|
|
public async Task SaveAs(TargetAppInfo target, string filePath)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (string.IsNullOrEmpty(filePath))
|
|
{
|
|
throw new ArgumentException($"{nameof(filePath)} cannot be null or empty.", nameof(filePath));
|
|
}
|
|
|
|
await _operationExecutor.SaveProjectAsync(target.ConnectionId, filePath);
|
|
}
|
|
|
|
public async Task OpenProject(TargetAppInfo target, string projectFilePath)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (!File.Exists(projectFilePath))
|
|
{
|
|
throw new ArgumentException($"{nameof(projectFilePath)} doesn't exist at '{projectFilePath}'.");
|
|
}
|
|
|
|
await _operationExecutor.OpenProject(target.ConnectionId, projectFilePath);
|
|
}
|
|
|
|
public async Task ShowRenderWindow(TargetAppInfo target, bool show)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
await _operationExecutor.ShowRenderWindow(target.ConnectionId, show);
|
|
}
|
|
|
|
public async Task BeginUndoGroup(TargetAppInfo target, string undoGroupName)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (string.IsNullOrEmpty(undoGroupName))
|
|
{
|
|
throw new ArgumentException($"{nameof(undoGroupName)} cannot be null or empty.", nameof(undoGroupName));
|
|
}
|
|
|
|
await _operationExecutor.BeginUndoGroup(target.ConnectionId, undoGroupName);
|
|
}
|
|
|
|
public async Task EndUndoGroup(TargetAppInfo target)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
await _operationExecutor.EndUndoGroup(target.ConnectionId);
|
|
}
|
|
|
|
public async Task<string> GetCurrentProjectFilePath(TargetAppInfo target)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
string filename = await _itemProvider.GetCurrentFileAsync(target.ConnectionId);
|
|
return filename;
|
|
}
|
|
|
|
// GET ITEMS
|
|
|
|
public async Task<ICollection<Item>> GetItems(TargetAppInfo target)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
ICollection<Item> items = await _itemProvider.GetAllItemsAsync(target.ConnectionId);
|
|
return items;
|
|
}
|
|
|
|
public async Task<ICollection<Item>> GetSelectedItems(TargetAppInfo target)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
ICollection<Item> items = await _itemProvider.GetSelectedProjectItemsAsync(target.ConnectionId);
|
|
return items;
|
|
}
|
|
|
|
public async Task<RenderQueue> GetRenderQueue(TargetAppInfo target)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
RenderQueue renderQueue = await _itemProvider.GetRenderQueueAsync(target.ConnectionId);
|
|
return renderQueue;
|
|
}
|
|
|
|
public async Task<RenderQueueItem> GetRenderQueueItem(TargetAppInfo target, int index)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
RenderQueueItem renderQueueItem = await _itemProvider.GetRenderQueueItemAsync(target.ConnectionId, index);
|
|
return renderQueueItem;
|
|
}
|
|
|
|
public async Task<FolderItem> GetFolderItem(TargetAppInfo target, int folderId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
FolderItem folderItem = await _itemProvider.GetFolderItemAsync(target.ConnectionId, folderId);
|
|
return folderItem;
|
|
}
|
|
|
|
public async Task<CompItem> GetCompItem(TargetAppInfo target, int compositionId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
CompItem compItem = await _itemProvider.GetCompItemAsync(target.ConnectionId, compositionId);
|
|
return compItem;
|
|
}
|
|
|
|
public async Task<FootageItem> GetFootageItem(TargetAppInfo target, int footageId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
FootageItem footageItem = await _itemProvider.GetFootageItemAsync(target.ConnectionId, footageId);
|
|
return footageItem;
|
|
}
|
|
|
|
|
|
// CREATE ITEMS
|
|
|
|
public async Task<FolderItem> AddFolder(TargetAppInfo target, string name)
|
|
{
|
|
return await AddFolder(target, name, RootItemId);
|
|
}
|
|
|
|
public async Task<FolderItem> AddFolder(TargetAppInfo target, string name, int parentFolderId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (name == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(name));
|
|
}
|
|
|
|
if (parentFolderId < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(parentFolderId), $"{nameof(parentFolderId)} must be non-negative.");
|
|
}
|
|
|
|
FolderItem folderItem = await _itemProvider.CreateFolderAsync(target.ConnectionId, name, parentFolderId);
|
|
return folderItem;
|
|
}
|
|
|
|
public async Task<CompItem> AddComp(TargetAppInfo target, string name, int width, int height, float pixelAspect, float duration, float frameRate)
|
|
{
|
|
return await AddComp(target, name, width, height, pixelAspect, duration, frameRate, RootItemId);
|
|
}
|
|
|
|
public async Task<CompItem> AddComp(TargetAppInfo target, string name, int width, int height, float pixelAspect, float duration, float frameRate, int parentFolderId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (name == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(name));
|
|
}
|
|
|
|
if (width < 0) throw new ArgumentOutOfRangeException(nameof(width), $"{nameof(width)} must be non-negative.");
|
|
if (height < 0) throw new ArgumentOutOfRangeException(nameof(height), $"{nameof(height)} must be non-negative.");
|
|
if (pixelAspect < 0) throw new ArgumentOutOfRangeException(nameof(pixelAspect), $"{nameof(pixelAspect)} must be non-negative.");
|
|
if (duration < 0) throw new ArgumentOutOfRangeException(nameof(duration), $"{nameof(duration)} must be non-negative.");
|
|
if (frameRate < 0) throw new ArgumentOutOfRangeException(nameof(frameRate), $"{nameof(frameRate)} must be non-negative.");
|
|
|
|
if (parentFolderId < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(parentFolderId), $"{nameof(parentFolderId)} must be non-negative.");
|
|
}
|
|
|
|
CompSettings settings = new CompSettings()
|
|
{
|
|
Width = width,
|
|
Height = height,
|
|
PixelAspect = pixelAspect,
|
|
Duration = duration,
|
|
FrameRate = frameRate
|
|
};
|
|
|
|
CompItem compItem = await _itemProvider.CreateCompAsync(target.ConnectionId, name, settings, parentFolderId);
|
|
return compItem;
|
|
}
|
|
|
|
public async Task<Item> ImportFile(TargetAppInfo target, string footageFilePath)
|
|
{
|
|
return await ImportFile(target, footageFilePath, RootItemId);
|
|
}
|
|
|
|
public async Task<Item> ImportFile(TargetAppInfo target, string footageFilePath, int parentFolderId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (!File.Exists(footageFilePath))
|
|
{
|
|
throw new ArgumentException($"{nameof(footageFilePath)} doesn't exist at '{footageFilePath}'.");
|
|
}
|
|
|
|
if (parentFolderId < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(parentFolderId), $"{nameof(parentFolderId)} must be non-negative.");
|
|
}
|
|
|
|
Item footageItem = await _itemProvider.CreateFootageAsync(target.ConnectionId, footageFilePath, parentFolderId);
|
|
return footageItem;
|
|
}
|
|
|
|
public async Task<RenderQueueItem> AddToRenderQueue(TargetAppInfo target, int compId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
if (compId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(compId), $"{nameof(compId)} must be strictly positive.");
|
|
}
|
|
|
|
RenderQueueItem renderQueueItem = await _itemProvider.AddToRenderQueue(target.ConnectionId, compId);
|
|
return renderQueueItem;
|
|
}
|
|
|
|
public async Task<Layer> AddNullLayer(TargetAppInfo target, int compId, string layerName)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
if (compId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(compId), $"{nameof(compId)} must be strictly positive.");
|
|
}
|
|
|
|
if (layerName == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(layerName));
|
|
}
|
|
|
|
Layer newLayer = await _itemProvider.AddNullLayerAsync(target.ConnectionId, compId, layerName);
|
|
return newLayer;
|
|
}
|
|
|
|
public async Task<Layer> AddLayer(TargetAppInfo target, int compId, int sourceItemId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
if (compId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(compId), $"{nameof(compId)} must be strictly positive.");
|
|
}
|
|
|
|
if (sourceItemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(sourceItemId), $"{nameof(sourceItemId)} must be strictly positive.");
|
|
}
|
|
|
|
Layer newLayer = await _itemProvider.AddLayerAsync(target.ConnectionId, compId, sourceItemId);
|
|
return newLayer;
|
|
}
|
|
|
|
|
|
// UPDATE ITEMS
|
|
|
|
public async Task<FolderItem> UpdateFolderItem(TargetAppInfo target, int folderItemId, FolderItemUpdatableData folderItemData)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (folderItemData == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(folderItemData));
|
|
}
|
|
|
|
if (folderItemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(folderItemId), $"{nameof(folderItemId)} must be strictly positive.");
|
|
}
|
|
|
|
FolderItem updatedFolderItem = await _itemProvider.UpdateFolderAsync(target.ConnectionId, folderItemId, folderItemData);
|
|
return updatedFolderItem;
|
|
}
|
|
|
|
public async Task<CompItem> UpdateCompItem(TargetAppInfo target, int compItemId, CompItemUpdatableData compItemData)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (compItemData == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(compItemData));
|
|
}
|
|
|
|
if (compItemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(compItemId), $"{nameof(compItemId)} must be strictly positive.");
|
|
}
|
|
|
|
CompItem updatedCompItem = await _itemProvider.UpdateCompAsync(target.ConnectionId, compItemId, compItemData);
|
|
return updatedCompItem;
|
|
}
|
|
|
|
public async Task<CompItem> CopyLayers(TargetAppInfo target, int sourceCompId, int targetCompId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
if (sourceCompId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(sourceCompId), $"{nameof(sourceCompId)} must be strictly positive.");
|
|
}
|
|
|
|
if (targetCompId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(targetCompId), $"{nameof(targetCompId)} must be strictly positive.");
|
|
}
|
|
|
|
CompItem updatedCompItem = await _itemProvider.CopyLayersAsync(target.ConnectionId, sourceCompId, targetCompId);
|
|
return updatedCompItem;
|
|
}
|
|
|
|
public async Task<CompItem> RemoveLayers(TargetAppInfo target, int compId, ICollection<string> layerNames)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
if (compId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(compId), $"{nameof(compId)} must be strictly positive.");
|
|
}
|
|
|
|
if (layerNames == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(layerNames));
|
|
}
|
|
|
|
if (layerNames.Count == 0)
|
|
{
|
|
return await _itemProvider.GetCompItemAsync(target.ConnectionId, compId);
|
|
}
|
|
|
|
CompItem updatedCompItem = await _itemProvider.RemoveLayersAsync(target.ConnectionId, compId, layerNames);
|
|
return updatedCompItem;
|
|
}
|
|
|
|
public async Task<FootageItem> UpdateFootageItem(TargetAppInfo target, int footageItemId, FootageItemUpdatableData footageItemData)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (footageItemData == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(footageItemData));
|
|
}
|
|
|
|
if (footageItemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(footageItemId), $"{nameof(footageItemId)} must be strictly positive.");
|
|
}
|
|
|
|
FootageItem updateFootageItem = await _itemProvider.UpdateFootageAsync(target.ConnectionId, footageItemId, footageItemData);
|
|
return updateFootageItem;
|
|
}
|
|
|
|
|
|
public async Task<FootageItem> ReplaceFootageSource(TargetAppInfo target, int footageId, string sourceFilePath)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (footageId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(footageId), $"{nameof(footageId)} must be strictly positive.");
|
|
}
|
|
|
|
if (!File.Exists(sourceFilePath))
|
|
{
|
|
throw new ArgumentException($"{nameof(sourceFilePath)} doesn't exist at '{sourceFilePath}'.");
|
|
}
|
|
|
|
FootageItem updateFootageItem = await _itemProvider.ReplaceFootageSourceAsync(target.ConnectionId, footageId, sourceFilePath);
|
|
return updateFootageItem;
|
|
}
|
|
|
|
public async Task<FootageItem> ReplaceFootageSourceWithSequence(TargetAppInfo target, int footageId, string firstSourceFilePath, bool forceAlphabetical)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (footageId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(footageId), $"{nameof(footageId)} must be strictly positive.");
|
|
}
|
|
|
|
if (!File.Exists(firstSourceFilePath))
|
|
{
|
|
throw new ArgumentException($"{nameof(firstSourceFilePath)} doesn't exist at '{firstSourceFilePath}'.");
|
|
}
|
|
|
|
FootageItem updateFootageItem = await _itemProvider.ReplaceFootageSourceWithSequenceAsync(target.ConnectionId, footageId, firstSourceFilePath, forceAlphabetical);
|
|
return updateFootageItem;
|
|
}
|
|
|
|
public async Task<RenderQueueItem> UpdateRenderQueueItem(TargetAppInfo target, int renderQueueItemId, RenderQueueItem renderQueueItem)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (renderQueueItem == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(renderQueueItem));
|
|
}
|
|
|
|
if (renderQueueItemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(renderQueueItemId), $"{nameof(renderQueueItemId)} must be strictly positive.");
|
|
}
|
|
|
|
RenderQueueItem updateRenderQueueItem = await _itemProvider.UpdateRenderQueueItem(target.ConnectionId, renderQueueItemId, renderQueueItem);
|
|
return updateRenderQueueItem;
|
|
}
|
|
|
|
public async Task<RenderQueueItem> ConfigureRenderQueueItem(TargetAppInfo target, int renderQueueItemIndex, string settingsTemplateName, string outputModuleTemplateName, string outputFilePath)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
if (renderQueueItemIndex <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(renderQueueItemIndex), $"{nameof(renderQueueItemIndex)} must be strictly positive (indexes start at 1).");
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(settingsTemplateName))
|
|
{
|
|
throw new ArgumentException($"{nameof(settingsTemplateName)} cannot be null or empty.", nameof(settingsTemplateName));
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(outputModuleTemplateName))
|
|
{
|
|
throw new ArgumentException($"{nameof(outputModuleTemplateName)} cannot be null or empty.", nameof(outputModuleTemplateName));
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(outputFilePath))
|
|
{
|
|
throw new ArgumentException($"{nameof(outputFilePath)} cannot be null or empty.", nameof(outputFilePath));
|
|
}
|
|
|
|
RenderQueueItem configuredRenderQueueItem = await _itemProvider.ConfigureRenderQueueItem(target.ConnectionId, renderQueueItemIndex, settingsTemplateName, outputModuleTemplateName, outputFilePath);
|
|
return configuredRenderQueueItem;
|
|
}
|
|
|
|
public async Task<Layer> UpdateLayer(TargetAppInfo target, int compId, int layerIndex, LayerUpdatableData layerData)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
|
|
if (compId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(compId), $"{nameof(compId)} must be strictly positive.");
|
|
}
|
|
|
|
if (layerIndex <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(layerIndex), $"{nameof(layerIndex)} must be strictly positive.");
|
|
}
|
|
|
|
if (layerData == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(layerData));
|
|
}
|
|
|
|
Layer updatedLayer = await _itemProvider.UpdateLayerAsync(target.ConnectionId, compId, layerIndex, layerData);
|
|
return updatedLayer;
|
|
}
|
|
|
|
public async Task<Item> SetParentFolderToRoot(TargetAppInfo target, int itemId)
|
|
{
|
|
return await SetParentFolder(target, itemId, RootItemId);
|
|
}
|
|
|
|
public async Task<Item> SetParentFolder(TargetAppInfo target, int itemId, int parentFolderId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (itemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(itemId), $"{nameof(itemId)} must be strictly positive.");
|
|
}
|
|
|
|
if (parentFolderId < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(parentFolderId), $"{nameof(parentFolderId)} must be non-negative.");
|
|
}
|
|
|
|
Item updateItem = await _itemProvider.SetParentAsync(target.ConnectionId, itemId, parentFolderId);
|
|
return updateItem;
|
|
}
|
|
|
|
public async Task<Item> RenameItem(TargetAppInfo target, int itemId, string newName)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (itemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(itemId), $"{nameof(itemId)} must be strictly positive.");
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(newName))
|
|
{
|
|
throw new ArgumentException($"{nameof(newName)} cannot be null or empty.", nameof(newName));
|
|
}
|
|
|
|
Item updateItem = await _itemProvider.RenameItem(target.ConnectionId, itemId, newName);
|
|
return updateItem;
|
|
}
|
|
|
|
|
|
// DELETE ITEMS
|
|
|
|
public async Task RemoveItem(TargetAppInfo target, int itemId)
|
|
{
|
|
ThrowIfUnknown(target);
|
|
if (itemId <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(itemId), $"{nameof(itemId)} must be strictly positive.");
|
|
}
|
|
|
|
await _itemProvider.RemoveItemFromProject(target.ConnectionId, itemId);
|
|
}
|
|
}
|
|
} |