Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Templates/src/templates/maui-mobile/AppShell.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
SegmentWidth="40" SegmentHeight="40">
<sf:SfSegmentedControl.ItemsSource>
<x:Array Type="{x:Type sf:SfSegmentItem}">
<sf:SfSegmentItem ImageSource="{StaticResource IconLight}"/>
<sf:SfSegmentItem ImageSource="{StaticResource IconDark}"/>
<sf:SfSegmentItem ImageSource="{StaticResource IconLight}" SemanticProperties.Description="Light mode"/>
<sf:SfSegmentItem ImageSource="{StaticResource IconDark}" SemanticProperties.Description="Dark mode"/>
</x:Array>
</sf:SfSegmentedControl.ItemsSource>
</sf:SfSegmentedControl>
Expand Down
3 changes: 3 additions & 0 deletions src/Templates/src/templates/maui-mobile/AppShell.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public AppShell()
#if (IncludeSampleContent)
var currentTheme = Application.Current!.RequestedTheme;
ThemeSegmentedControl.SelectedIndex = currentTheme == AppTheme.Light ? 0 : 1;
#endif
#if ANDROID || WINDOWS
SemanticProperties.SetDescription(ThemeSegmentedControl, "Theme selection");
#endif
}
#if (IncludeSampleContent)
Expand Down

This file was deleted.

32 changes: 32 additions & 0 deletions src/Templates/src/templates/maui-mobile/Data/TagRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ public async Task<int> SaveItemAsync(Tag item, int projectID)
await Init();
await SaveItemAsync(item);

var isAssociated = await IsAssociated(item, projectID);
if (isAssociated)
{
return 0; // No need to save again if already associated
}

await using var connection = new SqliteConnection(Constants.DatabasePath);
await connection.OpenAsync();

Expand All @@ -212,6 +218,32 @@ public async Task<int> SaveItemAsync(Tag item, int projectID)
return await saveCmd.ExecuteNonQueryAsync();
}

/// <summary>
/// Checks if a tag is already associated with a specific project.
/// </summary>
/// <param name="item">The tag to save.</param>
/// <param name="projectID">The ID of the project.</param>
/// <returns>If tag is already associated with this project</returns>
async Task<bool> IsAssociated(Tag item, int projectID)
{
await Init();

await using var connection = new SqliteConnection(Constants.DatabasePath);
await connection.OpenAsync();

// First check if the association already exists
var checkCmd = connection.CreateCommand();
checkCmd.CommandText = @"
SELECT COUNT(*) FROM ProjectsTags
WHERE ProjectID = @projectID AND TagID = @tagID";
checkCmd.Parameters.AddWithValue("@projectID", projectID);
checkCmd.Parameters.AddWithValue("@tagID", item.ID);

int existingCount = Convert.ToInt32(await checkCmd.ExecuteScalarAsync());

return existingCount != 0;
}

/// <summary>
/// Deletes a tag from the database.
/// </summary>
Expand Down
19 changes: 19 additions & 0 deletions src/Templates/src/templates/maui-mobile/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ public static MauiApp CreateMauiApp()
#if (IncludeSampleContent)
.UseMauiCommunityToolkit()
.ConfigureSyncfusionToolkit()
//-:cnd:noEmit
.ConfigureMauiHandlers(handlers =>
{
#if WINDOWS
Microsoft.Maui.Controls.Handlers.Items.CollectionViewHandler.Mapper.AppendToMapping("KeyboardAccessibleCollectionView", (handler, view) =>
{
handler.PlatformView.SingleSelectionFollowsFocus = false;
});

Microsoft.Maui.Handlers.ContentViewHandler.Mapper.AppendToMapping(nameof(Pages.Controls.CategoryChart), (handler, view) =>
{
if (view is Pages.Controls.CategoryChart && handler.PlatformView is ContentPanel contentPanel)
{
contentPanel.IsTabStop = true;
}
});
#endif
})
//+:cnd:noEmit
#endif
.ConfigureFonts(fonts =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public partial class MainPageModel : ObservableObject, IProjectTaskPageModel

[ObservableProperty]
private Project? selectedProject;

public bool HasCompletedTasks
=> Tasks?.Any(t => t.IsCompleted) ?? false;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MauiApp._1.Models;
using System.Collections.ObjectModel;
using System.Windows.Input;

namespace MauiApp._1.PageModels;

Expand Down Expand Up @@ -34,6 +36,8 @@ public partial class ProjectDetailPageModel : ObservableObject, IQueryAttributab
[ObservableProperty]
private List<Tag> _allTags = [];

public IList<object> SelectedTags { get; set; } = new List<object>();

[ObservableProperty]
private IconData _icon;

Expand Down Expand Up @@ -147,6 +151,10 @@ private async Task LoadData(int id)
foreach (var tag in allTags)
{
tag.IsSelected = _project.Tags.Any(t => t.ID == tag.ID);
if (tag.IsSelected)
{
SelectedTags.Add(tag);
}
}
AllTags = new(allTags);
}
Expand All @@ -169,7 +177,6 @@ private async Task TaskCompleted(ProjectTask task)
OnPropertyChanged(nameof(HasCompletedTasks));
}


[RelayCommand]
private async Task Save()
{
Expand All @@ -187,14 +194,11 @@ private async Task Save()
_project.Icon = Icon.Icon ?? FluentUI.ribbon_24_regular;
await _projectRepository.SaveItemAsync(_project);

if (_project.IsNullOrNew())
foreach (var tag in AllTags)
{
foreach (var tag in AllTags)
if (tag.IsSelected)
{
if (tag.IsSelected)
{
await _tagRepository.SaveItemAsync(tag, _project.ID);
}
await _tagRepository.SaveItemAsync(tag, _project.ID);
}
}

Expand Down Expand Up @@ -249,7 +253,7 @@ private Task NavigateToTask(ProjectTask task) =>
Shell.Current.GoToAsync($"task?id={task.ID}");

[RelayCommand]
private async Task ToggleTag(Tag tag)
internal async Task ToggleTag(Tag tag)
{
tag.IsSelected = !tag.IsSelected;

Expand All @@ -258,20 +262,15 @@ private async Task ToggleTag(Tag tag)
if (tag.IsSelected)
{
await _tagRepository.SaveItemAsync(tag, _project.ID);
AllTags = new(AllTags);
SemanticScreenReader.Announce($"{tag.Title} selected");
}
else
{
await _tagRepository.DeleteItemAsync(tag, _project.ID);
AllTags = new(AllTags);
SemanticScreenReader.Announce($"{tag.Title} unselected");
}
}
else
{
AllTags = new(AllTags);
}

AllTags = new(AllTags);
SemanticScreenReader.Announce($"{tag.Title} {(tag.IsSelected ? "selected" : "unselected")}");
}

[RelayCommand]
Expand All @@ -294,4 +293,34 @@ private async Task CleanTasks()
OnPropertyChanged(nameof(HasCompletedTasks));
await AppShell.DisplayToastAsync("All cleaned up!");
}

[RelayCommand]
private async Task SelectionChanged(object parameter)
{
if (parameter is IEnumerable<object> enumerableParameter)
{
var currentSelection = enumerableParameter.OfType<Tag>().ToList();
var previousSelection = AllTags.Where(t => t.IsSelected).ToList();

// Handle newly selected tags
foreach (var tag in currentSelection.Except(previousSelection))
{
tag.IsSelected = true;
if (!_project.IsNullOrNew())
{
await _tagRepository.SaveItemAsync(tag, _project.ID);
}
}

// Handle deselected tags
foreach (var tag in previousSelection.Except(currentSelection))
{
tag.IsSelected = false;
if (!_project.IsNullOrNew())
{
await _tagRepository.DeleteItemAsync(tag, _project.ID);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#nullable disable
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MauiApp._1.Data;
Expand All @@ -14,6 +13,9 @@ public partial class ProjectListPageModel : ObservableObject
[ObservableProperty]
private List<Project> _projects = [];

[ObservableProperty]
private Project? selectedProject;

public ProjectListPageModel(ProjectRepository projectRepository)
{
_projectRepository = projectRepository;
Expand All @@ -26,8 +28,8 @@ private async Task Appearing()
}

[RelayCommand]
Task NavigateToProject(Project project)
=> Shell.Current.GoToAsync($"project?id={project.ID}");
Task? NavigateToProject(Project project)
=> project is null ? Task.CompletedTask : Shell.Current.GoToAsync($"project?id={project.ID}");

[RelayCommand]
async Task AddProject()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
xmlns:shimmer="clr-namespace:Syncfusion.Maui.Toolkit.Shimmer;assembly=Syncfusion.Maui.Toolkit"
xmlns:pageModels="clr-namespace:MauiApp._1.PageModels"
xmlns:models="clr-namespace:MauiApp._1.Models"
xmlns:converter="clr-namespace:MauiApp._1.Converter"
x:Class="MauiApp._1.Pages.Controls.CategoryChart"
x:DataType="pageModels:MainPageModel"
HeightRequest="{OnIdiom 300, Phone=200}"
Expand All @@ -16,7 +15,6 @@
AutomationProperties.IsInAccessibleTree="False"
BackgroundColor="Transparent"
VerticalOptions="Fill"
x:DataType="pageModels:MainPageModel"
IsActive="{Binding IsBusy}">
<shimmer:SfShimmer.CustomView>
<Grid>
Expand All @@ -28,12 +26,11 @@
</shimmer:SfShimmer.CustomView>
<shimmer:SfShimmer.Content>
<chart:SfCircularChart x:Name="Chart"
SemanticProperties.Description="Task Categories Chart">
SemanticProperties.Description="Task Categories Chart">
<chart:SfCircularChart.Resources>
<converter:DataLabelValueConverter x:Key="valueConverter"/>
<controls:ChartDataLabelConverter x:Key="ChartDataLabelConverter"/>
</chart:SfCircularChart.Resources>
<chart:DoughnutSeries
x:DataType="pageModels:MainPageModel"
<chart:DoughnutSeries
ItemsSource="{Binding TodoCategoryData}"
PaletteBrushes="{Binding TodoCategoryColors}"
XBindingPath="Title"
Expand All @@ -46,31 +43,31 @@
<chart:DoughnutSeries.LabelTemplate>
<DataTemplate>
<HorizontalStackLayout x:DataType="chart:ChartDataLabel">
<Label Text="{Binding Item, Converter={StaticResource valueConverter}, ConverterParameter='Title'}"
TextColor="{AppThemeBinding
<Label Text="{Binding Item, Converter={StaticResource ChartDataLabelConverter}, ConverterParameter='title'}"
TextColor="{AppThemeBinding
Light={StaticResource DarkOnLightBackground},
Dark={StaticResource LightOnDarkBackground}}"
FontSize="{OnIdiom 18, Phone=14}"/>
FontSize="{OnIdiom 18, Phone=14}"/>
<Label Text=": "
TextColor="{AppThemeBinding
TextColor="{AppThemeBinding
Light={StaticResource DarkOnLightBackground},
Dark={StaticResource LightOnDarkBackground}}"
FontSize="{OnIdiom 18, Phone=14}"/>
<Label Text="{Binding Item, Converter={StaticResource valueConverter}, ConverterParameter='Count'}"
TextColor="{AppThemeBinding
FontSize="{OnIdiom 18, Phone=14}"/>
<Label Text="{Binding Item, Converter={StaticResource ChartDataLabelConverter}, ConverterParameter='count'}"
TextColor="{AppThemeBinding
Light={StaticResource DarkOnLightBackground},
Dark={StaticResource LightOnDarkBackground}}"
FontSize="{OnIdiom 18, Phone=14}"/>
FontSize="{OnIdiom 18, Phone=14}"/>
</HorizontalStackLayout>
</DataTemplate>
</chart:DoughnutSeries.LabelTemplate>

<chart:DoughnutSeries.DataLabelSettings>
<chart:CircularDataLabelSettings LabelPosition="Outside"
SmartLabelAlignment="Shift">
SmartLabelAlignment="Shift">
<chart:CircularDataLabelSettings.ConnectorLineSettings>
<chart:ConnectorLineStyle ConnectorType="Line"
StrokeWidth="3"></chart:ConnectorLineStyle>
StrokeWidth="3"></chart:ConnectorLineStyle>
</chart:CircularDataLabelSettings.ConnectorLineSettings>
</chart:CircularDataLabelSettings>
</chart:DoughnutSeries.DataLabelSettings>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Globalization;
using MauiApp._1.Models;

namespace MauiApp._1.Pages.Controls;

public class ChartDataLabelConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is CategoryChartData categoryData && parameter is string parameterValue)
{
if (string.Equals(parameterValue, "title", StringComparison.OrdinalIgnoreCase))
{
return categoryData.Title;
}

if (string.Equals(parameterValue, "count", StringComparison.OrdinalIgnoreCase))
{
return categoryData.Count.ToString();
}

return value?.ToString();
}

return value?.ToString();
}

public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Loading