fix crash of sqlite in release mode
This commit is contained in:
		@@ -30,7 +30,6 @@ namespace Billing
 | 
			
		||||
            InitResources();
 | 
			
		||||
 | 
			
		||||
            MainPage = new MainShell();
 | 
			
		||||
            //Shell.Current.GoToAsync("//Splash");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void OnStart()
 | 
			
		||||
@@ -39,12 +38,13 @@ namespace Billing
 | 
			
		||||
            Helper.Debug($"cache folder: {StoreHelper.CacheFolder}");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal static async Task InitializeData()
 | 
			
		||||
        public static async Task InitializeData()
 | 
			
		||||
        {
 | 
			
		||||
            var instance = await StoreHelper.Instance;
 | 
			
		||||
            await Task.WhenAll(
 | 
			
		||||
                Task.Run(async () => accounts = await StoreHelper.GetAccountsAsync()),
 | 
			
		||||
                Task.Run(async () => categories = await StoreHelper.GetCategoriesAsync()),
 | 
			
		||||
                Task.Run(async () => bills = await StoreHelper.GetBillsAsync()));
 | 
			
		||||
                Task.Run(async () => accounts = await instance.GetListAsync<Account>()),
 | 
			
		||||
                Task.Run(async () => categories = await instance.GetListAsync<Category>()),
 | 
			
		||||
                Task.Run(async () => bills = await instance.GetListAsync<Bill>()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void OnResume()
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ namespace Billing
 | 
			
		||||
 | 
			
		||||
        public static void Error(string category, Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            MainThread.BeginInvokeOnMainThread(async () => await Shell.Current.DisplayAlert(category, ex.ToString(), "Ok"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Error(string category, string message)
 | 
			
		||||
@@ -139,15 +140,10 @@ namespace Billing
 | 
			
		||||
        public delegate void PropertyValueChanged<TResult, TOwner>(TOwner obj, TResult old, TResult @new);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal class AsyncLazy<T>
 | 
			
		||||
    public class AsyncLazy<T>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Lazy<Task<T>> instance;
 | 
			
		||||
 | 
			
		||||
        public AsyncLazy(Func<T> factory)
 | 
			
		||||
        {
 | 
			
		||||
            instance = new Lazy<Task<T>>(() => Task.Run(factory));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public AsyncLazy(Func<Task<T>> factory)
 | 
			
		||||
        {
 | 
			
		||||
            instance = new Lazy<Task<T>>(() => Task.Run(factory));
 | 
			
		||||
 
 | 
			
		||||
@@ -28,68 +28,97 @@ namespace Billing.Store
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if (database != null)
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await database.CloseAsync();
 | 
			
		||||
                if (database != null)
 | 
			
		||||
                {
 | 
			
		||||
                    await database.CloseAsync();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Helper.Error("database.close", ex);
 | 
			
		||||
            }
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                File.Copy(file, path, true);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Helper.Error("file.import", ex);
 | 
			
		||||
            }
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                database = new SQLiteAsyncConnection(path,
 | 
			
		||||
                    SQLiteOpenFlags.ReadWrite |
 | 
			
		||||
                    SQLiteOpenFlags.Create |
 | 
			
		||||
                    SQLiteOpenFlags.SharedCache);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Helper.Error("database.connect", ex);
 | 
			
		||||
            }
 | 
			
		||||
            File.Copy(file, path, true);
 | 
			
		||||
            database = new SQLiteAsyncConnection(path,
 | 
			
		||||
                SQLiteOpenFlags.ReadWrite |
 | 
			
		||||
                SQLiteOpenFlags.Create |
 | 
			
		||||
                SQLiteOpenFlags.SharedCache);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static readonly AsyncLazy<StoreHelper> Instance = new(async () =>
 | 
			
		||||
        public static readonly AsyncLazy<StoreHelper> Instance = new(async () =>
 | 
			
		||||
        {
 | 
			
		||||
            var instance = new StoreHelper();
 | 
			
		||||
            await database.CreateTablesAsync<Category, Account, Bill>();
 | 
			
		||||
            var count = await database.ExecuteScalarAsync<int>("SELECT COUNT(Id) FROM [Category]");
 | 
			
		||||
            if (count <= 0)
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                // init categories
 | 
			
		||||
                await database.InsertAllAsync(new List<Category>
 | 
			
		||||
                await database.CreateTablesAsync<Category, Account, Bill>();
 | 
			
		||||
            } catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Helper.Error("database.init.table", ex);
 | 
			
		||||
            }
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var count = await database.ExecuteScalarAsync<int>("SELECT COUNT(Id) FROM [Category]");
 | 
			
		||||
                if (count <= 0)
 | 
			
		||||
                {
 | 
			
		||||
                    // sample categories
 | 
			
		||||
                    new() { Name = Resource.Clothing, Icon = "clothes" },
 | 
			
		||||
                    new() { Name = Resource.Food, Icon = "food" },
 | 
			
		||||
                    new() { Name = Resource.Daily, Icon = "daily" },
 | 
			
		||||
                    new() { Name = Resource.Trans, Icon = "trans" },
 | 
			
		||||
                    new() { Name = Resource.Entertainment, Icon = "face" },
 | 
			
		||||
                    new() { Name = Resource.Learn, Icon = "learn" },
 | 
			
		||||
                    new() { Name = Resource.Medical, Icon = "medical" },
 | 
			
		||||
                    new() { Name = Resource.OtherSpending, Icon = "plus" },
 | 
			
		||||
                    // init categories
 | 
			
		||||
                    await database.InsertAllAsync(new List<Category>
 | 
			
		||||
                    {
 | 
			
		||||
                        // sample categories
 | 
			
		||||
                        new() { Name = Resource.Clothing, Icon = "clothes" },
 | 
			
		||||
                        new() { Name = Resource.Food, Icon = "food" },
 | 
			
		||||
                        new() { Name = Resource.Daily, Icon = "daily" },
 | 
			
		||||
                        new() { Name = Resource.Trans, Icon = "trans" },
 | 
			
		||||
                        new() { Name = Resource.Entertainment, Icon = "face" },
 | 
			
		||||
                        new() { Name = Resource.Learn, Icon = "learn" },
 | 
			
		||||
                        new() { Name = Resource.Medical, Icon = "medical" },
 | 
			
		||||
                        new() { Name = Resource.OtherSpending, Icon = "plus" },
 | 
			
		||||
 | 
			
		||||
                    new() { Type = CategoryType.Income, Name = Resource.Earnings, Icon = "#brand#btc" },
 | 
			
		||||
                    new() { Type = CategoryType.Income, Name = Resource.OtherIncome, Icon = "plus" },
 | 
			
		||||
                        new() { Type = CategoryType.Income, Name = Resource.Earnings, Icon = "#brand#btc" },
 | 
			
		||||
                        new() { Type = CategoryType.Income, Name = Resource.OtherIncome, Icon = "plus" },
 | 
			
		||||
 | 
			
		||||
                    // sub-categories
 | 
			
		||||
                    new() { ParentId = 1, Name = Resource.Jewellery, Icon = "gem" },
 | 
			
		||||
                    new() { ParentId = 1, Name = Resource.Cosmetics, Icon = "makeup" },
 | 
			
		||||
                    new() { ParentId = 2, Name = Resource.Brunch, Icon = "brunch" },
 | 
			
		||||
                    new() { ParentId = 2, Name = Resource.Dinner, Icon = "dinner" },
 | 
			
		||||
                    new() { ParentId = 2, Name = Resource.Drinks, Icon = "drink" },
 | 
			
		||||
                    new() { ParentId = 2, Name = Resource.Fruit, Icon = "fruit" },
 | 
			
		||||
                    new() { ParentId = 3, Name = Resource.UtilityBill, Icon = "bill" },
 | 
			
		||||
                    new() { ParentId = 3, Name = Resource.PropertyFee, Icon = "fee" },
 | 
			
		||||
                    new() { ParentId = 3, Name = Resource.Rent, Icon = "rent" },
 | 
			
		||||
                    new() { ParentId = 3, Name = Resource.Maintenance, Icon = "maintenance" },
 | 
			
		||||
                    new() { ParentId = 4, Name = Resource.LightRail, Icon = "rail" },
 | 
			
		||||
                    new() { ParentId = 4, Name = Resource.Taxi, Icon = "taxi" },
 | 
			
		||||
                    new() { ParentId = 5, Name = Resource.Fitness, Icon = "fitness" },
 | 
			
		||||
                    new() { ParentId = 5, Name = Resource.Party, Icon = "party" },
 | 
			
		||||
                    new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Salary, Icon = "#brand#buffer" },
 | 
			
		||||
                    new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Bonus, Icon = "dollar" },
 | 
			
		||||
                });
 | 
			
		||||
                        // sub-categories
 | 
			
		||||
                        new() { ParentId = 1, Name = Resource.Jewellery, Icon = "gem" },
 | 
			
		||||
                        new() { ParentId = 1, Name = Resource.Cosmetics, Icon = "makeup" },
 | 
			
		||||
                        new() { ParentId = 2, Name = Resource.Brunch, Icon = "brunch" },
 | 
			
		||||
                        new() { ParentId = 2, Name = Resource.Dinner, Icon = "dinner" },
 | 
			
		||||
                        new() { ParentId = 2, Name = Resource.Drinks, Icon = "drink" },
 | 
			
		||||
                        new() { ParentId = 2, Name = Resource.Fruit, Icon = "fruit" },
 | 
			
		||||
                        new() { ParentId = 3, Name = Resource.UtilityBill, Icon = "bill" },
 | 
			
		||||
                        new() { ParentId = 3, Name = Resource.PropertyFee, Icon = "fee" },
 | 
			
		||||
                        new() { ParentId = 3, Name = Resource.Rent, Icon = "rent" },
 | 
			
		||||
                        new() { ParentId = 3, Name = Resource.Maintenance, Icon = "maintenance" },
 | 
			
		||||
                        new() { ParentId = 4, Name = Resource.LightRail, Icon = "rail" },
 | 
			
		||||
                        new() { ParentId = 4, Name = Resource.Taxi, Icon = "taxi" },
 | 
			
		||||
                        new() { ParentId = 5, Name = Resource.Fitness, Icon = "fitness" },
 | 
			
		||||
                        new() { ParentId = 5, Name = Resource.Party, Icon = "party" },
 | 
			
		||||
                        new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Salary, Icon = "#brand#buffer" },
 | 
			
		||||
                        new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Bonus, Icon = "dollar" },
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Helper.Error("database.init.category", ex);
 | 
			
		||||
            }
 | 
			
		||||
            return instance;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        public static async Task<List<Account>> GetAccountsAsync()
 | 
			
		||||
        {
 | 
			
		||||
            var instance = await Instance;
 | 
			
		||||
            return await instance.GetListAsync<Account>();
 | 
			
		||||
        }
 | 
			
		||||
        public static async Task<int> SaveAccountItemAsync(Account account)
 | 
			
		||||
        {
 | 
			
		||||
            var instance = await Instance;
 | 
			
		||||
@@ -101,11 +130,6 @@ namespace Billing.Store
 | 
			
		||||
            return await instance.DeleteItemAsync(account);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task<List<Bill>> GetBillsAsync()
 | 
			
		||||
        {
 | 
			
		||||
            var instance = await Instance;
 | 
			
		||||
            return await instance.GetListAsync<Bill>();
 | 
			
		||||
        }
 | 
			
		||||
        public static async Task<int> SaveBillItemAsync(Bill bill)
 | 
			
		||||
        {
 | 
			
		||||
            var instance = await Instance;
 | 
			
		||||
@@ -117,11 +141,6 @@ namespace Billing.Store
 | 
			
		||||
            return await instance.DeleteItemAsync(bill);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task<List<Category>> GetCategoriesAsync()
 | 
			
		||||
        {
 | 
			
		||||
            var instance = await Instance;
 | 
			
		||||
            return await instance.GetListAsync<Category>();
 | 
			
		||||
        }
 | 
			
		||||
        public static async Task<int> SaveCategoryItemAsync(Category category)
 | 
			
		||||
        {
 | 
			
		||||
            var instance = await Instance;
 | 
			
		||||
@@ -137,10 +156,17 @@ namespace Billing.Store
 | 
			
		||||
        {
 | 
			
		||||
            if (database == null)
 | 
			
		||||
            {
 | 
			
		||||
                database = new SQLiteAsyncConnection(DatabasePath,
 | 
			
		||||
                    SQLiteOpenFlags.ReadWrite |
 | 
			
		||||
                    SQLiteOpenFlags.Create |
 | 
			
		||||
                    SQLiteOpenFlags.SharedCache);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    database = new SQLiteAsyncConnection(DatabasePath,
 | 
			
		||||
                        SQLiteOpenFlags.ReadWrite |
 | 
			
		||||
                        SQLiteOpenFlags.Create |
 | 
			
		||||
                        SQLiteOpenFlags.SharedCache);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Helper.Error("database.ctor.connect", ex);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -178,7 +204,7 @@ namespace Billing.Store
 | 
			
		||||
 | 
			
		||||
        #region Helper
 | 
			
		||||
 | 
			
		||||
        private Task<List<T>> GetListAsync<T>() where T : new()
 | 
			
		||||
        public Task<List<T>> GetListAsync<T>() where T : new()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
@@ -191,7 +217,7 @@ namespace Billing.Store
 | 
			
		||||
            return default;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task<int> SaveItemAsync<T>(T item) where T : IIdItem
 | 
			
		||||
        public Task<int> SaveItemAsync<T>(T item) where T : IIdItem
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
@@ -211,7 +237,7 @@ namespace Billing.Store
 | 
			
		||||
            return Task.FromResult(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task<int> DeleteItemAsync<T>(T item) where T : IIdItem
 | 
			
		||||
        public Task<int> DeleteItemAsync<T>(T item) where T : IIdItem
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,6 @@
 | 
			
		||||
    <Reference Include="System" />
 | 
			
		||||
    <Reference Include="System.Core" />
 | 
			
		||||
    <Reference Include="System.Numerics" />
 | 
			
		||||
    <Reference Include="System.Numerics.Vectors" />
 | 
			
		||||
    <Reference Include="System.Xml.Linq" />
 | 
			
		||||
    <Reference Include="System.Xml" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.10.311" package="org.tsanie.billing" android:installLocation="auto" android:versionCode="10">
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0.312" package="org.tsanie.billing" android:installLocation="auto" android:versionCode="11">
 | 
			
		||||
	<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30" />
 | 
			
		||||
	<application android:label="@string/applabel" android:theme="@style/MainTheme"></application>
 | 
			
		||||
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,7 @@
 | 
			
		||||
    <MtouchLink>None</MtouchLink>
 | 
			
		||||
    <MtouchArch>x86_64</MtouchArch>
 | 
			
		||||
    <CodesignKey>iPhone Distribution</CodesignKey>
 | 
			
		||||
    <MtouchUseLlvm>true</MtouchUseLlvm>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
 | 
			
		||||
    <DebugSymbols>true</DebugSymbols>
 | 
			
		||||
@@ -64,6 +65,8 @@
 | 
			
		||||
    <CodesignKey>iPhone Distribution</CodesignKey>
 | 
			
		||||
    <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
 | 
			
		||||
    <MtouchLink>SdkOnly</MtouchLink>
 | 
			
		||||
    <MtouchInterpreter>-all</MtouchInterpreter>
 | 
			
		||||
    <MtouchUseLlvm>true</MtouchUseLlvm>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="Definition.cs" />
 | 
			
		||||
@@ -166,14 +169,13 @@
 | 
			
		||||
    <Reference Include="System.Xml.Linq" />
 | 
			
		||||
    <Reference Include="Xamarin.iOS" />
 | 
			
		||||
    <Reference Include="System.Numerics" />
 | 
			
		||||
    <Reference Include="System.Numerics.Vectors" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microcharts.Forms" Version="0.9.5.9" />
 | 
			
		||||
    <PackageReference Include="SkiaSharp.Views.Forms" Version="2.80.3" />
 | 
			
		||||
    <PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
 | 
			
		||||
    <PackageReference Include="Xamarin.Forms" Version="5.0.0.2337" />
 | 
			
		||||
    <PackageReference Include="Xamarin.Essentials" Version="1.7.1" />
 | 
			
		||||
    <PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <BundleResource Include="Resources\dollar.png" />
 | 
			
		||||
@@ -477,14 +479,6 @@
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <BundleResource Include="Resources\left%403x.png" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\Billing.ShareExtension\Billing.ShareExtension.csproj">
 | 
			
		||||
      <IsAppExtension>true</IsAppExtension>
 | 
			
		||||
      <Project>{D4EA6D3A-17E6-4300-80A7-2ED19B738C6B}</Project>
 | 
			
		||||
      <Name>Billing.ShareExtension</Name>
 | 
			
		||||
      <ReferenceSourceTarget></ReferenceSourceTarget>
 | 
			
		||||
    </ProjectReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Import Project="..\..\Billing.Shared\Billing.Shared.projitems" Label="Shared" />
 | 
			
		||||
  <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -42,23 +42,23 @@
 | 
			
		||||
		<string>OpenSans-SemiBold.ttf</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleDocumentTypes</key>
 | 
			
		||||
 	<array>
 | 
			
		||||
 		<dict>
 | 
			
		||||
 			<key>CFBundleTypeName</key>
 | 
			
		||||
 			<string>Master SQLite file</string>
 | 
			
		||||
 			<key>LSItemContentTypes</key>
 | 
			
		||||
 			<array>
 | 
			
		||||
 				<string>public.data</string>
 | 
			
		||||
 			</array>
 | 
			
		||||
 			<key>CFBundleTypeIconFiles</key>
 | 
			
		||||
 			<array>
 | 
			
		||||
 				<string>Assets.xcassets/AppIcon.appiconset/Icon180</string>
 | 
			
		||||
 			</array>
 | 
			
		||||
 		</dict>
 | 
			
		||||
 	</array>
 | 
			
		||||
	<array>
 | 
			
		||||
		<dict>
 | 
			
		||||
			<key>CFBundleTypeName</key>
 | 
			
		||||
			<string>Master SQLite file</string>
 | 
			
		||||
			<key>LSItemContentTypes</key>
 | 
			
		||||
			<array>
 | 
			
		||||
				<string>public.data</string>
 | 
			
		||||
			</array>
 | 
			
		||||
			<key>CFBundleTypeIconFiles</key>
 | 
			
		||||
			<array>
 | 
			
		||||
				<string>Assets.xcassets/AppIcon.appiconset/Icon180</string>
 | 
			
		||||
			</array>
 | 
			
		||||
		</dict>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>10</string>
 | 
			
		||||
	<string>11</string>
 | 
			
		||||
	<key>CFBundleShortVersionString</key>
 | 
			
		||||
	<string>0.10.311</string>
 | 
			
		||||
	<string>1.0.312</string>
 | 
			
		||||
</dict>
 | 
			
		||||
</plist>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user