Skip to content

Commit

Permalink
Merge branch 'master' into feature/ios-voiceover
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaMorphic authored Jan 23, 2025
2 parents bf9933d + fce5682 commit f9ed243
Show file tree
Hide file tree
Showing 21 changed files with 668 additions and 29 deletions.
12 changes: 12 additions & 0 deletions api/Avalonia.nupkg.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@
<Left>baseline/netstandard2.0/Avalonia.Controls.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.Storage.IStorageFolder.GetFileAsync(System.String)</Target>
<Left>baseline/netstandard2.0/Avalonia.Base.dll</Left>
<Right>target/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.Storage.IStorageFolder.GetFolderAsync(System.String)</Target>
<Left>baseline/netstandard2.0/Avalonia.Base.dll</Left>
<Right>target/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Controls.Notifications.IManagedNotificationManager.Close(System.Object)</Target>
Expand Down
2 changes: 1 addition & 1 deletion packages/Avalonia/Avalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Avalonia.BuildServices" Version="0.0.29" />
<PackageReference Include="Avalonia.BuildServices" Version="0.0.31" />
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj"
PrivateAssets="all" />
Expand Down
1 change: 1 addition & 0 deletions samples/ControlCatalog/Pages/TextBoxPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
UseFloatingWatermark="True"
PasswordChar="*"
Text="Password" />
<TextBox Width="200" Watermark="Suggestions are hidden" TextInputOptions.ShowSuggestions="False" />
<TextBox Width="200" Text="Left aligned text" TextAlignment="Left" AcceptsTab="True" />
<TextBox Width="200" Text="Center aligned text" TextAlignment="Center" />
<TextBox Width="200" Text="Right aligned text" TextAlignment="Right" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ public void SetOptions(TextInputOptions options)
if (options.Multiline)
outAttrs.InputType |= InputTypes.TextFlagMultiLine;

if (outAttrs.InputType is InputTypes.ClassText && options.ShowSuggestions == false)
outAttrs.InputType |= InputTypes.TextVariationPassword | InputTypes.TextFlagNoSuggestions;

outAttrs.ImeOptions = options.ReturnKeyType switch
{
TextInputReturnKeyType.Return => ImeFlags.NoEnterAction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,79 @@ public async IAsyncEnumerable<IStorageItem> GetItemsAsync()
return destination;
}
}

private async Task<IStorageItem?> GetItemAsync(string name, bool isDirectory)
{
if (!await EnsureExternalFilesPermission(false))
{
return null;
}

var contentResolver = Activity.ContentResolver;
if (contentResolver == null)
{
return null;
}

var root = PermissionRoot ?? Uri;
var folderId = root != Uri ? DocumentsContract.GetDocumentId(Uri) : DocumentsContract.GetTreeDocumentId(Uri);
var childrenUri = DocumentsContract.BuildChildDocumentsUriUsingTree(root, folderId);

var projection = new[]
{
DocumentsContract.Document.ColumnDocumentId,
DocumentsContract.Document.ColumnMimeType,
DocumentsContract.Document.ColumnDisplayName
};

if (childrenUri != null)
{
using var cursor = contentResolver.Query(childrenUri, projection, null, null, null);
if (cursor != null)
{
while (cursor.MoveToNext())
{
var id = cursor.GetString(0);
var mime = cursor.GetString(1);

var fileName = cursor.GetString(2);
if (fileName != name)
{
continue;
}

bool mineDirectory = mime == DocumentsContract.Document.MimeTypeDir;
if (isDirectory != mineDirectory)
{
return null;
}

var uri = DocumentsContract.BuildDocumentUriUsingTree(root, id);
if (uri == null)
{
return null;
}

return isDirectory ? new AndroidStorageFolder(Activity, uri, false, this, root) :
new AndroidStorageFile(Activity, uri, this, root);
}
}
}

return null;
}

public async Task<IStorageFolder?> GetFolderAsync(string name)
{
var folder = await GetItemAsync(name, true);
return (IStorageFolder?)folder;
}

public async Task<IStorageFile?> GetFileAsync(string name)
{
var file = await GetItemAsync(name, false);
return (IStorageFile?)file;
}
}

internal sealed class WellKnownAndroidStorageFolder : AndroidStorageFolder
Expand Down
36 changes: 35 additions & 1 deletion src/Avalonia.Base/Input/TextInput/TextInputOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public static TextInputOptions FromStyledElement(StyledElement avaloniaObject)
AutoCapitalization = GetAutoCapitalization(avaloniaObject),
IsSensitive = GetIsSensitive(avaloniaObject),
Lowercase = GetLowercase(avaloniaObject),
Uppercase = GetUppercase(avaloniaObject)
Uppercase = GetUppercase(avaloniaObject),
ShowSuggestions = GetShowSuggestions(avaloniaObject),
};

return result;
Expand Down Expand Up @@ -253,4 +254,37 @@ public static bool GetIsSensitive(StyledElement avaloniaObject)
/// Text contains sensitive data like card numbers and should not be stored
/// </summary>
public bool IsSensitive { get; set; }

/// <summary>
/// Defines the <see cref="ShowSuggestions"/> property.
/// </summary>
public static readonly AttachedProperty<bool?> ShowSuggestionsProperty =
AvaloniaProperty.RegisterAttached<TextInputOptions, StyledElement, bool?>(
"ShowSuggestions",
inherits: true);

/// <summary>
/// Sets the value of the attached <see cref="ShowSuggestionsProperty"/> on a control.
/// </summary>
/// <param name="avaloniaObject">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetShowSuggestions(StyledElement avaloniaObject, bool? value)
{
avaloniaObject.SetValue(ShowSuggestionsProperty, value);
}

/// <summary>
/// Gets the value of the attached <see cref="ShowSuggestionsProperty"/>.
/// </summary>
/// <param name="avaloniaObject">The target.</param>
/// <returns>true if ShowSuggestions</returns>
public static bool? GetShowSuggestions(StyledElement avaloniaObject)
{
return avaloniaObject.GetValue(ShowSuggestionsProperty);
}

/// <summary>
/// Show virtual keyboard suggestions
/// </summary>
public bool? ShowSuggestions { get; set; }
}
6 changes: 6 additions & 0 deletions src/Avalonia.Base/Platform/Storage/FileIO/BclStorageFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ public IAsyncEnumerable<IStorageItem> GetItemsAsync() => GetItemsCore(directoryI

public Task<IStorageFolder?> CreateFolderAsync(string name) => Task.FromResult(
(IStorageFolder?)WrapFileSystemInfo(CreateFolderCore(directoryInfo, name)));

public Task<IStorageFolder?> GetFolderAsync(string name) => Task.FromResult(
(IStorageFolder?)WrapFileSystemInfo(GetFolderCore(directoryInfo, name)));

public Task<IStorageFile?> GetFileAsync(string name) => Task.FromResult(
(IStorageFile?)WrapFileSystemInfo(GetFileCore(directoryInfo, name)));
}
22 changes: 22 additions & 0 deletions src/Avalonia.Base/Platform/Storage/FileIO/BclStorageItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,28 @@ internal static IEnumerable<FileSystemInfo> GetItemsCore(DirectoryInfo directory
.OfType<FileSystemInfo>()
.Concat(directoryInfo.EnumerateFiles());

internal static FileSystemInfo? GetFolderCore(DirectoryInfo directoryInfo, string name)
{
var path = System.IO.Path.Combine(directoryInfo.FullName, name);
if (Directory.Exists(path))
{
return new DirectoryInfo(path);
}

return null;
}

internal static FileSystemInfo? GetFileCore(DirectoryInfo directoryInfo, string name)
{
var path = System.IO.Path.Combine(directoryInfo.FullName, name);
if (File.Exists(path))
{
return new FileInfo(path);
}

return null;
}

internal static FileInfo CreateFileCore(DirectoryInfo directoryInfo, string name)
{
var fileName = System.IO.Path.Combine(directoryInfo.FullName, name);
Expand Down
18 changes: 18 additions & 0 deletions src/Avalonia.Base/Platform/Storage/IStorageFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ public interface IStorageFolder : IStorageItem
/// </returns>
IAsyncEnumerable<IStorageItem> GetItemsAsync();

/// <summary>
/// Gets the folder with the specified name from the current folder.
/// </summary>
/// <param name="name">The name of the folder to get</param>
/// <returns>
/// When this method completes successfully, it returns the folder with the specified name from the current folder.
/// </returns>
Task<IStorageFolder?> GetFolderAsync(string name);

/// <summary>
/// Gets the file with the specified name from the current folder.
/// </summary>
/// <param name="name">The name of the file to get</param>
/// <returns>
/// When this method completes successfully, it returns the file with the specified name from the current folder.
/// </returns>
Task<IStorageFile?> GetFileAsync(string name);

/// <summary>
/// Creates a file with specified name as a child of the current storage folder
/// </summary>
Expand Down
59 changes: 53 additions & 6 deletions src/Avalonia.Controls/Primitives/UniformGrid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ public class UniformGrid : Panel
public static readonly StyledProperty<int> FirstColumnProperty =
AvaloniaProperty.Register<UniformGrid, int>(nameof(FirstColumn));

/// <summary>
/// Defines the <see cref="RowSpacing"/> property.
/// </summary>
public static readonly StyledProperty<double> RowSpacingProperty =
AvaloniaProperty.Register<UniformGrid, double>(nameof(RowSpacing), 0);

/// <summary>
/// Defines the <see cref="ColumnSpacing"/> property.
/// </summary>
public static readonly StyledProperty<double> ColumnSpacingProperty =
AvaloniaProperty.Register<UniformGrid, double>(nameof(ColumnSpacing), 0);

private int _rows;
private int _columns;

Expand Down Expand Up @@ -60,14 +72,34 @@ public int FirstColumn
set => SetValue(FirstColumnProperty, value);
}

/// <summary>
/// Specifies the spacing between rows.
/// </summary>
public double RowSpacing
{
get => GetValue(RowSpacingProperty);
set => SetValue(RowSpacingProperty, value);
}

/// <summary>
/// Specifies the spacing between columns.
/// </summary>
public double ColumnSpacing
{
get => GetValue(ColumnSpacingProperty);
set => SetValue(ColumnSpacingProperty, value);
}

protected override Size MeasureOverride(Size availableSize)
{
UpdateRowsAndColumns();

var maxWidth = 0d;
var maxHeight = 0d;

var childAvailableSize = new Size(availableSize.Width / _columns, availableSize.Height / _rows);
var childAvailableSize = new Size(
(availableSize.Width - (_columns - 1) * ColumnSpacing) / _columns,
(availableSize.Height - (_rows - 1) * RowSpacing) / _rows);

foreach (var child in Children)
{
Expand All @@ -84,16 +116,25 @@ protected override Size MeasureOverride(Size availableSize)
}
}

return new Size(maxWidth * _columns, maxHeight * _rows);
var totalWidth = maxWidth * _columns + ColumnSpacing * (_columns - 1);
var totalHeight = maxHeight * _rows + RowSpacing * (_rows - 1);

totalWidth = Math.Max(totalWidth, 0);
totalHeight = Math.Max(totalHeight, 0);

return new Size(totalWidth, totalHeight);
}

protected override Size ArrangeOverride(Size finalSize)
{
var x = FirstColumn;
var y = 0;

var width = finalSize.Width / _columns;
var height = finalSize.Height / _rows;
var columnSpacing = ColumnSpacing;
var rowSpacing = RowSpacing;

var width = (finalSize.Width - (_columns - 1) * columnSpacing) / _columns;
var height = (finalSize.Height - (_rows - 1) * rowSpacing) / _rows;

foreach (var child in Children)
{
Expand All @@ -102,7 +143,13 @@ protected override Size ArrangeOverride(Size finalSize)
continue;
}

child.Arrange(new Rect(x * width, y * height, width, height));
var rect = new Rect(
x * (width + columnSpacing),
y * (height + rowSpacing),
width,
height);

child.Arrange(rect);

x++;

Expand All @@ -121,7 +168,7 @@ private void UpdateRowsAndColumns()
_rows = Rows;
_columns = Columns;

if (FirstColumn >= Columns)
if (FirstColumn >= _columns)
{
SetCurrentValue(FirstColumnProperty, 0);
}
Expand Down
14 changes: 14 additions & 0 deletions src/Avalonia.Controls/TextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,20 @@ public bool CanRedo
private set => SetAndRaise(CanRedoProperty, ref _canRedo, value);
}

/// <summary>
/// Get the number of lines in the TextBox.
/// </summary>
/// <value>number of lines in the TextBox, or -1 if no layout information is available</value>
/// <remarks>
/// If Wrap == true, changing the width of the TextBox may change this value.
/// The value returned is the number of lines in the entire TextBox, regardless of how many are
/// currently in view.
/// </remarks>
public int GetLineCount()
{
return this._presenter?.TextLayout.TextLines.Count ?? -1;
}

/// <summary>
/// Raised when content is being copied to the clipboard
/// </summary>
Expand Down
14 changes: 14 additions & 0 deletions src/Avalonia.Native/StorageItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,18 @@ IEnumerable<IStorageItem> GetItems()
var folder = BclStorageItem.CreateFolderCore(directoryInfo, name);
return Task.FromResult((IStorageFolder?)WrapFileSystemInfo(folder, ScopeOwnerUri));
}

public Task<IStorageFolder?> GetFolderAsync(string name)
{
using var scope = OpenScope();
var item = BclStorageItem.GetFolderCore(directoryInfo, name);
return Task.FromResult((IStorageFolder?)WrapFileSystemInfo(item, ScopeOwnerUri));
}

public Task<IStorageFile?> GetFileAsync(string name)
{
using var scope = OpenScope();
var item = BclStorageItem.GetFileCore(directoryInfo, name);
return Task.FromResult((IStorageFile?)WrapFileSystemInfo(item, ScopeOwnerUri));
}
}
6 changes: 6 additions & 0 deletions src/Browser/Avalonia.Browser/Interop/StorageHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,10 @@ internal static partial class StorageHelper

[JSImport("StorageProvider.createFolder", AvaloniaModule.StorageModuleName)]
public static partial Task<JSObject?> CreateFolder(JSObject folderHandle, string name);

[JSImport("StorageItem.getFile", AvaloniaModule.StorageModuleName)]
public static partial Task<JSObject?> GetFile(JSObject folderHandle, string name);

[JSImport("StorageItem.getFolder", AvaloniaModule.StorageModuleName)]
public static partial Task<JSObject?> GetFolder(JSObject folderHandle, string name);
}
Loading

0 comments on commit f9ed243

Please sign in to comment.