Skip to content

Commit 76a430c

Browse files
committed
feat(Avalonia): implement initial drag&drop support
1 parent 8b50985 commit 76a430c

5 files changed

Lines changed: 111 additions & 68 deletions

File tree

SnapX.Avalonia/Views/HomePageView.axaml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@
2121
<Design.DataContext>
2222
<viewModels1:HomePageViewModel />
2323
</Design.DataContext>
24-
<ScrollViewer>
25-
<Grid>
26-
<controls:ItemsRepeater IsVisible="{Binding recentTasks.Count, Converter={StaticResource CountToBoolean}}" ItemsSource="{Binding recentTasks}">
24+
<ScrollViewer DragDrop.AllowDrop="True">
25+
<Grid DragDrop.AllowDrop="True">
26+
<controls:ItemsRepeater
27+
DragDrop.AllowDrop="True"
28+
IsVisible="{Binding recentTasks.Count, Converter={StaticResource CountToBoolean}}"
29+
ItemsSource="{Binding recentTasks}">
2730
<controls:ItemsRepeater.Layout>
2831
<controls:UniformGridLayout
2932
ItemsJustification="Start"
@@ -35,9 +38,12 @@
3538
<DataTemplate DataType="models:ListTaskTemplate">
3639

3740
<ToggleButton
41+
Classes="draggable"
3842
ClickMode="Press"
43+
DragDrop.AllowDrop="True"
3944
Height="200"
4045
Margin="5"
46+
Name="{Binding task.TrayMenuText}"
4147
UseLayoutRounding="True"
4248
Width="205">
4349
<ToolTip.Tip>

SnapX.Avalonia/Views/HomePageView.axaml.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
using AsyncImageLoader.Loaders;
22
using Avalonia.Controls;
3+
using Avalonia.Input;
34
using Avalonia.Interactivity;
5+
using Avalonia.Platform.Storage;
6+
using Avalonia.VisualTree;
47
using FluentAvalonia.UI.Controls;
58
using SnapX.Avalonia.Models;
69
using SnapX.Avalonia.ViewModels;
710
using SnapX.Core;
11+
using SnapX.Core.Upload;
812
using SnapX.Core.Utils;
913
using SnapX.Core.Utils.Miscellaneous;
1014

@@ -19,8 +23,94 @@ public HomePageView(HomePageViewModel vm)
1923
DataContext = vm;
2024
ViewModel = vm;
2125
InitializeComponent();
26+
AddHandler(DragDrop.DragOverEvent, DragOver);
27+
AddHandler(DragDrop.DragEnterEvent, DragEnter);
28+
AddHandler(DragDrop.DropEvent, Drop);
2229
AsyncImageLoader.ImageLoader.AsyncImageLoader = new DiskCachedWebImageLoader(HttpClientFactory.Get(), false, Path.Combine(Core.SnapX.CacheFolder, "Images"));
2330
}
31+
32+
private void SetupAllDraggables(TopLevel topLevel)
33+
{
34+
foreach (var element in topLevel.GetVisualDescendants().OfType<Control>())
35+
{
36+
if (element.Classes.Contains("draggable"))
37+
{
38+
SetupDnd(element, d =>
39+
{
40+
if (element.DataContext is ListTaskTemplate task && !string.IsNullOrEmpty(task.task.FilePath))
41+
{
42+
d.Set(DataFormats.Files, new[] { task.task.FilePath });
43+
}
44+
else
45+
{
46+
DebugHelper.WriteLine($"Element that has draggable class doesn't have a DataContext of ListTaskTemplate");
47+
}
48+
},
49+
DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
50+
}
51+
}
52+
}
53+
private void SetupDnd(IInputElement draggable, Action<DataObject> factory, DragDropEffects effects)
54+
{
55+
draggable.PointerPressed += (_, e) => DoDrag(factory, e, effects);
56+
}
57+
private async void DoDrag(Action<DataObject> factory, PointerEventArgs e, DragDropEffects effects)
58+
{
59+
var dragData = new DataObject();
60+
factory(dragData);
61+
62+
var result = await DragDrop.DoDragDrop(e, dragData, effects);
63+
}
64+
65+
private void DragEnter(object? Sender, DragEventArgs e)
66+
{
67+
// DebugHelper.WriteLine("DragEnter Event");
68+
// DebugHelper.WriteLine($"Sender: {Sender} | EventArgs: {e.GetPosition(this)}");
69+
}
70+
71+
private void DragOver(object? Sender, DragEventArgs e)
72+
{
73+
// DebugHelper.WriteLine("DragOver Event");
74+
// DebugHelper.WriteLine($"Sender: {Sender} | EventArgs: {e.GetPosition(this)}");
75+
}
76+
77+
private void Drop(object? Sender, DragEventArgs e)
78+
{
79+
DebugHelper.WriteLine("Drop Event");
80+
DebugHelper.WriteLine($"Sender: {Sender} | EventArgs: {e.GetPosition(this)}");
81+
if (e.Source is Control)
82+
{
83+
e.DragEffects &= DragDropEffects.Move;
84+
}
85+
else
86+
{
87+
e.DragEffects &= DragDropEffects.Copy;
88+
}
89+
if (e.Data.Contains(DataFormats.Text))
90+
{
91+
UploadManager.UploadText(e.Data.GetText());
92+
}
93+
else if (e.Data.Contains(DataFormats.Files))
94+
{
95+
var files = e.Data.GetFiles() ?? Array.Empty<IStorageItem>();
96+
97+
foreach (var item in files)
98+
{
99+
switch (item)
100+
{
101+
case IStorageFile file:
102+
UploadManager.UploadFile(file.Path.AbsolutePath);
103+
break;
104+
case IStorageFolder folder:
105+
UploadManager.UploadFolder(folder.Path.AbsolutePath);
106+
break;
107+
}
108+
}
109+
110+
}
111+
112+
DebugHelper.WriteLine($"{string.Join(", ", e.Data.GetDataFormats())}");
113+
}
24114
public HomePageView() : this(new HomePageViewModel())
25115
{
26116
}
@@ -33,6 +123,7 @@ private void PopupFlyoutBase_OnOpening(object? Sender, EventArgs E)
33123
private void Control_OnLoaded(object? Sender, RoutedEventArgs E)
34124
{
35125
Task.Run(() => ViewModel.Initialize()).ConfigureAwait(false);
126+
// SetupAllDraggables(TopLevel.GetTopLevel(this)!);
36127
}
37128

38129
private void DeleteLocallyButton_OnClick(object? Sender, RoutedEventArgs E)

SnapX.Core/NativeMethods.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ GetDC
1414
GlobalMemoryStatusEx
1515
GetWindowText
1616
GetWindowTextLength
17+
GetWindowThreadProcessId
1718
GetWindowRgn
1819
GetCursorPos
1920
SetCursorPos

SnapX.Core/Upload/UploadManager.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ public static bool IsValidDirectory(string? dir)
8989
return !string.IsNullOrEmpty(dir) && Directory.Exists(dir);
9090
}
9191

92+
public static void UploadFolder(string? folderPath, TaskSettings? taskSettings = null)
93+
{
94+
if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
95+
return;
96+
97+
foreach (var file in Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories))
98+
{
99+
UploadFile(file, taskSettings);
100+
}
101+
}
92102
public static void UploadFolder(TaskSettings taskSettings = null)
93103
{
94104
// using (FolderSelectDialog folderDialog = new FolderSelectDialog())

SnapX.Core/Utils/FileHelpers.cs

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -161,71 +161,6 @@ public static EDataType FindDataType(string? filePath)
161161
return Path.GetFullPath(path);
162162
}
163163

164-
public static string FindSnapX(string? binary = null)
165-
{
166-
var knownBinaryNames = new[]
167-
{
168-
"snapx-ui", // SnapX.Avalonia
169-
"snapx-gtk", // SnapX.GTK4
170-
"snapx", // SnapX.CLI
171-
"SnapX" // Could literally be anything.
172-
};
173-
if (OperatingSystem.IsWindows()) knownBinaryNames = knownBinaryNames.Select(name => name + ".exe").ToArray();
174-
175-
var path = Environment.GetEnvironmentVariable("PATH");
176-
177-
if (!string.IsNullOrWhiteSpace(binary))
178-
{
179-
var foundBinary = FindBinaryInPath(binary, path);
180-
if (foundBinary != null)
181-
return foundBinary;
182-
183-
// Check if the binary exists in the base directory
184-
var baseDirBinary = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, binary);
185-
if (File.Exists(baseDirBinary))
186-
return baseDirBinary;
187-
}
188-
189-
// If no binary is provided, search through the known binary names in the PATH and BaseDirectory
190-
foreach (var knownBinary in knownBinaryNames)
191-
{
192-
var foundBinary = FindBinaryInPath(knownBinary, path);
193-
if (foundBinary != null)
194-
return foundBinary;
195-
196-
// Check if the known binary exists in the base directory
197-
var baseDirBinary = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, knownBinary);
198-
if (File.Exists(baseDirBinary))
199-
return baseDirBinary;
200-
}
201-
202-
// Return null if no binary is found
203-
DebugHelper.WriteLine("SnapX NOT found in PATH or BaseDirectory. Weewoo weewoo");
204-
return null;
205-
}
206-
207-
private static string? FindBinaryInPath(string binaryName, string? path)
208-
{
209-
if (path == null)
210-
return null;
211-
212-
// Split the PATH by the platform-specific path separator
213-
var pathEntries = path.Split(Path.PathSeparator);
214-
215-
// Search for the binary in each path entry
216-
foreach (var entry in pathEntries)
217-
{
218-
var binaryPath = Path.Combine(entry, binaryName);
219-
220-
// Check if the binary exists in the directory
221-
if (File.Exists(binaryPath))
222-
return binaryPath; // Return the path if the binary is found
223-
}
224-
225-
// Return null if the binary is not found in the PATH
226-
return null;
227-
}
228-
229164
public static string GetPathRoot(string? path)
230165
{
231166
var separator = path.IndexOf(":\\");

0 commit comments

Comments
 (0)