From c8878722f484b1a09016f5f9e7439cf025e9357d Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Fri, 20 May 2022 00:22:28 -0500 Subject: [PATCH] Sorry that the README is not complete --- .../.vs/TimelapseApi/xs/UserPrefs.xml | 17 + TimelapseApi/Api.cs | 5 +- TimelapseApi/Assets/directory.png | Bin 0 -> 126 bytes TimelapseApi/Assets/file.png | Bin 0 -> 130 bytes TimelapseApi/TimelapseApi.csproj | 5 +- TimelapseApi/TimelapseFileSystem.cs | 380 +++++++++++++++++- TimelapseApi/TimelapseSettings.cs | 10 +- TimelapseApi/TimelapseSettingsModel.cs | 1 + 8 files changed, 408 insertions(+), 10 deletions(-) create mode 100644 TimelapseApi/.vs/TimelapseApi/xs/UserPrefs.xml create mode 100644 TimelapseApi/Assets/directory.png create mode 100644 TimelapseApi/Assets/file.png 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 0000000000000000000000000000000000000000..548cd005881229892fd1e939ae802e217bb0d02e GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9oB=)|u0R?H{{LrKcV8hM$YL%D z@(Tv?T>`Et0=bHwE{-7;bCMGpn6C*a9Nfm@r^8#CkPyAKOW>dsR|q>hgS<7r@S~kV Q5+GwdUHx3vIVCg!0MthxL;wH) literal 0 HcmV?d00001 diff --git a/TimelapseApi/Assets/file.png b/TimelapseApi/Assets/file.png new file mode 100644 index 0000000000000000000000000000000000000000..628885c6bd6e4804279d2a87313a8251c114e505 GIT binary patch literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9oB=)|u0R?H{{LrKcV8hM$YL%D z@(Tv?T>`Et0=cT5E{-7;bCMGpn6F)6U}M`B8tibyN5JqZqsJO0mkn)gRth|f4Bh4e UkHVX0uK*e4>FVdQ&MBb@0ES#5o&W#< literal 0 HcmV?d00001 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;}