Skip to content

Commit

Permalink
Merge pull request #29 from UnicordDev/feature/modern-navigation
Browse files Browse the repository at this point in the history
Improve navigation
  • Loading branch information
WamWooWam authored Dec 27, 2024
2 parents 49660a2 + bb5cad4 commit 6cc8f63
Show file tree
Hide file tree
Showing 33 changed files with 1,388 additions and 570 deletions.
7 changes: 7 additions & 0 deletions UniSky.Services/Implementation/SettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ public bool TryRead<T>(string key, out T? value)
{
if (Settings.Values.TryGetValue(key, out var valueObj) && valueObj is string valueString)
{
if (typeof(T) == typeof(string) && !valueString.StartsWith('"'))
{
// :D
value = (T)(object)valueString;
return true;
}

value = JsonSerializer.Deserialize<T>(valueString, Options);
return true;
}
Expand Down
6 changes: 4 additions & 2 deletions UniSky.Services/ModerationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ namespace UniSky.Services;

public record struct LabelStrings(string Name, string Description);

public class ModerationService(IProtocolService protocolService, ILogger<ModerationService> logger) : IModerationService
public class ModerationService(
IProtocolService protocolService,
ILogger<ModerationService> logger) : IModerationService
{
private readonly ResourceLoader resources
= ResourceLoader.GetForCurrentView();
= ResourceLoader.GetForViewIndependentUse();

public ModerationOptions ModerationOptions { get; set; }

Expand Down
4 changes: 2 additions & 2 deletions UniSky/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(RootPage), e.Arguments);
rootFrame.Navigate(typeof(RootPage), e.SplashScreen);
}

// Ensure the current window is active
Expand All @@ -152,7 +152,7 @@ private void OnProtocolActivated(ProtocolActivatedEventArgs e)
{
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
rootFrame.Navigate(typeof(RootPage));
rootFrame.Navigate(typeof(RootPage), e.SplashScreen);
Window.Current.Content = rootFrame;
}

Expand Down
90 changes: 90 additions & 0 deletions UniSky/Controls/UniformGrid/TakenSpotsReferenceHolder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections;
using System.Drawing;

namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Referencable class object we can use to have a reference shared between
/// our <see cref="UniformGrid.MeasureOverride"/> and
/// <see cref="UniformGrid.GetFreeSpot"/> iterator.
/// This is used so we can better isolate our logic and make it easier to test.
/// </summary>
internal sealed class TakenSpotsReferenceHolder
{
/// <summary>
/// The <see cref="BitArray"/> instance used to efficiently track empty spots.
/// </summary>
private readonly BitArray spotsTaken;

/// <summary>
/// Initializes a new instance of the <see cref="TakenSpotsReferenceHolder"/> class.
/// </summary>
/// <param name="rows">The number of rows to track.</param>
/// <param name="columns">The number of columns to track.</param>
public TakenSpotsReferenceHolder(int rows, int columns)
{
Height = rows;
Width = columns;

this.spotsTaken = new BitArray(rows * columns);
}

/// <summary>
/// Gets the height of the grid to monitor.
/// </summary>
public int Height { get; }

/// <summary>
/// Gets the width of the grid to monitor.
/// </summary>
public int Width { get; }

/// <summary>
/// Gets or sets the value of a specified grid cell.
/// </summary>
/// <param name="i">The vertical offset.</param>
/// <param name="j">The horizontal offset.</param>
public bool this[int i, int j]
{
get => this.spotsTaken[(i * Width) + j];
set => this.spotsTaken[(i * Width) + j] = value;
}

/// <summary>
/// Fills the specified area in the current grid with a given value.
/// If invalid coordinates are given, they will simply be ignored and no exception will be thrown.
/// </summary>
/// <param name="value">The value to fill the target area with.</param>
/// <param name="row">The row to start on (inclusive, 0-based index).</param>
/// <param name="column">The column to start on (inclusive, 0-based index).</param>
/// <param name="width">The positive width of area to fill.</param>
/// <param name="height">The positive height of area to fill.</param>
public void Fill(bool value, int row, int column, int width, int height)
{
Rectangle bounds = new Rectangle(0, 0, Width, Height);

// Precompute bounds to skip branching in main loop
bounds.Intersect(new Rectangle(column, row, width, height));

for (int i = bounds.Top; i < bounds.Bottom; i++)
{
for (int j = bounds.Left; j < bounds.Right; j++)
{
this[i, j] = value;
}
}
}

/// <summary>
/// Resets the current reference holder.
/// </summary>
public void Reset()
{
this.spotsTaken.SetAll(false);
}
}
}
179 changes: 179 additions & 0 deletions UniSky/Controls/UniformGrid/UniformGrid.Helpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// The UniformGrid control presents information within a Grid with even spacing.
/// </summary>
public partial class UniformGrid : Grid
{
// Provides the next spot in the boolean array with a 'false' value.
#pragma warning disable SA1009 // Closing parenthesis must be followed by a space.
internal static IEnumerable<(int row, int column)> GetFreeSpot(TakenSpotsReferenceHolder arrayref, int firstcolumn, bool topdown)
#pragma warning restore SA1009 // Closing parenthesis must be followed by a space.
{
if (topdown)
{
var rows = arrayref.Height;

// Layout spots from Top-Bottom, Left-Right (right-left handled automatically by Grid with Flow-Direction).
// Effectively transpose the Grid Layout.
for (int c = 0; c < arrayref.Width; c++)
{
int start = (c == 0 && firstcolumn > 0 && firstcolumn < rows) ? firstcolumn : 0;
for (int r = start; r < rows; r++)
{
if (!arrayref[r, c])
{
yield return (r, c);
}
}
}
}
else
{
var columns = arrayref.Width;

// Layout spots as normal from Left-Right.
// (right-left handled automatically by Grid with Flow-Direction
// during its layout, internal model is always left-right).
for (int r = 0; r < arrayref.Height; r++)
{
int start = (r == 0 && firstcolumn > 0 && firstcolumn < columns) ? firstcolumn : 0;
for (int c = start; c < columns; c++)
{
if (!arrayref[r, c])
{
yield return (r, c);
}
}
}
}
}

// Based on the number of visible children,
// returns the dimensions of the
// grid we need to hold all elements.
#pragma warning disable SA1008 // Opening parenthesis must be spaced correctly
internal static (int rows, int columns) GetDimensions(FrameworkElement[] visible, int rows, int cols, int firstColumn)
#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly
{
// If a dimension isn't specified, we need to figure out the other one (or both).
if (rows == 0 || cols == 0)
{
// Calculate the size & area of all objects in the grid to know how much space we need.
var count = Math.Max(1, visible.Sum(item => GetRowSpan(item) * GetColumnSpan(item)));

if (rows == 0)
{
if (cols > 0)
{
// Bound check
var first = (firstColumn >= cols || firstColumn < 0) ? 0 : firstColumn;

// If we have columns but no rows, calculate rows based on column offset and number of children.
rows = (count + first + (cols - 1)) / cols;
return (rows, cols);
}
else
{
// Otherwise, determine square layout if both are zero.
var size = (int)Math.Ceiling(Math.Sqrt(count));

// Figure out if firstColumn is in bounds
var first = (firstColumn >= size || firstColumn < 0) ? 0 : firstColumn;

rows = (int)Math.Ceiling(Math.Sqrt(count + first));
return (rows, rows);
}
}
else if (cols == 0)
{
// If we have rows and no columns, then calculate columns needed based on rows
cols = (count + (rows - 1)) / rows;

// Now that we know a rough size of our shape, see if the FirstColumn effects that:
var first = (firstColumn >= cols || firstColumn < 0) ? 0 : firstColumn;

cols = (count + first + (rows - 1)) / rows;
}
}

return (rows, cols);
}

// Used to interleave specified row dimensions with automatic rows added to use
// underlying Grid layout for main arrange of UniformGrid.
internal void SetupRowDefinitions(int rows)
{
// Mark initial definitions so we don't erase them.
foreach (var rd in RowDefinitions)
{
if (GetAutoLayout(rd) == null)
{
SetAutoLayout(rd, false);
}
}

// Remove non-autolayout rows we've added and then add them in the right spots.
if (rows != RowDefinitions.Count)
{
for (int r = RowDefinitions.Count - 1; r >= 0; r--)
{
if (GetAutoLayout(RowDefinitions[r]) == true)
{
RowDefinitions.RemoveAt(r);
}
}

for (int r = this.RowDefinitions.Count; r < rows; r++)
{
var rd = new RowDefinition();
SetAutoLayout(rd, true);
this.RowDefinitions.Insert(r, rd);
}
}
}

// Used to interleave specified column dimensions with automatic columns added to use
// underlying Grid layout for main arrange of UniformGrid.
internal void SetupColumnDefinitions(int columns)
{
// Mark initial definitions so we don't erase them.
foreach (var cd in ColumnDefinitions)
{
if (GetAutoLayout(cd) == null)
{
SetAutoLayout(cd, false);
}
}

// Remove non-autolayout columns we've added and then add them in the right spots.
if (columns != ColumnDefinitions.Count)
{
for (int c = ColumnDefinitions.Count - 1; c >= 0; c--)
{
if (GetAutoLayout(ColumnDefinitions[c]) == true)
{
this.ColumnDefinitions.RemoveAt(c);
}
}

for (int c = ColumnDefinitions.Count; c < columns; c++)
{
var cd = new ColumnDefinition();
SetAutoLayout(cd, true);
ColumnDefinitions.Insert(c, cd);
}
}
}
}
}
Loading

0 comments on commit 6cc8f63

Please sign in to comment.