2025-01-10 12:28:29 +03:00
|
|
|
using System;
|
2025-01-11 20:39:58 +03:00
|
|
|
using System.Collections.Frozen;
|
|
|
|
|
using System.Collections.Generic;
|
2025-01-10 12:28:29 +03:00
|
|
|
using System.Collections.ObjectModel;
|
2025-01-12 15:15:01 +03:00
|
|
|
using System.Diagnostics;
|
2025-01-11 20:39:58 +03:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2025-01-12 15:15:01 +03:00
|
|
|
using System.IO;
|
2025-01-11 20:39:58 +03:00
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
2025-01-10 12:28:29 +03:00
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
2025-01-14 22:10:16 +03:00
|
|
|
using Nebula.Launcher.Services;
|
2025-03-12 14:51:47 +03:00
|
|
|
using Nebula.Launcher.ViewModels.ContentView;
|
2025-01-14 22:10:16 +03:00
|
|
|
using Nebula.Launcher.ViewModels.Popup;
|
2025-01-10 12:28:29 +03:00
|
|
|
using Nebula.Launcher.Views.Pages;
|
2025-03-14 17:08:35 +03:00
|
|
|
using Nebula.Shared.FileApis;
|
2025-01-10 12:28:29 +03:00
|
|
|
using Nebula.Shared.Models;
|
2025-01-11 20:39:58 +03:00
|
|
|
using Nebula.Shared.Services;
|
|
|
|
|
using Nebula.Shared.Utils;
|
2025-01-10 12:28:29 +03:00
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
namespace Nebula.Launcher.ViewModels.Pages;
|
2025-01-10 12:28:29 +03:00
|
|
|
|
|
|
|
|
[ViewModelRegister(typeof(ContentBrowserView))]
|
2025-01-14 22:10:16 +03:00
|
|
|
[ConstructGenerator]
|
2025-01-29 12:32:42 +03:00
|
|
|
public sealed partial class ContentBrowserViewModel : ViewModelBase , IViewModelPage
|
2025-01-10 12:28:29 +03:00
|
|
|
{
|
2025-01-11 20:39:58 +03:00
|
|
|
private readonly List<ContentEntry> _root = new();
|
|
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
private readonly List<string> _history = new();
|
|
|
|
|
|
2025-01-10 12:28:29 +03:00
|
|
|
[ObservableProperty] private string _message = "";
|
|
|
|
|
[ObservableProperty] private string _searchText = "";
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
private ContentEntry? _selectedEntry;
|
2025-01-14 22:10:16 +03:00
|
|
|
[ObservableProperty] private string _serverText = "";
|
2025-03-12 14:51:47 +03:00
|
|
|
[ObservableProperty] private ContentViewBase? _contentView;
|
|
|
|
|
public bool IsCustomContenView => ContentView != null;
|
|
|
|
|
|
|
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
[GenerateProperty] private ContentService ContentService { get; } = default!;
|
|
|
|
|
[GenerateProperty] private CancellationService CancellationService { get; } = default!;
|
|
|
|
|
[GenerateProperty] private FileService FileService { get; } = default!;
|
|
|
|
|
[GenerateProperty] private DebugService DebugService { get; } = default!;
|
|
|
|
|
[GenerateProperty] private PopupMessageService PopupService { get; } = default!;
|
|
|
|
|
[GenerateProperty] private HubService HubService { get; } = default!;
|
2025-03-14 17:08:35 +03:00
|
|
|
[GenerateProperty] private IServiceProvider ServiceProvider {get;}
|
2025-01-22 21:06:05 +03:00
|
|
|
[GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; } = default!;
|
2025-01-14 22:10:16 +03:00
|
|
|
|
|
|
|
|
public ObservableCollection<ContentEntry> Entries { get; } = new();
|
2025-01-11 20:39:58 +03:00
|
|
|
|
2025-03-12 14:51:47 +03:00
|
|
|
private Dictionary<string, Type> _contentContainers = new();
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
public ContentEntry? SelectedEntry
|
|
|
|
|
{
|
|
|
|
|
get => _selectedEntry;
|
|
|
|
|
set
|
|
|
|
|
{
|
2025-03-14 17:08:35 +03:00
|
|
|
var oldSearchText = SearchText;
|
2025-03-12 14:51:47 +03:00
|
|
|
SearchText = value?.GetPath().ToString() ?? "";
|
2025-03-14 17:08:35 +03:00
|
|
|
|
2025-03-12 14:51:47 +03:00
|
|
|
ContentView = null;
|
2025-03-14 17:08:35 +03:00
|
|
|
Entries.Clear();
|
|
|
|
|
_selectedEntry = value;
|
2025-03-12 14:51:47 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
if (value == null) return;
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
if(value.TryOpen(out var stream, out var item)){
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
var ext = Path.GetExtension(item.Value.Path);
|
|
|
|
|
var myTempFile = Path.Combine(Path.GetTempPath(), "tempie" + ext);
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
if(TryGetContentViewer(ext, out var contentViewBase)){
|
|
|
|
|
DebugService.Debug($"Opening custom context:{item.Value.Path}");
|
2025-03-14 18:32:20 +03:00
|
|
|
contentViewBase.InitialiseWithData(value.GetPath(), stream, value);
|
|
|
|
|
stream.Dispose();
|
2025-03-14 17:08:35 +03:00
|
|
|
ContentView = contentViewBase;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
var sw = new FileStream(myTempFile, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
|
|
|
stream.CopyTo(sw);
|
2025-01-12 15:15:01 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
sw.Dispose();
|
|
|
|
|
stream.Dispose();
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
var startInfo = new ProcessStartInfo(myTempFile)
|
|
|
|
|
{
|
|
|
|
|
UseShellExecute = true
|
|
|
|
|
};
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
|
|
|
|
|
DebugService.Log("Opening " + myTempFile);
|
|
|
|
|
Process.Start(startInfo);
|
2025-01-12 15:15:01 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(SearchText.Length > oldSearchText.Length)
|
|
|
|
|
AppendHistory(oldSearchText);
|
2025-01-14 22:10:16 +03:00
|
|
|
|
|
|
|
|
foreach (var (_, entryCh) in value.Childs) Entries.Add(entryCh);
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-12 14:51:47 +03:00
|
|
|
private bool TryGetContentViewer(string type,[NotNullWhen(true)] out ContentViewBase? contentViewBase){
|
|
|
|
|
contentViewBase = null;
|
|
|
|
|
if(!_contentContainers.TryGetValue(type, out var contentViewType) ||
|
|
|
|
|
!contentViewType.IsAssignableTo(typeof(ContentViewBase)))
|
|
|
|
|
return false;
|
|
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
contentViewBase = (ContentViewBase)ServiceProvider.GetService(contentViewType)!;
|
2025-03-12 14:51:47 +03:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-10 12:28:29 +03:00
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
protected override void InitialiseInDesignMode()
|
2025-01-10 12:28:29 +03:00
|
|
|
{
|
2025-03-14 17:08:35 +03:00
|
|
|
var a = new ContentEntry(this, "A:", "A", "", default!);
|
|
|
|
|
var b = new ContentEntry(this, "B", "B", "", default!);
|
2025-01-11 20:39:58 +03:00
|
|
|
a.TryAddChild(b);
|
2025-01-14 22:10:16 +03:00
|
|
|
Entries.Add(a);
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
protected override void Initialise()
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
FillRoot(HubService.ServerList);
|
|
|
|
|
|
|
|
|
|
HubService.HubServerChangedEventArgs += HubServerChangedEventArgs;
|
|
|
|
|
HubService.HubServerLoaded += GoHome;
|
|
|
|
|
|
|
|
|
|
if (!HubService.IsUpdating) GoHome();
|
2025-03-14 17:08:35 +03:00
|
|
|
|
|
|
|
|
_contentContainers.Add(".dll",typeof(DecompilerContentView));
|
2025-01-10 12:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
private void GoHome()
|
2025-01-10 12:28:29 +03:00
|
|
|
{
|
2025-01-11 20:39:58 +03:00
|
|
|
SelectedEntry = null;
|
2025-01-14 22:10:16 +03:00
|
|
|
foreach (var entry in _root) Entries.Add(entry);
|
2025-01-10 12:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
private void HubServerChangedEventArgs(HubServerChangedEventArgs obj)
|
|
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
if (obj.Action == HubServerChangeAction.Clear) _root.Clear();
|
|
|
|
|
if (obj.Action == HubServerChangeAction.Add) FillRoot(obj.Items);
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
2025-01-10 12:28:29 +03:00
|
|
|
|
2025-01-12 22:49:32 +03:00
|
|
|
private void FillRoot(IEnumerable<ServerHubInfo> infos)
|
|
|
|
|
{
|
2025-03-14 17:08:35 +03:00
|
|
|
foreach (var info in infos) _root.Add(new ContentEntry(this, info.StatusData.Name, info.Address, info.Address, default!));
|
2025-01-12 22:49:32 +03:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
public async void Go(ContentPath path)
|
2025-01-10 12:28:29 +03:00
|
|
|
{
|
2025-01-12 22:49:32 +03:00
|
|
|
if (path.Pathes.Count > 0 && (path.Pathes[0].StartsWith("ss14://") || path.Pathes[0].StartsWith("ss14s://")))
|
|
|
|
|
{
|
|
|
|
|
ServerText = path.Pathes[0];
|
2025-01-13 19:24:12 +03:00
|
|
|
path = new ContentPath("");
|
2025-01-12 22:49:32 +03:00
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-01-12 22:49:32 +03:00
|
|
|
if (string.IsNullOrEmpty(ServerText))
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
|
|
|
|
SearchText = "";
|
|
|
|
|
GoHome();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
|
|
|
|
if (ServerText != SelectedEntry?.ServerName) SelectedEntry = await CreateEntry(ServerText);
|
|
|
|
|
|
|
|
|
|
DebugService.Debug("Going to:" + path.Path);
|
|
|
|
|
|
2025-01-12 22:49:32 +03:00
|
|
|
var oriPath = path.Clone();
|
2025-01-11 20:39:58 +03:00
|
|
|
try
|
|
|
|
|
{
|
2025-01-12 22:49:32 +03:00
|
|
|
if (SelectedEntry == null || !SelectedEntry.GetRoot().TryGetEntry(path, out var centry))
|
2025-01-13 19:24:12 +03:00
|
|
|
throw new Exception("Not found! " + oriPath.Path);
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-01-12 15:15:01 +03:00
|
|
|
SelectedEntry = centry;
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
PopupService.Popup(e);
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void OnBackEnter()
|
|
|
|
|
{
|
2025-03-14 17:08:35 +03:00
|
|
|
Go(new ContentPath(GetHistory()));
|
2025-01-10 12:28:29 +03:00
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-01-10 12:28:29 +03:00
|
|
|
public void OnGoEnter()
|
|
|
|
|
{
|
2025-01-11 20:39:58 +03:00
|
|
|
Go(new ContentPath(SearchText));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<ContentEntry> CreateEntry(string serverUrl)
|
|
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
var loading = ViewHelperService.GetViewModel<LoadingContextViewModel>();
|
2025-01-11 20:39:58 +03:00
|
|
|
loading.LoadingName = "Loading entry";
|
2025-01-14 22:10:16 +03:00
|
|
|
PopupService.Popup(loading);
|
2025-03-12 14:51:47 +03:00
|
|
|
|
|
|
|
|
var rurl = serverUrl.ToRobustUrl();
|
|
|
|
|
var info = await ContentService.GetBuildInfo(rurl, CancellationService.Token);
|
2025-03-13 14:58:47 +03:00
|
|
|
var hashApi = await ContentService.EnsureItems(info.RobustManifestInfo, loading,
|
2025-01-14 22:10:16 +03:00
|
|
|
CancellationService.Token);
|
2025-01-11 20:39:58 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
var rootEntry = new ContentEntry(this, "", "", serverUrl, default!);
|
2025-01-11 20:39:58 +03:00
|
|
|
|
2025-03-13 14:58:47 +03:00
|
|
|
foreach (var item in hashApi.Manifest.Values)
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
|
|
|
|
var path = new ContentPath(item.Path);
|
2025-03-14 17:08:35 +03:00
|
|
|
rootEntry.CreateItem(path, item, hashApi);
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
loading.Dispose();
|
|
|
|
|
|
|
|
|
|
return rootEntry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AppendHistory(string str)
|
|
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
if (_history.Count >= 10) _history.RemoveAt(9);
|
2025-01-11 20:39:58 +03:00
|
|
|
_history.Insert(0, str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetHistory()
|
|
|
|
|
{
|
|
|
|
|
if (_history.Count == 0) return "";
|
|
|
|
|
var h = _history[0];
|
|
|
|
|
_history.RemoveAt(0);
|
|
|
|
|
return h;
|
|
|
|
|
}
|
2025-01-29 12:32:42 +03:00
|
|
|
|
|
|
|
|
public void OnPageOpen(object? args)
|
|
|
|
|
{
|
|
|
|
|
}
|
2025-01-10 12:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
public class ContentEntry
|
2025-01-10 12:28:29 +03:00
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
private readonly Dictionary<string, ContentEntry> _childs = new();
|
|
|
|
|
private readonly ContentBrowserViewModel _viewModel;
|
2025-03-14 17:08:35 +03:00
|
|
|
private HashApi _fileApi;
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
public RobustManifestItem? Item { get; private set; }
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
internal ContentEntry(ContentBrowserViewModel viewModel, string name, string pathName, string serverName, HashApi fileApi)
|
2025-01-14 22:10:16 +03:00
|
|
|
{
|
|
|
|
|
Name = name;
|
|
|
|
|
ServerName = serverName;
|
|
|
|
|
PathName = pathName;
|
|
|
|
|
_viewModel = viewModel;
|
2025-03-14 17:08:35 +03:00
|
|
|
_fileApi = fileApi;
|
2025-01-14 22:10:16 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
public bool IsDirectory => Item == null;
|
|
|
|
|
|
|
|
|
|
public string Name { get; private set; }
|
2025-01-14 22:10:16 +03:00
|
|
|
public string PathName { get; }
|
|
|
|
|
public string ServerName { get; }
|
2025-01-18 18:20:11 +03:00
|
|
|
public string IconPath { get; set; } = "/Assets/svg/folder.svg";
|
2025-01-11 20:39:58 +03:00
|
|
|
|
|
|
|
|
public ContentEntry? Parent { get; private set; }
|
|
|
|
|
public bool IsRoot => Parent == null;
|
|
|
|
|
|
|
|
|
|
public IReadOnlyDictionary<string, ContentEntry> Childs => _childs.ToFrozenDictionary();
|
|
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
public Stream Open()
|
|
|
|
|
{
|
|
|
|
|
_fileApi.TryOpen(Item!.Value, out var stream);
|
|
|
|
|
return stream!;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool TryOpen([NotNullWhen(true)] out Stream? stream,[NotNullWhen(true)] out RobustManifestItem? item){
|
|
|
|
|
stream = null;
|
|
|
|
|
item = null;
|
|
|
|
|
if(Item is null || !_fileApi.TryOpen(Item.Value, out stream))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
item = Item;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
public bool TryGetChild(string name, [NotNullWhen(true)] out ContentEntry? child)
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
|
|
|
|
return _childs.TryGetValue(name, out child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool TryAddChild(ContentEntry contentEntry)
|
|
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
if (_childs.TryAdd(contentEntry.PathName, contentEntry))
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
|
|
|
|
contentEntry.Parent = this;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ContentPath GetPath()
|
|
|
|
|
{
|
|
|
|
|
if (Parent != null)
|
|
|
|
|
{
|
|
|
|
|
var path = Parent.GetPath();
|
2025-01-12 22:49:32 +03:00
|
|
|
path.Pathes.Add(PathName);
|
2025-01-11 20:39:58 +03:00
|
|
|
return path;
|
|
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-01-12 22:49:32 +03:00
|
|
|
return new ContentPath([PathName]);
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ContentEntry GetOrCreateDirectory(ContentPath rootPath)
|
|
|
|
|
{
|
|
|
|
|
if (rootPath.Pathes.Count == 0) return this;
|
2025-01-12 22:49:32 +03:00
|
|
|
|
|
|
|
|
var fName = rootPath.GetNext();
|
2025-01-14 22:10:16 +03:00
|
|
|
|
|
|
|
|
if (!TryGetChild(fName, out var child))
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
2025-03-14 17:08:35 +03:00
|
|
|
child = new ContentEntry(_viewModel, fName, fName, ServerName, _fileApi);
|
2025-01-11 20:39:58 +03:00
|
|
|
TryAddChild(child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return child.GetOrCreateDirectory(rootPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ContentEntry GetRoot()
|
|
|
|
|
{
|
|
|
|
|
if (Parent == null) return this;
|
|
|
|
|
return Parent.GetRoot();
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-14 17:08:35 +03:00
|
|
|
public ContentEntry CreateItem(ContentPath path, RobustManifestItem item, HashApi fileApi)
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
|
|
|
|
var dir = path.GetDirectory();
|
|
|
|
|
var dirEntry = GetOrCreateDirectory(dir);
|
|
|
|
|
|
2025-01-12 22:49:32 +03:00
|
|
|
var name = path.GetName();
|
2025-03-14 17:08:35 +03:00
|
|
|
var entry = new ContentEntry(_viewModel, name, name, ServerName, fileApi)
|
2025-01-11 20:39:58 +03:00
|
|
|
{
|
|
|
|
|
Item = item
|
|
|
|
|
};
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
dirEntry.TryAddChild(entry);
|
2025-01-18 18:20:11 +03:00
|
|
|
entry.IconPath = "/Assets/svg/file.svg";
|
2025-01-11 20:39:58 +03:00
|
|
|
return entry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool TryGetEntry(ContentPath path, out ContentEntry? entry)
|
|
|
|
|
{
|
|
|
|
|
entry = null;
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
if (path.Pathes.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
entry = this;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2025-01-12 22:49:32 +03:00
|
|
|
|
|
|
|
|
var fName = path.GetNext();
|
2025-01-14 22:10:16 +03:00
|
|
|
|
|
|
|
|
if (!TryGetChild(fName, out var child)) return false;
|
2025-01-11 20:39:58 +03:00
|
|
|
|
|
|
|
|
return child.TryGetEntry(path, out entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void OnPathGo()
|
|
|
|
|
{
|
|
|
|
|
_viewModel.Go(GetPath());
|
|
|
|
|
}
|
2025-01-10 12:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
public struct ContentPath
|
2025-01-10 12:28:29 +03:00
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
public List<string> Pathes { get; }
|
2025-01-11 20:39:58 +03:00
|
|
|
|
|
|
|
|
public ContentPath(List<string> pathes)
|
|
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
Pathes = pathes;
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ContentPath(string path)
|
|
|
|
|
{
|
2025-01-12 22:49:32 +03:00
|
|
|
Pathes = string.IsNullOrEmpty(path)
|
|
|
|
|
? new List<string>()
|
|
|
|
|
: path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ContentPath GetDirectory()
|
|
|
|
|
{
|
2025-01-12 22:49:32 +03:00
|
|
|
if (Pathes.Count == 0)
|
|
|
|
|
return this; // Root remains root when getting the directory.
|
|
|
|
|
|
|
|
|
|
var directoryPathes = Pathes.Take(Pathes.Count - 1).ToList();
|
|
|
|
|
return new ContentPath(directoryPathes);
|
2025-01-11 20:39:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetName()
|
|
|
|
|
{
|
2025-01-12 22:49:32 +03:00
|
|
|
if (Pathes.Count == 0)
|
|
|
|
|
throw new InvalidOperationException("Cannot get the name of the root path.");
|
|
|
|
|
|
2025-01-11 20:39:58 +03:00
|
|
|
return Pathes.Last();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-12 22:49:32 +03:00
|
|
|
public string GetNext()
|
|
|
|
|
{
|
|
|
|
|
if (Pathes.Count == 0)
|
|
|
|
|
throw new InvalidOperationException("No elements left to retrieve from the root.");
|
|
|
|
|
|
|
|
|
|
var nextName = Pathes[0];
|
|
|
|
|
Pathes.RemoveAt(0);
|
|
|
|
|
|
|
|
|
|
return string.IsNullOrWhiteSpace(nextName) ? GetNext() : nextName;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-12 15:15:01 +03:00
|
|
|
public ContentPath Clone()
|
|
|
|
|
{
|
2025-01-12 22:49:32 +03:00
|
|
|
return new ContentPath(new List<string>(Pathes));
|
2025-01-12 15:15:01 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-12 22:49:32 +03:00
|
|
|
public string Path => Pathes.Count == 0 ? "/" : string.Join("/", Pathes);
|
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return Path;
|
|
|
|
|
}
|
|
|
|
|
}
|