diff --git a/TimelapseApi/.vs/TimelapseApi/xs/UserPrefs.xml b/TimelapseApi/.vs/TimelapseApi/xs/UserPrefs.xml
new file mode 100644
index 0000000..3950bbe
--- /dev/null
+++ b/TimelapseApi/.vs/TimelapseApi/xs/UserPrefs.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TimelapseApi/Api.cs b/TimelapseApi/Api.cs
index 0c69d5b..97655e0 100644
--- a/TimelapseApi/Api.cs
+++ b/TimelapseApi/Api.cs
@@ -13,6 +13,7 @@ public class GuiData
public async Task Set()
{
if(Instance ==null) return;
+ Api.natfs.api=Instance;
var s= Instance._extSettings;
ExtensionLoader.Data=this;
s.Add((
@@ -183,12 +184,12 @@ public class Api
public int CurrentFileSystemIndex {get {return Gui.CurrentFSIndex;}}
internal List<(TimelapseFileSystem FileSystem,string Text,TimelapseExtension Extension)> _fs = CreateFileSystemList();
-
+ internal static NativeFileSystem natfs=new NativeFileSystem();
internal List Extensions =new List();
private static List<(TimelapseFileSystem FileSystem,string Text,TimelapseExtension Extension)> CreateFileSystemList()
{
List<(TimelapseFileSystem FileSystem,string Text,TimelapseExtension Extension)> fs=new List<(TimelapseFileSystem FileSystem,string Text,TimelapseExtension Extension)>();
- fs.Add((new NativeFileSystem(),"Native",TimelapseExtension.Null));
+ fs.Add((natfs,"Native",TimelapseExtension.Null));
return fs;
}
diff --git a/TimelapseApi/Assets/directory.png b/TimelapseApi/Assets/directory.png
new file mode 100644
index 0000000..548cd00
Binary files /dev/null and b/TimelapseApi/Assets/directory.png differ
diff --git a/TimelapseApi/Assets/file.png b/TimelapseApi/Assets/file.png
new file mode 100644
index 0000000..628885c
Binary files /dev/null and b/TimelapseApi/Assets/file.png differ
diff --git a/TimelapseApi/TimelapseApi.csproj b/TimelapseApi/TimelapseApi.csproj
index 80324fd..d772725 100644
--- a/TimelapseApi/TimelapseApi.csproj
+++ b/TimelapseApi/TimelapseApi.csproj
@@ -26,5 +26,8 @@
-
+
+
+
+
diff --git a/TimelapseApi/TimelapseFileSystem.cs b/TimelapseApi/TimelapseFileSystem.cs
index d06277e..c564a8b 100644
--- a/TimelapseApi/TimelapseFileSystem.cs
+++ b/TimelapseApi/TimelapseFileSystem.cs
@@ -1,6 +1,330 @@
namespace TimelapseApi;
using Eto.Forms;
+using Eto.Drawing;
+using System.Collections.ObjectModel;
+using Dir=System.IO.Directory;
+using System.Reflection;
+internal class OpenDialog : Dialog
+{
+ public enum DialogType
+ {
+ Open,
+ Save,
+ Directory
+ }
+ private static Stream[] GetIcons()
+ {
+ Stream[] Strms=new Stream[2];
+ var asm=Assembly.GetExecutingAssembly();
+
+ if(asm != null)
+ {
+
+ var strm=asm.GetManifestResourceStream("TimelapseApi.Assets.directory.png");
+ if(strm != null)
+ {
+ Strms[0]=strm;
+ }
+ strm=asm.GetManifestResourceStream("TimelapseApi.Assets.file.png");
+ if(strm != null)
+ {
+ Strms[1]=strm;
+ }
+
+ }
+ return Strms;
+ }
+ private Stream[] Icons =GetIcons();
+ public class OpenFile
+ {
+ public OpenFile(Image icon,string name,string path,bool file)
+ {
+ Icon=icon;
+ Name = name;
+ Path=path;
+ IsFile=file;
+ }
+ public bool IsFile {get;set;}
+ public string Path {get;set;}
+ public string Name {get;set;}
+
+ public Image Icon {get;set;}
+ }
+ Button upBtn=new Button();
+ TextBox path=new TextBox();
+ GridView view=new GridView();
+ ObservableCollection Files=new ObservableCollection();
+ Image[] imgs=new Image[2];
+ public List Filters {get;set;}
+ DialogType Type;
+
+ DropDown extPick;
+ public OpenDialog(TimelapseFileSystem fs,DialogType type)
+ {
+ Button cancel=new Button {Text="Cancel"};
+ cancel.Click +=(sender,e)=>{
+ Result=new string[0];
+ this.Close();
+ };
+ TextBox filename=new TextBox();
+ filename.PlaceholderText="Filename";
+ Button createDir = new Button {Text="Create Folder"};
+
+ createDir.Click+=(sender,e)=>{
+ if(string.IsNullOrWhiteSpace(filename.Text))
+ {
+ MessageBox.Show("Please type Filename");
+ }else{
+ fs.CreateDirectory(TimelapseFileSystem.CombinePath(Directory,filename.Text));
+ }
+ };
+ extPick=new DropDown();
+
+ Type=type;
+ Filters=new List();
+ Title=Type == DialogType.Open ? "Open File" : (Type == DialogType.Save ? "Save File" : "Open Directory");
+ path.KeyDown+=(sender,e)=>{
+ if(e.Key==Keys.Enter)
+ {
+ ListDirectory();
+ }
+ };
+ upBtn.Text="Up";
+ upBtn.Click+=(sender,e)=>{
+ string? path=Path.GetDirectoryName(Directory);
+ if(!string.IsNullOrWhiteSpace(path))
+ {
+ Directory=path;
+ ListDirectory();
+ }
+ };
+ Resizable=true;
+ Width=640;
+ Height=480;
+ imgs[0]=new Bitmap(Icons[0]);
+ imgs[1]=new Bitmap(Icons[1]);
+ Directory="/";
+ Result=new string[0];
+ FileSystem=fs;
+ MultiSelect=false;
+ view.DataStore=Files;
+ view.Columns.Add(new GridColumn {DataCell =new ImageViewCell("Icon")});
+ view.Columns.Add(new GridColumn {HeaderText="Name",DataCell=new TextBoxCell("Name"), Editable=false});
+ view.SelectedItemsChanged+=(sender,e)=>{
+ List filenames=new List();
+ foreach(var v in view.SelectedItems)
+ {
+ filenames.Add(v.Name);
+ }
+ filename.Text=string.Join(',',filenames);
+ };
+ view.CellDoubleClick+=(sender,e)=>{
+ OpenFile f = (OpenFile)e.Item;
+
+ if(f.IsFile)
+ {
+ if(Type == DialogType.Save)
+ {
+ if(MessageBox.Show($"Do you want to overwrite {f.Path}",MessageBoxButtons.YesNo,MessageBoxType.Question,MessageBoxDefaultButton.No) != DialogResult.Yes)
+ {
+ return;
+ }
+ }
+ Result=new string[]{f.Path};
+ this.Close();
+ }else{
+ Directory=f.Path;
+ ListDirectory();
+ }
+ };
+ Button openBtn = new Button {Text=Type == DialogType.Save ? "Save" : "Open"};
+ openBtn.Click +=(sender,e)=>{
+ if(Type == DialogType.Directory)
+ {
+ if(view.SelectedItems.Any())
+ {
+ Result = new string[]{ view.SelectedItem.Path};
+ this.Close();
+ return;
+ }
+
+ if(!string.IsNullOrWhiteSpace(filename.Text))
+ {
+ if(!FileSystem.DirectoryExists(Directory))
+ {
+ return;
+ }
+ string dir =TimelapseFileSystem.CombinePath(Directory,filename.Text);
+ if(FileSystem.DirectoryExists(dir))
+ {
+ Result=new string[] {dir};
+ this.Close();
+ return;
+ }
+
+ }
+ if(FileSystem.DirectoryExists(Directory))
+ {
+ Result=new string[] {Directory};
+ this.Close();
+ return;
+ }
+ }
+ else
+ {
+ if(view.SelectedItems.Any())
+ {
+ List paths=new List();
+ foreach(var item in view.SelectedItems)
+ {
+ if(!item.IsFile)
+ {
+ return;
+ }
+ if(Type==DialogType.Save && FileSystem.FileExists(item.Path))
+ {
+ if(MessageBox.Show($"Do you want to overwrite {item.Path}",MessageBoxButtons.YesNo,MessageBoxType.Question,MessageBoxDefaultButton.No) != DialogResult.Yes)
+ {
+ return;
+ }
+ }
+ paths.Add(item.Path);
+ }
+ Result=paths.ToArray();
+ this.Close();
+ return;
+ }
+ if(!string.IsNullOrWhiteSpace(filename.Text))
+ {
+ string dir =TimelapseFileSystem.CombinePath(Directory,filename.Text);
+ if(!FileSystem.DirectoryExists(Directory))
+ {
+ return;
+ }
+ if(Type==DialogType.Open)
+ {
+
+ if(FileSystem.FileExists(dir))
+ {
+ Result=new string[]{dir};
+ this.Close();
+ return;
+ }
+ }else{
+ if(FileSystem.FileExists(dir))
+ {
+ if(MessageBox.Show($"Do you want to overwrite {dir}",MessageBoxButtons.YesNo,MessageBoxType.Question,MessageBoxDefaultButton.No) != DialogResult.Yes)
+ {
+ return;
+ }
+ Result=new string[]{dir};
+ this.Close();
+ return;
+ }else{
+ Result=new string[]{dir};
+ this.Close();
+ return;
+ }
+ }
+
+ }
+ }
+ };
+ DynamicLayout lyt=new DynamicLayout();
+ lyt.BeginVertical();
+ lyt.BeginHorizontal();
+ lyt.Add(upBtn);
+ lyt.Add(path,true);
+ lyt.EndHorizontal();
+ lyt.EndBeginVertical();
+ lyt.BeginHorizontal();
+
+ lyt.Add(createDir);
+ lyt.Add(filename,true);
+ if(Type!=DialogType.Directory)
+ {
+ lyt.Add(extPick);
+ }
+ lyt.EndHorizontal();
+ lyt.EndBeginVertical();
+ lyt.BeginHorizontal();
+ lyt.AddSpace(true);
+ lyt.Add(cancel);
+ lyt.Add(openBtn);
+ lyt.EndBeginVertical();
+ lyt.BeginHorizontal();
+
+ lyt.Add(view,true,true);
+
+ lyt.EndHorizontal();
+ lyt.EndVertical();
+ this.Content=lyt;
+
+ }
+ private void ListDirectory()
+ {
+
+ Files.Clear();
+ foreach(var dir in FileSystem.GetDirectories(Directory))
+ {
+
+ Files.Add(new OpenFile(imgs[0],dir, TimelapseFileSystem.CombinePath(Directory,dir),false));
+ }
+ if(Type != DialogType.Directory){
+ List validExts=new List();
+ if(Filters.Count > 0 && extPick.SelectedIndex > -1)
+ {
+ foreach(var ext in Filters[extPick.SelectedIndex].Extensions)
+ {
+ validExts.Add(ext);
+ }
+ }
+ foreach(var dir in FileSystem.GetFiles(Directory))
+ {
+ string ext=Path.GetExtension(dir);
+ bool add=true;
+ if(validExts.Count > 0)
+ {
+ add=validExts.Contains(ext);
+ }
+ if(add)
+ Files.Add(new OpenFile(imgs[1],dir,TimelapseFileSystem.CombinePath(Directory,dir),true));
+ }
+ }
+ }
+ protected override void OnShown(EventArgs e)
+ {
+ foreach(var item in Filters)
+ {
+ extPick.Items.Add(item.Name);
+ }
+ if(extPick.Items.Count > 0)
+ {
+ extPick.SelectedIndex=0;
+ }
+ view.AllowMultipleSelection=MultiSelect;
+ ListDirectory();
+ extPick.SelectedIndexChanged+=(sender,e)=>{
+ ListDirectory();
+ };
+ }
+ protected override void OnClosed(EventArgs e)
+ {
+ foreach(var i in imgs)
+ {
+ if(i!=null && !i.IsDisposed) i.Dispose();
+ }
+ foreach(var i in Icons)
+ {
+ if(i!=null) i.Dispose();
+ }
+ }
+ public bool MultiSelect {get {return view.AllowMultipleSelection;}set{view.AllowMultipleSelection=value;}}
+ public string Directory {get {return path.Text;} set{path.Text=value;}}
+
+ public TimelapseFileSystem FileSystem {get;set;}
+}
public class Protect : TimelapseFileSystem
{
TimelapseFileSystem fs;
@@ -68,6 +392,7 @@ public class Protect : TimelapseFileSystem
}
public class NativeFileSystem : TimelapseFileSystem
{
+ internal Api? api;
public override void CreateDirectory(string path)
{
Directory.CreateDirectory(path);
@@ -105,6 +430,9 @@ public class NativeFileSystem : TimelapseFileSystem
}
public override string? ShowDirectoryDialog(Window parent, string startDir = "")
{
+ if(api != null && api.Model.useCustomFilePickerForNativeFS) {
+ return base.ShowDirectoryDialog(parent,startDir);
+ }
using(var d = new SelectFolderDialog())
{
if(!string.IsNullOrWhiteSpace(startDir))
@@ -114,8 +442,11 @@ public class NativeFileSystem : TimelapseFileSystem
return d.ShowDialog(parent) == DialogResult.Ok ? d.Directory : null;
}
}
- public override string[] ShowOpenDialog(Window parent, FileFilter[] filters,bool multi, string startDir = "")
+ public override string[] ShowOpenDialog(Window parent, FileFilter[] filters,bool multi, string startDir = "")
{
+ if(api != null && api.Model.useCustomFilePickerForNativeFS) {
+ return base.ShowOpenDialog(parent,filters,multi,startDir);
+ }
using(var ofd=new OpenFileDialog())
{
ofd.MultiSelect = multi;
@@ -132,6 +463,9 @@ public class NativeFileSystem : TimelapseFileSystem
}
public override string? ShowSaveDialog(Window parent, FileFilter[] filters, string startDir = "")
{
+ if(api != null && api.Model.useCustomFilePickerForNativeFS) {
+ return base.ShowSaveDialog(parent,filters,startDir);
+ }
using(var sfd=new SaveFileDialog())
{
if(!string.IsNullOrWhiteSpace(startDir))
@@ -186,16 +520,52 @@ public abstract class TimelapseFileSystem
}
public virtual string[] ShowOpenDialog(Window parent,FileFilter[] filters,bool multi,string startDir="")
{
- throw new Exception();
+ using(var ofd=new OpenDialog(this,OpenDialog.DialogType.Open))
+ {
+ ofd.MultiSelect=multi;
+ foreach(var f in filters)
+ {
+ ofd.Filters.Add(f);
+ }
+ if(!string.IsNullOrWhiteSpace(startDir))
+ {
+ ofd.Directory=startDir;
+ }
+ return ofd.ShowModal(parent);
+ }
+
}
public virtual string? ShowSaveDialog(Window parent,FileFilter[] filters,string startDir="")
{
- throw new Exception();
+ using(var ofd=new OpenDialog(this,OpenDialog.DialogType.Save))
+ {
+
+ foreach(var f in filters)
+ {
+ ofd.Filters.Add(f);
+ }
+ if(!string.IsNullOrWhiteSpace(startDir))
+ {
+ ofd.Directory=startDir;
+ }
+ var res=ofd.ShowModal(parent);
+ return res.Length == 1 ? res[0] : null;
+ }
}
public virtual string? ShowDirectoryDialog(Window parent,string startDir="")
{
- throw new Exception();
+ using(var ofd=new OpenDialog(this,OpenDialog.DialogType.Directory))
+ {
+
+
+ if(!string.IsNullOrWhiteSpace(startDir))
+ {
+ ofd.Directory=startDir;
+ }
+ var res=ofd.ShowModal(parent);
+ return res.Length == 1 ? res[0] : null;
+ }
}
public int GetNumberOfFiles(string path,string filter="*")
@@ -256,7 +626,7 @@ public abstract class TimelapseFileSystem
public abstract bool DirectoryExists(string path);
public static string CombinePath(string p1,string p2)
{
- return Path.Combine(p1,p2).Replace(Path.DirectorySeparatorChar,'/');
+ return Path.Combine(p1,p2.TrimStart('/')).Replace(Path.DirectorySeparatorChar,'/');
}
public abstract Stream Open(string path,FileMode mode,FileAccess access,FileShare share);
diff --git a/TimelapseApi/TimelapseSettings.cs b/TimelapseApi/TimelapseSettings.cs
index 259cbec..83d4408 100644
--- a/TimelapseApi/TimelapseSettings.cs
+++ b/TimelapseApi/TimelapseSettings.cs
@@ -133,9 +133,11 @@ internal class TimelapseSettings : Dialog
Button installExtension = new Button{
Text="Install Extension"
};
- CheckBox enableExt=new CheckBox();
- enableExt.Text="Add extensions on install";
+ CheckBox enableExt=new CheckBox{Text="Add extensions on install"};
enableExt.Checked = api.Model.addExtensionOnInstall;
+
+ CheckBox useCustomFilePickerForNativeFS = new CheckBox{Text="Use Custom File Picker For Native FileSystem"};
+ useCustomFilePickerForNativeFS.Checked=api.Model.useCustomFilePickerForNativeFS;
installExtension.Click += async(sender,e)=>{
using(var ofd=new OpenFileDialog())
{
@@ -205,6 +207,8 @@ internal class TimelapseSettings : Dialog
lyt2.AddRow(lyt);
lyt2.AddRow(installExtension);
lyt2.AddRow(enableExt);
+ lyt2.AddRow(useCustomFilePickerForNativeFS);
+
lyt2.AddRow(null);
lyt2.EndVertical();
@@ -222,6 +226,7 @@ internal class TimelapseSettings : Dialog
api.Model.enableWebServer=enableServer.Checked.GetValueOrDefault();
api.Model.timelapsePort=(ushort)stepper.Value;
api.Model.addExtensionOnInstall = enableExt.Checked.GetValueOrDefault();
+ api.Model.useCustomFilePickerForNativeFS = useCustomFilePickerForNativeFS.Checked.GetValueOrDefault();
foreach(var item in coll.Items)
{
if(!item.OverlayChecked)
@@ -235,6 +240,7 @@ internal class TimelapseSettings : Dialog
}
api.SaveModel();
+ this.Close();
};
lyt1.EndBeginHorizontal();
diff --git a/TimelapseApi/TimelapseSettingsModel.cs b/TimelapseApi/TimelapseSettingsModel.cs
index a519f34..e5c8866 100644
--- a/TimelapseApi/TimelapseSettingsModel.cs
+++ b/TimelapseApi/TimelapseSettingsModel.cs
@@ -13,6 +13,7 @@ public class TimelapseSettingsModel
addExtensionOnInstall=true;
}
+ public bool useCustomFilePickerForNativeFS {get;set;}
public bool addExtensionOnInstall {get;set;}
public bool canOverlayVideo {get;set;}
public bool canBlockFrames {get;set;}