DI 注入文件系统,web平台不支持System.IO.File
parent
a02aeca6df
commit
09d8bc7ba8
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Notes.Android;
|
||||
|
||||
class FileService : IFileService
|
||||
{
|
||||
public string Combine(string args0, string args1)
|
||||
{
|
||||
return Path.Combine(args0, args1);
|
||||
}
|
||||
|
||||
public string GetRandomFileName()
|
||||
{
|
||||
return Path.GetRandomFileName();
|
||||
}
|
||||
|
||||
public IEnumerable<string> EnumerateFiles(string path, string patten)
|
||||
{
|
||||
return Directory.EnumerateFiles(path, patten);
|
||||
}
|
||||
|
||||
public string GetFileName(string filename)
|
||||
{
|
||||
return Path.GetFileName(filename);
|
||||
}
|
||||
|
||||
public string ReadAllText(string filename)
|
||||
{
|
||||
return File.ReadAllText(filename);
|
||||
}
|
||||
|
||||
public DateTime GetLastWriteTime(string filename)
|
||||
{
|
||||
return File.GetLastWriteTime(filename);
|
||||
}
|
||||
|
||||
public bool ExistsFile(string filename)
|
||||
{
|
||||
return File.Exists(filename);
|
||||
}
|
||||
|
||||
public void Delete(string path)
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
|
||||
public void WriteAllText(string path, string text)
|
||||
{
|
||||
File.WriteAllText(path, text);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using Android.Content.PM;
|
|||
using Avalonia;
|
||||
using Avalonia.Android;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Notes.ViewModels;
|
||||
|
||||
namespace Notes.Android;
|
||||
|
||||
|
@ -16,6 +17,10 @@ public class MainActivity : AvaloniaMainActivity<App>
|
|||
{
|
||||
protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
|
||||
{
|
||||
|
||||
var services = new Services();
|
||||
services.Register<IFileService>(new FileService());
|
||||
App.services = services;
|
||||
return base.CustomizeAppBuilder(builder)
|
||||
.WithInterFont()
|
||||
.UseReactiveUI();
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
|
||||
<WasmMainJSPath>AppBundle\main.js</WasmMainJSPath>
|
||||
<OutputType>Exe</OutputType>
|
||||
<WasmAllowUndefinedSymbols>true</WasmAllowUndefinedSymbols>
|
||||
<MSBuildDebugEngine>1</MSBuildDebugEngine>
|
||||
<WasmBuildNative>true</WasmBuildNative>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Notes.Desktop;
|
||||
|
||||
class FileService: IFileService
|
||||
{
|
||||
public string Combine(string args0, string args1)
|
||||
{
|
||||
return Path.Combine(args0, args1);
|
||||
}
|
||||
|
||||
public string GetRandomFileName()
|
||||
{
|
||||
return Path.GetRandomFileName();
|
||||
}
|
||||
|
||||
public IEnumerable<string> EnumerateFiles(string path, string patten)
|
||||
{
|
||||
return Directory.EnumerateFiles(path,patten);
|
||||
}
|
||||
|
||||
public string GetFileName(string filename)
|
||||
{
|
||||
return Path.GetFileName(filename);
|
||||
}
|
||||
|
||||
public string ReadAllText(string filename)
|
||||
{
|
||||
return File.ReadAllText(filename);
|
||||
}
|
||||
|
||||
public DateTime GetLastWriteTime(string filename)
|
||||
{
|
||||
return File.GetLastWriteTime(filename);
|
||||
}
|
||||
|
||||
public bool ExistsFile(string filename)
|
||||
{
|
||||
return File.Exists(filename);
|
||||
}
|
||||
|
||||
public void Delete(string path)
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
|
||||
public void WriteAllText(string path, string text)
|
||||
{
|
||||
File.WriteAllText(path,text);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Notes.ViewModels;
|
||||
|
||||
namespace Notes.Desktop;
|
||||
|
||||
|
@ -10,8 +11,14 @@ sealed class Program
|
|||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var services = new Services();
|
||||
services.Register<IFileService>(new FileService());
|
||||
App.services = services;
|
||||
BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
}
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
|
|
|
@ -8,9 +8,12 @@ namespace Notes;
|
|||
|
||||
public partial class App : Application
|
||||
{
|
||||
public static IServices services { get; set; }
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
FileSystem.fileService = services.GetSafeAs<IFileService>();
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Notes;
|
||||
|
||||
public interface IFileService
|
||||
{
|
||||
string Combine(string args0, string args1);
|
||||
string GetRandomFileName();
|
||||
IEnumerable<string> EnumerateFiles(string path, string patten);
|
||||
string GetFileName(string filename);
|
||||
string ReadAllText(string filename);
|
||||
DateTime GetLastWriteTime(string filename);
|
||||
bool ExistsFile(string filename);
|
||||
void Delete(string path);
|
||||
void WriteAllText(string path, string text);
|
||||
}
|
||||
|
||||
public static class FileSystem
|
||||
{
|
||||
public static IFileService fileService;
|
||||
|
||||
public static string Combine(string args0, string args1)
|
||||
{
|
||||
return fileService.Combine(args0, args1);
|
||||
}
|
||||
|
||||
public static string GetRandomFileName()
|
||||
{
|
||||
return fileService.GetRandomFileName();
|
||||
}
|
||||
|
||||
public static IEnumerable<string> EnumerateFiles(string path, string patten)
|
||||
{
|
||||
return fileService.EnumerateFiles(path, patten);
|
||||
}
|
||||
|
||||
public static string GetFileName(string filename)
|
||||
{
|
||||
return fileService.GetFileName(filename);
|
||||
}
|
||||
|
||||
public static string ReadAllText(string filename)
|
||||
{
|
||||
return fileService.ReadAllText(filename);
|
||||
}
|
||||
|
||||
public static DateTime GetLastWriteTime(string filename)
|
||||
{
|
||||
return fileService.GetLastWriteTime(filename);
|
||||
}
|
||||
|
||||
public static bool ExistsFile(string filename)
|
||||
{
|
||||
return fileService.ExistsFile(filename);
|
||||
}
|
||||
|
||||
public static void Delete(string filename)
|
||||
{
|
||||
fileService.Delete(filename);
|
||||
}
|
||||
|
||||
public static void WriteAllText(string path, string text)
|
||||
{
|
||||
fileService.WriteAllText(path, text);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Utils;
|
||||
|
||||
|
@ -20,37 +19,37 @@ public class Note
|
|||
{
|
||||
get
|
||||
{
|
||||
var appDataDirectory = Path.Combine(AppContext.BaseDirectory, "Data");
|
||||
var appDataDirectory = FileSystem.Combine(AppContext.BaseDirectory, "Data");
|
||||
IOUtils.EnsureDirectory(appDataDirectory,false);
|
||||
return appDataDirectory;
|
||||
}
|
||||
}
|
||||
public Note()
|
||||
{
|
||||
Filename = $"{Path.GetRandomFileName()}{Extension}";
|
||||
Filename = $"{FileSystem.GetRandomFileName()}{Extension}";
|
||||
Date = DateTime.Now;
|
||||
Text = "";
|
||||
}
|
||||
|
||||
public void Save() =>
|
||||
File.WriteAllText(Path.Combine(AppDataDirectory, Filename), Text);
|
||||
FileSystem.WriteAllText(FileSystem.Combine(AppDataDirectory, Filename), Text);
|
||||
|
||||
public void Delete() =>
|
||||
File.Delete(Path.Combine(AppDataDirectory, Filename));
|
||||
FileSystem.Delete(FileSystem.Combine(AppDataDirectory, Filename));
|
||||
|
||||
public static Note Load(string filename)
|
||||
{
|
||||
filename = Path.Combine(AppDataDirectory, filename);
|
||||
filename = FileSystem.Combine(AppDataDirectory, filename);
|
||||
|
||||
if (!File.Exists(filename))
|
||||
throw new FileNotFoundException("Unable to find file on local storage.", filename);
|
||||
if (!FileSystem.ExistsFile(filename))
|
||||
throw new InvalidOperationException($"Unable to find file '{filename}' on local storage.");
|
||||
|
||||
return
|
||||
new()
|
||||
{
|
||||
Filename = Path.GetFileName(filename),
|
||||
Text = File.ReadAllText(filename),
|
||||
Date = File.GetLastWriteTime(filename)
|
||||
Filename = FileSystem.GetFileName(filename),
|
||||
Text = FileSystem.ReadAllText(filename),
|
||||
Date = FileSystem.GetLastWriteTime(filename)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -60,13 +59,13 @@ public class Note
|
|||
string appDataPath = AppDataDirectory;
|
||||
|
||||
// Use Linq extensions to load the *.notes.txt files.
|
||||
return Directory
|
||||
return FileSystem
|
||||
|
||||
// Select the file names from the directory
|
||||
.EnumerateFiles(appDataPath, "*.notes.txt")
|
||||
|
||||
// Each file name is used to load a note
|
||||
.Select(filename => Load(Path.GetFileName(filename)))
|
||||
.Select(filename => Load(FileSystem.GetFileName(filename)))
|
||||
|
||||
// With the final collection of notes, order them by date
|
||||
.OrderByDescending(note => note.Date);
|
||||
|
|
|
@ -14,7 +14,7 @@ public partial class AboutViewModel:ViewModelBase
|
|||
[RelayCommand]
|
||||
public void ShowAllNotes()
|
||||
{
|
||||
_services.GetAs<MainViewModel>().Navitation<AllNotesViewModel>(this._services);
|
||||
_services.GetSafeAs<MainViewModel>().Navitation<AllNotesViewModel>(this._services);
|
||||
}
|
||||
|
||||
[Obsolete("Used by designer",true)]
|
||||
|
|
|
@ -26,7 +26,7 @@ public partial class AllNotesViewModel: ViewModelBase
|
|||
{
|
||||
var note = new Note();
|
||||
note.Filename = string.Empty;
|
||||
this._services.GetAs<MainViewModel>().Navitation<NoteViewModel>(this._services,this,note);
|
||||
this._services.GetSafeAs<MainViewModel>().Navitation<NoteViewModel>(this._services,this,note);
|
||||
}
|
||||
[RelayCommand]
|
||||
public void DeleteNote(ISelectionModel selectionModel)
|
||||
|
@ -43,7 +43,7 @@ public partial class AllNotesViewModel: ViewModelBase
|
|||
[RelayCommand]
|
||||
public void OpenAbout()
|
||||
{
|
||||
this._services.GetAs<MainViewModel>().Navitation<AboutViewModel>(this._services);
|
||||
this._services.GetSafeAs<MainViewModel>().Navitation<AboutViewModel>(this._services);
|
||||
}
|
||||
|
||||
[Obsolete("Used by designer",true)]
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
namespace Notes.ViewModels;
|
||||
|
||||
public interface IServices
|
||||
{
|
||||
void Register<T>(T t);
|
||||
T? Get<T>();
|
||||
T GetSafeAs<T>();
|
||||
}
|
|
@ -1,40 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Utils;
|
||||
|
||||
namespace Notes.ViewModels;
|
||||
|
||||
public interface IServices
|
||||
{
|
||||
void Register<T>(T t);
|
||||
T? Get<T>();
|
||||
T GetAs<T>();
|
||||
}
|
||||
|
||||
public sealed class Sevices:IServices
|
||||
{
|
||||
private readonly Dictionary<Type, object?> map = new Dictionary<Type, object?>();
|
||||
public void Register<T>(T t)
|
||||
{
|
||||
map.Add(typeof(T), t);
|
||||
}
|
||||
|
||||
public T? Get<T>()
|
||||
{
|
||||
map.TryGetValue(typeof(T), out var t);
|
||||
return (T?)t;
|
||||
}
|
||||
|
||||
public T GetAs<T>()
|
||||
{
|
||||
T? foo = this.Get<T?>();
|
||||
if (foo is { } t)
|
||||
return t;
|
||||
throw new InvalidOperationException($"Not find type '{typeof(T)}'");
|
||||
}
|
||||
}
|
||||
public partial class MainViewModel:ViewModelBase
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -47,7 +17,7 @@ public partial class MainViewModel:ViewModelBase
|
|||
|
||||
public MainViewModel()
|
||||
{
|
||||
_service = new Sevices();
|
||||
_service = App.services;
|
||||
_service.Register(this);
|
||||
_contentViewModel = new AboutViewModel(_service);
|
||||
}
|
||||
|
|
|
@ -51,13 +51,13 @@ public partial class NoteViewModel : ViewModelBase
|
|||
|
||||
public void Back()
|
||||
{
|
||||
_services.GetAs<MainViewModel>().Navitation<AllNotesViewModel>(this._services);
|
||||
_services.GetSafeAs<MainViewModel>().Navitation<AllNotesViewModel>(this._services);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void OpenNote()
|
||||
{
|
||||
this._services.GetAs<MainViewModel>().Navitation<NoteViewModel>(this._services, this.AllNotesViewModel, this.Note);
|
||||
this._services.GetSafeAs<MainViewModel>().Navitation<NoteViewModel>(this._services, this.AllNotesViewModel, this.Note);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Notes.ViewModels;
|
||||
|
||||
public sealed class Services:IServices
|
||||
{
|
||||
private readonly Dictionary<Type, object?> map = new Dictionary<Type, object?>();
|
||||
public void Register<T>(T t)
|
||||
{
|
||||
this.map.Add(typeof(T), t);
|
||||
}
|
||||
|
||||
public T? Get<T>()
|
||||
{
|
||||
this.map.TryGetValue(typeof(T), out var t);
|
||||
return (T?)t;
|
||||
}
|
||||
|
||||
public T GetSafeAs<T>()
|
||||
{
|
||||
T? foo = this.Get<T?>();
|
||||
if (foo is { } t)
|
||||
return t;
|
||||
throw new InvalidOperationException($"Not find type '{typeof(T)}'");
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ public partial class MainView : UserControl
|
|||
{
|
||||
public MainView()
|
||||
{
|
||||
DataContext = new MainViewModel();
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue