using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Billing.Models; using Billing.UI; using Xamarin.Essentials; using Resource = Billing.Languages.Resource; namespace Billing.Store { public class StoreHelper { public static readonly string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal); public static readonly string CacheFolder = FileSystem.CacheDirectory; private const string accountFile = "accounts.xml"; private const string billFile = "bills.xml"; private const string categoryFile = "categories.xml"; private static StoreHelper instance; private static StoreHelper Instance => instance ??= new StoreHelper(); public static List GetAccounts() => Instance.GetAccountsInternal(); public static void WriteAccounts(IEnumerable accounts) => Instance.WriteAccountsInternal(accounts); public static List GetBills() => Instance.GetBillsInternal(); public static void WriteBills(IEnumerable bills) => Instance.WriteBillsInternal(bills); public static List GetCategories() => Instance.GetCategoriesInternal(); public static void WriteCategories(IEnumerable categories) => Instance.WriteCategoriesInternal(categories); private StoreHelper() { } private List GetAccountsInternal() { return GetList(Path.Combine(PersonalFolder, accountFile)); } private void WriteAccountsInternal(IEnumerable accounts) { var filename = Path.Combine(PersonalFolder, accountFile); WriteList(filename, accounts); } private List GetBillsInternal() { return GetList(Path.Combine(PersonalFolder, billFile)); } private void WriteBillsInternal(IEnumerable bills) { var filename = Path.Combine(PersonalFolder, billFile); WriteList(filename, bills); } private List GetCategoriesInternal() { var list = GetList(Path.Combine(PersonalFolder, categoryFile)); if (list == null || list.Count == 0) { list = new List { // TODO: sample categories new() { Id = 1, Name = Resource.Clothing, Icon = "clothes" }, new() { Id = 2, Name = Resource.Food, Icon = "food" }, new() { Id = 3, Name = Resource.Drinks, Icon = "drink" }, new() { Id = 4, Name = Resource.Daily, Icon = "daily" }, new() { Id = 5, Name = Resource.Trans, Icon = "trans" }, new() { Id = 6, Name = Resource.Entertainment, Icon = "face" }, new() { Id = 7, Name = Resource.Learn, Icon = "learn" }, new() { Id = 8, Name = Resource.Medical, Icon = "medical" }, new() { Id = 9, Type = CategoryType.Income, Name = Resource.Salary, Icon = "#brand#buffer" }, new() { Id = 10, Type = CategoryType.Income, Name = Resource.Earnings, Icon = "#brand#btc" }, new() { Id = 20, Type = CategoryType.Income, Name = Resource.Bonus, Icon = "dollar" } }; Task.Run(() => WriteCategoriesInternal(list)); } return list; } private void WriteCategoriesInternal(IEnumerable categories) { var filename = Path.Combine(PersonalFolder, categoryFile); WriteList(filename, categories); } #region Helper private void WriteList(string filename, IEnumerable list) where T : IModel, new() { if (list == null) { return; } try { using var stream = File.Open(filename, FileMode.Create); list.ToStream(stream); } catch (Exception ex) { Helper.Error("file.write", $"failed to write file: {filename}, error: {ex.Message}"); } } private List GetList(string file) where T : IModel, new() { try { if (File.Exists(file)) { using var stream = File.OpenRead(file); var list = ModelExtensionHelper.FromStream(stream); return list; } } catch (Exception ex) { Helper.Error("file.read", $"failed to read file: {file}, error: {ex.Message}"); } return default; } #endregion } }