diff --git a/critterfolio/CritterFolio/CritterFolio.Android/MainActivity.cs b/critterfolio/CritterFolio/CritterFolio.Android/MainActivity.cs index ee07061..888d2af 100644 --- a/critterfolio/CritterFolio/CritterFolio.Android/MainActivity.cs +++ b/critterfolio/CritterFolio/CritterFolio.Android/MainActivity.cs @@ -1,9 +1,16 @@ -using System; +using System.Collections.Generic; +using Android; using Android.App; using Android.Content.PM; +using Android.OS; +using AndroidX.Core.App; using Avalonia; using Avalonia.Android; using Avalonia.Controls.ApplicationLifetimes; +using Java.Security; +using Environment = System.Environment; +using Permission = Android.Content.PM.Permission; + namespace CritterFolio.Android; @@ -21,6 +28,12 @@ public class MainActivity : AvaloniaMainActivity .WithInterFont(); } + protected override void OnCreate(Bundle? savedInstanceState) + { + base.OnCreate(savedInstanceState); + RequestStorageAccess(); + } + public override void OnBackPressed() { if (Sys.Navigation != null && Sys.Navigation.IsLastPage()) @@ -38,4 +51,39 @@ public class MainActivity : AvaloniaMainActivity Sys.Navigation?.PopPage(); } } + + public void RequestStorageAccess() + { + string[] permissions; + + if (Build.VERSION.SdkInt >= BuildVersionCodes.Tiramisu) + { + permissions = new string[] + { + Manifest.Permission.ReadMediaImages, + Manifest.Permission.ReadMediaVideo + }; + } + else + { + permissions = new string[] { Manifest.Permission.ReadExternalStorage }; + } + + List permissionsToRequest = new List(); + + foreach (var permission in permissions) + { + if (CheckSelfPermission(permission) != Permission.Granted) + { + permissionsToRequest.Add(permission); + } + } + + if (permissionsToRequest.Count > 0) + { + RequestPermissions(permissionsToRequest.ToArray(), 1000); + } + } + + } diff --git a/critterfolio/CritterFolio/CritterFolio.Android/Properties/AndroidManifest.xml b/critterfolio/CritterFolio/CritterFolio.Android/Properties/AndroidManifest.xml index 082d433..b44a739 100644 --- a/critterfolio/CritterFolio/CritterFolio.Android/Properties/AndroidManifest.xml +++ b/critterfolio/CritterFolio/CritterFolio.Android/Properties/AndroidManifest.xml @@ -1,5 +1,6 @@  + diff --git a/critterfolio/CritterFolio/CritterFolio/App.axaml.cs b/critterfolio/CritterFolio/CritterFolio/App.axaml.cs index b10e75e..959dcd3 100644 --- a/critterfolio/CritterFolio/CritterFolio/App.axaml.cs +++ b/critterfolio/CritterFolio/CritterFolio/App.axaml.cs @@ -40,6 +40,7 @@ public partial class App : Application // Other init stuff here Directory.CreateDirectory(Sys.UserDataPath); Directory.CreateDirectory(Path.Combine(Sys.UserDataPath, "ImageCache")); + Directory.CreateDirectory(Path.Combine(Sys.UserDataPath, "DocumentCache")); base.OnFrameworkInitializationCompleted(); diff --git a/critterfolio/CritterFolio/CritterFolio/Controls/DocumentItem.axaml b/critterfolio/CritterFolio/CritterFolio/Controls/DocumentItem.axaml index 6c5353b..6700657 100644 --- a/critterfolio/CritterFolio/CritterFolio/Controls/DocumentItem.axaml +++ b/critterfolio/CritterFolio/CritterFolio/Controls/DocumentItem.axaml @@ -2,7 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + mc:Ignorable="d" d:DesignWidth="720" d:DesignHeight="1280" x:Class="CritterFolio.Controls.DocumentItem"> + FontSize="20" + MaxWidth="150" + /> + + diff --git a/critterfolio/CritterFolio/CritterFolio/Pages/CritterPage.axaml.cs b/critterfolio/CritterFolio/CritterFolio/Pages/CritterPage.axaml.cs index 8240795..50147c6 100644 --- a/critterfolio/CritterFolio/CritterFolio/Pages/CritterPage.axaml.cs +++ b/critterfolio/CritterFolio/CritterFolio/Pages/CritterPage.axaml.cs @@ -9,6 +9,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Platform.Storage; using Avalonia.Threading; +using CritterFolio.Controls; using CritterFolio.DataModels; using CritterFolio.Services; @@ -18,6 +19,7 @@ public partial class CritterPage : Page { private Critter? _critter; private List _critterDisplays = []; + private List _documents = []; public CritterPage() { @@ -31,9 +33,13 @@ public partial class CritterPage : Page PfpButton.Click += OpenFileButton_Clicked; GenderOption.ItemsSource = Enum.GetNames(typeof(Gender)); + AddDocButton.Click += AddDocButtonOnClick; + await UpdateInfo(); } + + public override void Refresh() { base.Refresh(); @@ -125,8 +131,36 @@ public partial class CritterPage : Page Console.WriteLine($"Pfp image for {_critter.Id} was moved, deleted, or is corrupt."); } } + + RegenDocsList(); } - + + private async void RegenDocsList() + { + _documents.Clear(); + var docs = await DatabaseService.GetAllDocumentsForCritter(_critter.Id); + _documents.AddRange(docs); + + DocsStack.Children.Clear(); + foreach (var document in _documents) + { + CreateDocItem(document); + } + } + + private void CreateDocItem(Document document) + { + var item = new DocumentItem(); + item.Init(document); + DocsStack.Children.Add(item); + + item.DocumentWasDeleted += async (sender, args) => + { + RegenDocsList(); + }; + } + + private void CreateHeaderButtons() { var saveBttn = new Button() @@ -264,6 +298,7 @@ public partial class CritterPage : Page private async void OpenFileButton_Clicked(object? sender, RoutedEventArgs args) { var topLevel = TopLevel.GetTopLevel(this); + if (topLevel is null) return; var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { @@ -289,8 +324,41 @@ public partial class CritterPage : Page { await DialogHelper.ShowMessage(e.ToString()); } + } + + private async void AddDocButtonOnClick(object? sender, RoutedEventArgs e) + { + if (_critter is null) return; + var topLevel = TopLevel.GetTopLevel(this); + if (topLevel is null) return; + var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + Title = "Add Document", + AllowMultiple = false, + }); + + if (files.Count == 0) return; + var file = files[0]; + + var newFileLocation = Path.Combine(Sys.UserDataPath, "DocumentCache", $"{_critter.Id}-{_critter.Name}-{file.Name}"); + + await using var sourceStream = await file.OpenReadAsync(); + await using var destStream = File.Create(newFileLocation); + await sourceStream.CopyToAsync(destStream); + + var doc = new Document() + { + Name = file.Name, + CritterId = _critter.Id, + Path = newFileLocation, + Description = "" + }; + + await DatabaseService.AddDocument(doc); + + CreateDocItem(doc); } } \ No newline at end of file diff --git a/critterfolio/CritterFolio/CritterFolio/Services/AndroidPermissions.cs b/critterfolio/CritterFolio/CritterFolio/Services/AndroidPermissions.cs new file mode 100644 index 0000000..b513a8c --- /dev/null +++ b/critterfolio/CritterFolio/CritterFolio/Services/AndroidPermissions.cs @@ -0,0 +1,6 @@ +namespace CritterFolio.Services; + +public static class AndroidPermissions +{ + +} \ No newline at end of file