Refactor project structure and enhance functionality

Changed the project namespace from `Ghost.Editor` to `Ghost.App` across multiple files.
Changed the `InternalsVisibleTo` attribute in `AssemblyInfo.cs` to include `Ghost.App`.
Changed the `ProjectRepository` class to add new asynchronous methods for retrieving projects by ID, name, and metadata path.
Changed the `ProjectService` class to utilize the new asynchronous project loading methods.
Changed the `SceneGraph` classes to improve node management and serialization.
Changed the `EntityManager` class to enhance entity management with new component handling methods.
Added new test classes, `EntityTest` and `SerializationTest`, to ensure reliability in entity and serialization systems.
Added the `Ghost.App` project file to establish a modular project structure.
Added the `Ghost.Generator` project for automated component serialization code generation.
Updated UI components to reflect the new namespace for proper functionality.
This commit is contained in:
2025-06-07 20:54:07 +09:00
parent bab3be2508
commit 40d333b004
123 changed files with 1441 additions and 740 deletions

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="Ghost.App.View.Pages.EngineEditor.ConsolePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Ghost.App.View.Pages.EngineEditor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource LayerFillColorDefaultBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Toolbar -->
<Grid
Grid.Row="0"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
BorderThickness="0,0,0,1">
<CommandBar Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}" DefaultLabelPosition="Collapsed">
<CommandBar.PrimaryCommands>
<AppBarButton Command="{x:Bind ViewModel.ClearLogsCommand}" Content="Clear" />
<AppBarSeparator />
<AppBarToggleButton Width="45" IsChecked="{x:Bind ViewModel.ShowInfo, Mode=TwoWay}">
<AppBarToggleButton.Icon>
<FontIcon Glyph="&#xF167;" />
</AppBarToggleButton.Icon>
</AppBarToggleButton>
<AppBarToggleButton Width="45" IsChecked="{x:Bind ViewModel.ShowWarning, Mode=TwoWay}">
<AppBarToggleButton.Icon>
<FontIcon Glyph="&#xE814;" />
</AppBarToggleButton.Icon>
</AppBarToggleButton>
<AppBarToggleButton Width="45" IsChecked="{x:Bind ViewModel.ShowError, Mode=TwoWay}">
<AppBarToggleButton.Icon>
<FontIcon Glyph="&#xEB90;" />
</AppBarToggleButton.Icon>
</AppBarToggleButton>
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
<AppBarToggleButton BorderThickness="0" Label="Clear On Play" />
<AppBarToggleButton
BorderThickness="0"
IsChecked="{x:Bind ViewModel.ShowStackTrace, Mode=TwoWay}"
Label="Show Stack Trace" />
</CommandBar.SecondaryCommands>
</CommandBar>
</Grid>
<!-- Log Content -->
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<ListView
x:Name="LogListView"
Grid.Row="0"
ItemsSource="{x:Bind ViewModel.Logs, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedLog, Mode=TwoWay}" />
<Grid
Grid.Row="1"
Padding="4"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
BorderThickness="0,1,0,0">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBlock
IsTextSelectionEnabled="True"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ViewModel.SelectedLog.ToStringWithStackTrace(), Mode=OneWay}"
TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,19 @@
using Ghost.Editor.ViewModels.Pages.EngineEditor;
using Microsoft.UI.Xaml.Controls;
namespace Ghost.App.View.Pages.EngineEditor;
internal sealed partial class ConsolePage : Page
{
public ConsoleViewModel ViewModel
{
get;
}
public ConsolePage()
{
ViewModel = GhostApplication.GetService<ConsoleViewModel>();
InitializeComponent();
}
}

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="Ghost.App.View.Pages.EngineEditor.HierarchyPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Ghost.App.View.Pages.EngineEditor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sg="using:Ghost.Editor.SceneGraph"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="SceneTemplate" x:DataType="sg:SceneGraphNode">
<TreeViewItem
AutomationProperties.Name="{x:Bind Name}"
Background="{ThemeResource ControlSolidFillColorDefaultBrush}"
IsExpanded="True"
ItemsSource="{x:Bind Children}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="14" Glyph="&#xF159;" />
<TextBlock Margin="10,0" Text="{x:Bind Name}" />
</StackPanel>
</TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="EntityTemplate" x:DataType="sg:SceneGraphNode">
<TreeViewItem AutomationProperties.Name="{x:Bind Name}" ItemsSource="{x:Bind Children}">
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="14" Glyph="&#xF158;" />
<TextBlock Margin="10,0" Text="{x:Bind Name}" />
</StackPanel>
</TreeViewItem>
</DataTemplate>
</Page.Resources>
<Grid Padding="4,6" Background="{ThemeResource LayerFillColorDefaultBrush}">
<TreeView ItemsSource="{x:Bind ViewModel.SceneList}">
<TreeView.ItemTemplateSelector>
<local:HierarchyTemplateSector EntityTemplate="{StaticResource EntityTemplate}" WorldTemplate="{StaticResource SceneTemplate}" />
</TreeView.ItemTemplateSelector>
</TreeView>
</Grid>
</Page>

View File

@@ -0,0 +1,57 @@
using Ghost.Editor.SceneGraph;
using Ghost.Editor.ViewModels.Pages.EngineEditor;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace Ghost.App.View.Pages.EngineEditor;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
internal sealed partial class HierarchyPage : Page
{
public HierarchyViewModel ViewModel
{
get;
}
public HierarchyPage()
{
ViewModel = GhostApplication.GetService<HierarchyViewModel>();
InitializeComponent();
}
}
internal partial class HierarchyTemplateSector : DataTemplateSelector
{
public DataTemplate? WorldTemplate
{
get;
set;
}
public DataTemplate? EntityTemplate
{
get;
set;
}
protected override DataTemplate SelectTemplateCore(object item)
{
if (WorldTemplate == null || EntityTemplate == null)
{
return base.SelectTemplateCore(item);
}
var node = (SceneGraphNode)item;
return node.NodeType switch
{
SceneGraphNodeType.Scene => WorldTemplate,
SceneGraphNodeType.Entity => EntityTemplate,
_ => base.SelectTemplateCore(item)
};
}
}

View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="Ghost.App.View.Pages.EngineEditor.ProjectPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="using:Ghost.Editor.Utilities.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Ghost.App.View.Pages.EngineEditor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:Ghost.App.Models"
mc:Ignorable="d">
<Page.Resources>
<converter:AssetPathToGlyphConverter x:Key="AssetPathToGlyphConverter" />
</Page.Resources>
<Grid Background="{ThemeResource LayerFillColorDefaultBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Folder Tree View -->
<Grid
Grid.Column="0"
Padding="4"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
BorderThickness="0,0,1,0">
<TreeView
x:Name="DirectoryTreeView"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{x:Bind ViewModel.SubDirectories}"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectedItem="{x:Bind ViewModel.SelectedDirectory, Mode=TwoWay}">
<TreeView.ItemTemplate>
<DataTemplate x:DataType="model:ExplorerItem">
<TreeViewItem ItemsSource="{x:Bind Children}">
<StackPanel Orientation="Horizontal">
<FontIcon
VerticalAlignment="Center"
FontSize="14"
Glyph="&#xE8B7;" />
<TextBlock
Margin="8,0,0,0"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Name}"
TextTrimming="CharacterEllipsis" />
</StackPanel>
</TreeViewItem>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
<!-- Files -->
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid
Grid.Row="0"
Padding="4"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
BorderThickness="0,0,0,1">
<BreadcrumbBar Height="15" />
</Grid>
<ScrollViewer
Grid.Row="1"
Padding="8"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<GridView
x:Name="AssetsGridView"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{x:Bind ViewModel.DirectoryAssets, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedAsset, Mode=TwoWay}">
<GridView.ItemContainerStyle>
<Style BasedOn="{StaticResource DefaultGridViewItemStyle}" TargetType="GridViewItem">
<Setter Property="Margin" Value="2" />
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemTemplate>
<DataTemplate x:DataType="model:ExplorerItem">
<Grid
Width="100"
Height="100"
Padding="8"
DoubleTapped="GridViewItem_DoubleTapped"
IsDoubleTapEnabled="True">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="0.25*" />
</Grid.RowDefinitions>
<FontIcon FontSize="42" Glyph="{x:Bind Path, Converter={StaticResource AssetPathToGlyphConverter}}" />
<TextBlock
Grid.Row="1"
Margin="8,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Name}"
TextTrimming="CharacterEllipsis" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</ScrollViewer>
<Grid
Grid.Row="2"
Padding="4"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultSolid}"
BorderThickness="0,1,0,0">
<TextBlock
VerticalAlignment="Center"
HorizontalTextAlignment="Left"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ViewModel.SelectedAsset.Path, Mode=OneWay}"
TextTrimming="CharacterEllipsis" />
</Grid>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,25 @@
using Ghost.Editor.ViewModels.Pages.EngineEditor;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
namespace Ghost.App.View.Pages.EngineEditor;
internal sealed partial class ProjectPage : Page
{
public ProjectViewModel ViewModel
{
get;
}
public ProjectPage()
{
ViewModel = GhostApplication.GetService<ProjectViewModel>();
InitializeComponent();
}
private void GridViewItem_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
ViewModel.NavigateToSelected();
}
}

View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="Ghost.App.View.Pages.Landing.CreateProjectPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="using:Ghost.Data.Models"
xmlns:editor="using:Ghost.Editor.Controls"
xmlns:local="using:Ghost.App.View.Pages.Landing"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
NavigationCacheMode="Enabled"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Template Info -->
<Grid Grid.Column="0" Width="300">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Margin="0,0,0,24"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="Template" />
<ListView
Grid.Row="1"
ItemsSource="{x:Bind ViewModel.templates}"
SelectedItem="{x:Bind ViewModel.SelectedTemplate, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:TemplateData">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ImageIcon
Grid.Column="0"
Width="24"
Height="24">
<ImageIcon.Source>
<BitmapImage UriSource="{x:Bind GetIconURI()}" />
</ImageIcon.Source>
</ImageIcon>
<TextBlock
Grid.Column="1"
Margin="8,0"
VerticalAlignment="Center"
Text="{x:Bind Info.Name}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
<!-- Project Info -->
<Grid
Grid.Column="1"
Margin="16,0,0,0"
Padding="16"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="{StaticResource OverlayCornerRadius}">
<Grid.RowDefinitions>
<RowDefinition Height="300" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" CornerRadius="4">
<Image VerticalAlignment="Center" Stretch="UniformToFill">
<Image.Source>
<BitmapImage UriSource="{x:Bind ViewModel.SelectedTemplate.Value.GetPreviewURI(), Mode=OneWay}" />
</Image.Source>
</Image>
<Grid
MaxHeight="100"
VerticalAlignment="Bottom"
Background="{ThemeResource ControlOnImageFillColorDefaultBrush}">
<TextBlock
Margin="16"
VerticalAlignment="Bottom"
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
Text="{x:Bind ViewModel.SelectedTemplate.Value.Info.Description, Mode=OneWay}" />
</Grid>
</Grid>
<StackPanel Grid.Row="1" Margin="8,0">
<TextBlock
Margin="0,16,0,8"
Style="{StaticResource TitleTextBlockStyle}"
Text="{x:Bind ViewModel.SelectedTemplate.Value.Info.Name, Mode=OneWay}" />
<TextBlock
Margin="0,8,0,16"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="Project Settings" />
<editor:PropertyField Label="Name">
<TextBox Text="{x:Bind ViewModel.ProjectName, Mode=TwoWay}" />
</editor:PropertyField>
<editor:PropertyField Label="Location">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
Grid.Column="0"
IsReadOnly="True"
Text="{x:Bind ViewModel.ProjectLocation, Mode=TwoWay}" />
<Button
Grid.Column="1"
Margin="4,0,0,0"
VerticalAlignment="Stretch"
Command="{x:Bind ViewModel.SelectionProjectLocationCommand}">
<FontIcon FontSize="16" Glyph="&#xE8DA;" />
</Button>
</Grid>
</editor:PropertyField>
</StackPanel>
<Grid Grid.Row="2">
<Button
Width="150"
HorizontalAlignment="Right"
Command="{x:Bind ViewModel.CreateProjectCommand}"
Content="Create"
Style="{ThemeResource AccentButtonStyle}" />
</Grid>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,26 @@
using Ghost.Editor.ViewModels.Pages.Landing;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
namespace Ghost.App.View.Pages.Landing;
internal sealed partial class CreateProjectPage : Page
{
public CreateProjectViewModel ViewModel
{
get;
}
public CreateProjectPage()
{
ViewModel = GhostApplication.GetService<CreateProjectViewModel>();
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
ViewModel.OnNavigatedTo(e.Parameter);
}
}

View File

@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page
x:Class="Ghost.App.View.Pages.Landing.OpenProjectPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:Ghost.Editor.Utilities.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="using:Ghost.Data.Models"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:Ghost.App.View.Pages.Landing"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
NavigationCacheMode="Enabled"
mc:Ignorable="d">
<Page.Resources>
<converters:GetDirectoryNameConverter x:Key="DirNameConverter" />
</Page.Resources>
<Grid x:Name="MainContainer">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="16,4">
<TextBlock
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="Projects" />
<AutoSuggestBox
Width="300"
HorizontalAlignment="Right"
PlaceholderText="Search project by name"
QueryIcon="Find" />
</Grid>
<!-- Header for the ListView -->
<Grid Grid.Row="1" Margin="28,16,45,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="165" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Style="{StaticResource CaptionTextBlockStyle}"
Text="NAME" />
<TextBlock
Grid.Column="1"
HorizontalAlignment="Right"
Style="{StaticResource CaptionTextBlockStyle}"
Text="LAST OPEN" />
<TextBlock
Grid.Column="2"
HorizontalAlignment="Right"
Style="{StaticResource CaptionTextBlockStyle}"
Text="ENGINE VERSION" />
</Grid>
<!-- Project ListView -->
<Grid
Grid.Row="2"
Padding="8"
AllowDrop="True"
DragEnter="ProjectContainer_DragEnter"
DragLeave="ProjectContainer_DragLeave"
DragOver="ProjectContainer_DragOver"
Drop="ProjectContainer_Drop">
<ListView
Padding="4,8"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
CornerRadius="{StaticResource OverlayCornerRadius}"
IsItemClickEnabled="True"
ItemClick="ListView_ItemClick"
ItemsSource="{x:Bind ViewModel.projects}"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:ProjectMetadataInfo">
<Grid Height="64" Padding="4,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="65" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
VerticalAlignment="Center"
FontSize="16"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{x:Bind Metadata.Name}" />
<TextBlock
Grid.Row="1"
Margin="0,4,0,0"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Path, Converter={StaticResource DirNameConverter}}" />
</Grid>
<TextBlock
Grid.Column="1"
Margin="16,4"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{x:Bind Metadata.LastOpened}" />
<TextBlock
Grid.Column="2"
Margin="16,4"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{x:Bind Metadata.EngineVersion}" />
<Button
Grid.Column="3"
HorizontalAlignment="Right"
Background="Transparent"
BorderThickness="0">
<FontIcon Glyph="&#xE712;" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- Drag Visual -->
<Grid
x:Name="DragVisual"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{ThemeResource CardStrokeColorDefaultBrush}"
BorderBrush="{ThemeResource ControlStrongStrokeColorDefaultBrush}"
BorderThickness="2"
CornerRadius="{StaticResource OverlayCornerRadius}"
Visibility="{x:Bind ViewModel.DragVisibility, Mode=OneWay}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource TitleTextBlockStyle}"
Text="Drage Project Folder Here" />
</Grid>
</Grid>
<!-- Empty Place Holder -->
<Grid
x:Name="EmptyPlaceHolder"
Grid.Row="2"
Visibility="{x:Bind ViewModel.EmptyVisibility, Mode=OneWay}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource TitleTextBlockStyle}"
Text="No projects found" />
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,71 @@
using Ghost.Data.Models;
using Ghost.Editor.ViewModels.Pages.Landing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Windows.ApplicationModel.DataTransfer;
namespace Ghost.App.View.Pages.Landing;
internal sealed partial class OpenProjectPage : Page
{
public OpenProjectViewModel ViewModel
{
get;
}
public OpenProjectPage()
{
ViewModel = GhostApplication.GetService<OpenProjectViewModel>();
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
ViewModel.OnNavigatedTo(e.Parameter);
}
override protected void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
ViewModel.OnNavigatedFrom();
}
private void ProjectContainer_DragEnter(object sender, DragEventArgs e)
{
ViewModel.DragVisibility = Visibility.Visible;
ViewModel.EmptyVisibility = Visibility.Collapsed;
}
private void ProjectContainer_DragLeave(object sender, DragEventArgs e)
{
ViewModel.DragVisibility = Visibility.Collapsed;
ViewModel.UpdateEmptyPlaceHolderVisibility();
}
private void ProjectContainer_DragOver(object sender, DragEventArgs e)
{
if (e.DataView.Contains(StandardDataFormats.StorageItems))
{
e.AcceptedOperation = DataPackageOperation.Link;
}
else
{
e.AcceptedOperation = DataPackageOperation.None;
}
}
private async void ProjectContainer_Drop(object sender, DragEventArgs e)
{
await ViewModel.ContentDrop(e.DataView);
}
private async void ListView_ItemClick(object sender, ItemClickEventArgs e)
{
if (e.ClickedItem is ProjectMetadataInfo project)
{
await ViewModel.LoadProject(project);
}
}
}