using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; using Gallery.Util.Model; using Newtonsoft.Json; using Xamarin.Essentials; using Xamarin.Forms; namespace Gallery.Util { public static class Store { public static readonly string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal); public static readonly string CacheFolder = FileSystem.CacheDirectory; private const string favoriteFile = "favorites.json"; private const string imageFolder = "img-original"; private const string previewFolder = "img-preview"; public static FavoriteList FavoriteList => GetFavoriteList(); public static string FavoriteListPath => Path.Combine(PersonalFolder, favoriteFile); private static FavoriteList favoriteList; public static FavoriteList GetFavoriteList(bool force = false) { if (force || favoriteList == null) { var favorites = LoadFavoriteList(); if (favorites != null) { favoriteList = favorites; } else { favoriteList = new FavoriteList(); } } return favoriteList; } private static FavoriteList LoadFavoriteList(string file = null) { if (file == null) { file = FavoriteListPath; } return LoadObject<FavoriteList>(file); } public static void SaveFavoriteList() { var file = FavoriteListPath; WriteObject(file, FavoriteList); } private static T LoadObject<T>(string file) { string content = null; if (File.Exists(file)) { try { content = File.ReadAllText(file); } catch (Exception ex) { Log.Error("file.read", $"failed to read file: {file}, error: {ex.Message}"); } } else { return default; } try { return JsonConvert.DeserializeObject<T>(content); } catch (Exception ex) { Log.Error("file.deserialize", $"failed to parse JSON object, error: {ex.Message}"); return default; } } private static void WriteObject(string file, object obj) { var folder = Path.GetDirectoryName(file); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } string content; try { content = JsonConvert.SerializeObject(obj, Formatting.None); } catch (Exception ex) { Log.Error("object.serialize", $"failed to serialize object, error: {ex.Message}"); return; } try { File.WriteAllText(file, content, Encoding.UTF8); } catch (Exception ex) { Log.Error("file.write", $"failed to write file: {file}, error: {ex.Message}"); } } public static async Task<ImageSource> LoadRawImage(GalleryItem item, bool downloading, bool force = false, Action<(int loc, int size)> action = null) { return await LoadImageAsync(item.RawUrl, null, PersonalFolder, Path.Combine(imageFolder, item.Source), downloading, force, action); } public static string GetRawImagePath(GalleryItem item) { var file = Path.Combine(PersonalFolder, imageFolder, item.Source, Path.GetFileName(item.RawUrl)); if (File.Exists(file)) { return file; } return null; } public static async Task<ImageSource> LoadPreviewImage(GalleryItem item, bool downloading, bool force = false) { return await LoadImage(item.PreviewUrl, CacheFolder, Path.Combine(previewFolder, item.Source), downloading, force); } private static async Task<ImageSource> LoadImage(string url, string working, string folder, bool downloading, bool force) { var file = Path.Combine(working, folder, Path.GetFileName(url)); ImageSource image; if (!force && File.Exists(file)) { image = ImageSource.FromFile(file); } else { image = null; } if (downloading && image == null) { file = await NetHelper.DownloadImage(url, working, folder); if (file != null) { return ImageSource.FromFile(file); } } return image; } private static async Task<ImageSource> LoadImageAsync(string url, string id, string working, string folder, bool downloading, bool force, Action<(int loc, int size)> action) { var file = Path.Combine(working, folder, Path.GetFileName(url)); ImageSource image; if (!force && File.Exists(file)) { image = ImageSource.FromFile(file); } else { image = null; } if (downloading && image == null) { file = await NetHelper.DownloadImageAsync(url, id, working, folder, action); if (file != null) { image = ImageSource.FromFile(file); } } return image; } } public class FavoriteList : List<GalleryItem> { public bool Changed { get; private set; } public FavoriteList() : base() { } public FavoriteList(IEnumerable<GalleryItem> collection) : base(collection) { } public new void Insert(int index, GalleryItem item) { base.Insert(index, item); Changed = true; } public new void InsertRange(int index, IEnumerable<GalleryItem> collection) { base.InsertRange(index, collection); Changed = true; } public new void RemoveAt(int index) { base.RemoveAt(index); Changed = true; } public FavoriteList Reload() { Changed = false; return this; } } }