Skip to content

Commit 213fb4e

Browse files
committed
Fix file picker
1 parent 866cb66 commit 213fb4e

File tree

10 files changed

+126
-95
lines changed

10 files changed

+126
-95
lines changed

src/Vocup.Android/App.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,5 @@
22

33
public class App : Vocup.App
44
{
5-
private readonly MainActivity? mainActivity;
65

7-
public App() { } // Default constructor for Avalonia
8-
9-
public App(MainActivity mainActivity)
10-
{
11-
this.mainActivity = mainActivity;
12-
}
13-
14-
protected override void BrowseFile()
15-
{
16-
mainActivity?.ShowFilePicker();
17-
}
186
}

src/Vocup.Android/MainActivity.cs

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
using Android.Content;
33
using Android.Content.PM;
44
using Android.OS;
5-
using Android.Runtime;
6-
using Android.Util;
75
using Avalonia;
86
using Avalonia.Android;
97
using Avalonia.ReactiveUI;
@@ -25,14 +23,6 @@ namespace Vocup.Android;
2523
DataPathPattern = ".*\\.vhf")]
2624
public class MainActivity : AvaloniaMainActivity<App>
2725
{
28-
private const string Tag = "Vocup.Android.MainActivity";
29-
private const int FilePickerRequestCode = 3147;
30-
31-
protected override AppBuilder CreateAppBuilder()
32-
{
33-
return AppBuilder.Configure(() => new App(this)).UseAndroid();
34-
}
35-
3626
protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
3727
{
3828
return base.CustomizeAppBuilder(builder)
@@ -52,59 +42,15 @@ protected override void OnNewIntent(Intent? intent)
5242
HandleIntent(intent);
5343
}
5444

55-
public void ShowFilePicker()
56-
{
57-
var intent = new Intent(Intent.ActionGetContent);
58-
intent.SetType("application/octet-stream");
59-
intent.AddCategory(Intent.CategoryOpenable);
60-
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
61-
StartActivityForResult(Intent.CreateChooser(intent, "Select a file"), FilePickerRequestCode);
62-
}
63-
64-
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent? data)
65-
{
66-
base.OnActivityResult(requestCode, resultCode, data);
67-
68-
if (requestCode == FilePickerRequestCode && resultCode == Result.Ok && data?.Data != null)
69-
{
70-
using System.IO.Stream? stream = ContentResolver?.OpenInputStream(data.Data);
71-
72-
if (stream == null)
73-
{
74-
Log.Error(Tag, "Stream is null in OnActivityResult");
75-
return;
76-
}
77-
if (Avalonia.Application.Current is not App app)
78-
{
79-
Log.Error(Tag, "App is null in OnActivityResult");
80-
return;
81-
}
82-
Log.Debug(Tag, $"File size is {stream.Length} bytes");
83-
app.OpenFile(stream);
84-
}
85-
}
86-
87-
private void HandleIntent(Intent? intent)
45+
private static void HandleIntent(Intent? intent)
8846
{
89-
if (intent?.Action == Intent.ActionView && intent.Data != null)
47+
if (intent?.Action == Intent.ActionView && intent.Data != null && Avalonia.Application.Current is App app)
9048
{
91-
using System.IO.Stream? stream = ContentResolver?.OpenInputStream(intent.Data);
92-
93-
if (stream == null)
49+
string? uri = intent.Data.ToString();
50+
if (uri != null)
9451
{
95-
Log.Error(Tag, "Stream is null in HandleIntent");
96-
return;
52+
app.OpenFile(new(uri));
9753
}
98-
99-
if (Avalonia.Application.Current is not App app)
100-
{
101-
Log.Error(Tag, "App is null in HandleIntent");
102-
return;
103-
}
104-
105-
Log.Debug(Tag, $"File size is {stream.Length} bytes");
106-
107-
app.OpenFile(stream);
10854
}
10955
}
11056
}

src/Vocup/App.axaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
<Application xmlns="https://github.com/avaloniaui"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:views="clr-namespace:Vocup.Views;assembly=Vocup.Avalonia"
4+
xmlns:vm="clr-namespace:Vocup.ViewModels;assembly=Vocup.Avalonia"
35
x:Class="Vocup.App"
46
RequestedThemeVariant="Default">
57
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
68

79
<Application.Styles>
810
<FluentTheme />
911
</Application.Styles>
12+
13+
<Application.DataTemplates>
14+
<DataTemplate DataType="{x:Type vm:BookViewModel}">
15+
<views:BookView />
16+
</DataTemplate>
17+
<DataTemplate DataType="{x:Type vm:AboutViewModel}">
18+
<views:AboutView />
19+
</DataTemplate>
20+
</Application.DataTemplates>
21+
1022
</Application>

src/Vocup/App.axaml.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
using Avalonia;
22
using Avalonia.Controls.ApplicationLifetimes;
33
using Avalonia.Markup.Xaml;
4-
using ReactiveUI;
5-
using System.IO;
4+
using System;
65
using Vocup.ViewModels;
76
using Vocup.Views;
87

@@ -17,12 +16,9 @@ public override void Initialize()
1716
AvaloniaXamlLoader.Load(this);
1817
}
1918

20-
public void OpenFile(Stream input)
19+
public void OpenFile(Uri path)
2120
{
22-
if (mainViewModel != null)
23-
{
24-
mainViewModel.FileLength = input.Length;
25-
}
21+
mainViewModel?.OpenFile(path);
2622
}
2723

2824
public override void OnFrameworkInitializationCompleted()
@@ -46,9 +42,4 @@ public override void OnFrameworkInitializationCompleted()
4642

4743
base.OnFrameworkInitializationCompleted();
4844
}
49-
50-
protected virtual void BrowseFile()
51-
{
52-
53-
}
5445
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using ReactiveUI;
2+
3+
namespace Vocup.ViewModels;
4+
5+
public class BookViewModel : ViewModelBase
6+
{
7+
private long _fileLength;
8+
public long FileLength
9+
{
10+
get => _fileLength;
11+
set => this.RaiseAndSetIfChanged(ref _fileLength, value);
12+
}
13+
}
Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,78 @@
1-
using ReactiveUI;
1+
using Avalonia.Platform.Storage;
2+
using Avalonia.Threading;
3+
using ReactiveUI;
4+
using System;
25
using System.IO;
36
using System.Reactive;
47
using System.Reactive.Linq;
8+
using System.Threading.Tasks;
59
using System.Windows.Input;
610

711
namespace Vocup.ViewModels;
812

913
public class MainViewModel : ViewModelBase
1014
{
11-
private long _fileLength;
12-
public long FileLength
15+
private ViewModelBase? _currentView;
16+
public ViewModelBase? CurrentView
1317
{
14-
get => _fileLength;
15-
set => this.RaiseAndSetIfChanged(ref _fileLength, value);
18+
get => _currentView;
19+
set => this.RaiseAndSetIfChanged(ref _currentView, value);
20+
}
21+
22+
private string _errorMessage = string.Empty;
23+
public string ErrorMessage
24+
{
25+
get => _errorMessage;
26+
set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
1627
}
1728

1829
public AboutViewModel About { get; } = new();
1930

20-
public Interaction<Unit, Avalonia.Platform.Storage.IStorageFile?> PickFileInteraction { get; } = new();
31+
public Interaction<Unit, IStorageFile?> PickFileInteraction { get; } = new();
32+
public Interaction<Uri, IStorageFile?> FileFromUriInteraction { get; } = new();
2133

2234
public ICommand OpenFileCommand { get; }
35+
public ICommand AboutCommand { get; }
2336

2437
public MainViewModel()
2538
{
2639
OpenFileCommand = ReactiveCommand.CreateFromTask(async () =>
2740
{
28-
var file = await PickFileInteraction.Handle(Unit.Default);
29-
if (file != null)
41+
try
3042
{
31-
using Stream stream = await file.OpenReadAsync();
32-
FileLength = stream.Length;
43+
var file = await PickFileInteraction.Handle(Unit.Default);
44+
if (file != null)
45+
{
46+
using Stream stream = await Task.Run(file.OpenReadAsync);
47+
CurrentView = new BookViewModel { FileLength = stream.Length };
48+
}
3349
}
50+
catch (Exception ex)
51+
{
52+
Dispatcher.UIThread.Invoke(() => ErrorMessage = $"Error opening file: {ex.Message}");
53+
}
54+
});
55+
56+
AboutCommand = ReactiveCommand.Create(() =>
57+
{
58+
CurrentView = About;
3459
});
3560
}
61+
62+
public async void OpenFile(Uri path)
63+
{
64+
try
65+
{
66+
var file = await FileFromUriInteraction.Handle(path);
67+
if (file != null)
68+
{
69+
using Stream stream = await Task.Run(file.OpenReadAsync);
70+
CurrentView = new BookViewModel { FileLength = stream.Length };
71+
}
72+
}
73+
catch (Exception ex)
74+
{
75+
Dispatcher.UIThread.Invoke(() => ErrorMessage = $"Error opening file: {ex.Message}");
76+
}
77+
}
3678
}

src/Vocup/Views/BookView.axaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<UserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:vm="clr-namespace:Vocup.ViewModels;assembly=Vocup.Avalonia"
6+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
7+
x:Class="Vocup.Views.BookView"
8+
x:DataType="vm:BookViewModel">
9+
10+
<Design.DataContext>
11+
<!-- This only sets the DataContext for the previewer in an IDE,
12+
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
13+
<vm:BookViewModel />
14+
</Design.DataContext>
15+
16+
<TextBlock Text="{Binding FileLength}" />
17+
18+
</UserControl>

src/Vocup/Views/BookView.axaml.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using Avalonia;
2+
using Avalonia.Controls;
3+
using Avalonia.Markup.Xaml;
4+
5+
namespace Vocup.Views;
6+
7+
public partial class BookView : UserControl
8+
{
9+
public BookView()
10+
{
11+
InitializeComponent();
12+
}
13+
}

src/Vocup/Views/MainView.axaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,18 @@
77
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
88
x:Class="Vocup.Views.MainView"
99
x:DataType="vm:MainViewModel">
10+
1011
<Design.DataContext>
1112
<!-- This only sets the DataContext for the previewer in an IDE,
1213
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
1314
<vm:MainViewModel />
1415
</Design.DataContext>
1516

1617
<StackPanel>
17-
<TextBlock Text="{Binding FileLength}" />
1818
<Button Command="{Binding OpenFileCommand}" Content="Open File" />
19-
<views:AboutView DataContext="{Binding About}" />
19+
<Button Command="{Binding AboutCommand}" Content="About" />
20+
<TextBlock Text="{Binding ErrorMessage}" />
21+
<ContentControl Content="{Binding CurrentView}" />
2022
</StackPanel>
2123

2224
</UserControl>

src/Vocup/Views/MainView.axaml.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,11 @@ public MainView()
2424
else
2525
interaction.SetOutput(null);
2626
})));
27+
28+
this.WhenActivated(d => d(ViewModel.FileFromUriInteraction.RegisterHandler(async interaction =>
29+
{
30+
var file = await TopLevel.GetTopLevel(this).StorageProvider.TryGetFileFromPathAsync(interaction.Input);
31+
interaction.SetOutput(file);
32+
})));
2733
}
2834
}

0 commit comments

Comments
 (0)