todo app fixes
This commit is contained in:
@@ -54,7 +54,7 @@
|
||||
<!-- Card-style item -->
|
||||
<Grid Padding="0,6" BackgroundColor="Transparent">
|
||||
<Border StrokeThickness="0"
|
||||
BackgroundColor="{AppThemeBinding Light={StaticResource CardBackgroundLight}, Dark={StaticResource CardBackgroundDark}}"
|
||||
BackgroundColor="{AppThemeBinding Light=#FFFFFF, Dark=#1E1E1E}"
|
||||
Padding="16,14"
|
||||
Opacity="{Binding IsCompleted, Converter={StaticResource CompletedToOpacityConverter}}">
|
||||
<Border.StrokeShape>
|
||||
@@ -67,7 +67,7 @@
|
||||
WidthRequest="8"
|
||||
HeightRequest="44"
|
||||
Margin="0"
|
||||
BackgroundColor="{Binding IsCompleted, Converter={StaticResource CompletedToColorConverter}, ConverterParameter=indicator}"
|
||||
BackgroundColor="#26A69A"
|
||||
VerticalOptions="Center">
|
||||
<Border.StrokeShape>
|
||||
<RoundRectangle CornerRadius="4" />
|
||||
@@ -98,22 +98,30 @@
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
|
||||
<!-- Footer Stats -->
|
||||
<!-- Footer Stats with Theme Toggle -->
|
||||
<Border Grid.Row="1"
|
||||
BackgroundColor="{StaticResource PrimaryColor}"
|
||||
StrokeThickness="0"
|
||||
Padding="24,14"
|
||||
Padding="20,10"
|
||||
Margin="0">
|
||||
<Grid ColumnDefinitions="Auto,Auto" ColumnSpacing="6" HorizontalOptions="Center" VerticalOptions="Center">
|
||||
<Grid ColumnDefinitions="*,Auto" VerticalOptions="Center">
|
||||
<!-- Stats on the left -->
|
||||
<Label Grid.Column="0"
|
||||
Text="Tasks:"
|
||||
FontSize="15"
|
||||
TextColor="White" />
|
||||
<Label Grid.Column="1"
|
||||
x:Name="StatsLabel"
|
||||
FontSize="15"
|
||||
TextColor="White"
|
||||
Opacity="0.9" />
|
||||
VerticalOptions="Center"
|
||||
LineBreakMode="NoWrap" />
|
||||
|
||||
<!-- Theme Toggle on the right -->
|
||||
<ImageButton Grid.Column="1"
|
||||
x:Name="ThemeToggleButton"
|
||||
Source="light_mode_white.svg"
|
||||
WidthRequest="32"
|
||||
HeightRequest="32"
|
||||
BackgroundColor="Transparent"
|
||||
Clicked="OnThemeToggleClicked"
|
||||
VerticalOptions="Center" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace TodoApp;
|
||||
public partial class TodoListPage : ContentPage
|
||||
{
|
||||
private readonly TodoService _service = TodoService.Instance;
|
||||
private bool _isNavigating; // Guard against double navigation
|
||||
|
||||
public TodoListPage()
|
||||
{
|
||||
@@ -18,22 +19,33 @@ public partial class TodoListPage : ContentPage
|
||||
TodoCollectionView.ItemsSource = _service.Todos;
|
||||
UpdateStats();
|
||||
|
||||
// Subscribe to theme changes to verify event is firing
|
||||
if (Application.Current != null)
|
||||
{
|
||||
Application.Current.RequestedThemeChanged += (s, e) =>
|
||||
{
|
||||
Console.WriteLine($"[TodoListPage] RequestedThemeChanged event received! NewTheme={e.RequestedTheme}");
|
||||
};
|
||||
}
|
||||
|
||||
Console.WriteLine("[TodoListPage] Constructor finished");
|
||||
}
|
||||
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
Console.WriteLine("[TodoListPage] OnAppearing called - refreshing CollectionView");
|
||||
base.OnAppearing();
|
||||
|
||||
// Reset navigation guard when page reappears
|
||||
_isNavigating = false;
|
||||
|
||||
// Refresh indexes for alternating row colors
|
||||
_service.RefreshIndexes();
|
||||
|
||||
// Refresh the collection view
|
||||
TodoCollectionView.ItemsSource = null;
|
||||
TodoCollectionView.ItemsSource = _service.Todos;
|
||||
Console.WriteLine($"[TodoListPage] ItemsSource set with {_service.Todos.Count} items");
|
||||
UpdateStats();
|
||||
UpdateThemeIcon();
|
||||
}
|
||||
|
||||
private async void OnAddClicked(object sender, EventArgs e)
|
||||
@@ -43,23 +55,18 @@ public partial class TodoListPage : ContentPage
|
||||
|
||||
private async void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
try
|
||||
// Guard against double navigation
|
||||
if (_isNavigating)
|
||||
{
|
||||
Console.WriteLine($"[TodoListPage] OnSelectionChanged: {e.CurrentSelection.Count} items selected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.CurrentSelection.FirstOrDefault() is TodoItem todo)
|
||||
{
|
||||
Console.WriteLine($"[TodoListPage] Navigating to TodoDetailPage for: {todo.Title}");
|
||||
TodoCollectionView.SelectedItem = null; // Deselect
|
||||
var detailPage = new TodoDetailPage(todo);
|
||||
Console.WriteLine($"[TodoListPage] Created TodoDetailPage, pushing...");
|
||||
await Navigation.PushAsync(detailPage);
|
||||
Console.WriteLine($"[TodoListPage] Navigation complete");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[TodoListPage] EXCEPTION in OnSelectionChanged: {ex.GetType().Name}: {ex.Message}");
|
||||
Console.WriteLine($"[TodoListPage] Stack trace: {ex.StackTrace}");
|
||||
_isNavigating = true;
|
||||
TodoCollectionView.SelectedItem = null; // Deselect immediately
|
||||
await Navigation.PushAsync(new TodoDetailPage(todo));
|
||||
// Note: _isNavigating is reset in OnAppearing when we return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,13 +77,42 @@ public partial class TodoListPage : ContentPage
|
||||
|
||||
if (total == 0)
|
||||
{
|
||||
StatsLabel.Text = "";
|
||||
StatsLabel.Text = "No tasks";
|
||||
}
|
||||
else
|
||||
{
|
||||
StatsLabel.Text = $"{completed} of {total} completed";
|
||||
StatsLabel.Text = $"Tasks: {completed} of {total} completed";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateThemeIcon()
|
||||
{
|
||||
// Check UserAppTheme first, fall back to RequestedTheme
|
||||
var userTheme = Application.Current?.UserAppTheme ?? AppTheme.Unspecified;
|
||||
var effectiveTheme = userTheme != AppTheme.Unspecified ? userTheme : Application.Current?.RequestedTheme ?? AppTheme.Light;
|
||||
var isDarkMode = effectiveTheme == AppTheme.Dark;
|
||||
|
||||
// Show sun icon in dark mode (to switch to light), moon icon in light mode (to switch to dark)
|
||||
ThemeToggleButton.Source = isDarkMode ? "light_mode_white.svg" : "dark_mode_white.svg";
|
||||
Console.WriteLine($"[TodoListPage] UpdateThemeIcon: UserAppTheme={userTheme}, RequestedTheme={Application.Current?.RequestedTheme}, isDarkMode={isDarkMode}");
|
||||
}
|
||||
|
||||
private void OnThemeToggleClicked(object? sender, EventArgs e)
|
||||
{
|
||||
if (Application.Current == null) return;
|
||||
|
||||
// Check current effective theme
|
||||
var userTheme = Application.Current.UserAppTheme;
|
||||
var effectiveTheme = userTheme != AppTheme.Unspecified ? userTheme : Application.Current.RequestedTheme;
|
||||
var isDarkMode = effectiveTheme == AppTheme.Dark;
|
||||
|
||||
// Toggle to the opposite theme
|
||||
var newTheme = isDarkMode ? AppTheme.Light : AppTheme.Dark;
|
||||
Application.Current.UserAppTheme = newTheme;
|
||||
|
||||
Console.WriteLine($"[TodoListPage] Theme toggled from {effectiveTheme} to {newTheme}");
|
||||
UpdateThemeIcon();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,7 +147,8 @@ public class AlternatingRowColorConverter : IValueConverter
|
||||
public class CompletedToColorConverter : IValueConverter
|
||||
{
|
||||
// Light theme colors
|
||||
private static readonly Color AccentColor = Color.FromArgb("#26A69A");
|
||||
private static readonly Color AccentColorLight = Color.FromArgb("#26A69A");
|
||||
private static readonly Color AccentColorDark = Color.FromArgb("#4DB6AC");
|
||||
private static readonly Color CompletedColor = Color.FromArgb("#9E9E9E");
|
||||
private static readonly Color TextPrimaryLight = Color.FromArgb("#212121");
|
||||
private static readonly Color TextSecondaryLight = Color.FromArgb("#757575");
|
||||
@@ -126,10 +163,12 @@ public class CompletedToColorConverter : IValueConverter
|
||||
string param = parameter as string ?? "";
|
||||
bool isDarkMode = Application.Current?.RequestedTheme == AppTheme.Dark;
|
||||
|
||||
// Indicator bar color
|
||||
// Indicator bar color - theme-aware accent color
|
||||
if (param == "indicator")
|
||||
{
|
||||
return isCompleted ? CompletedColor : AccentColor;
|
||||
var color = isCompleted ? CompletedColor : (isDarkMode ? AccentColorDark : AccentColorLight);
|
||||
Console.WriteLine($"[CompletedToColorConverter] indicator: isCompleted={isCompleted}, isDarkMode={isDarkMode}, color={color}");
|
||||
return color;
|
||||
}
|
||||
|
||||
// Text colors with theme support
|
||||
@@ -186,3 +225,4 @@ public class CompletedToOpacityConverter : IValueConverter
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
TodoApp/Resources/Images/dark_mode_white.svg
Normal file
1
TodoApp/Resources/Images/dark_mode_white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path fill="#FFFFFF" d="M480-120q-150 0-255-105T120-480q0-150 105-255t255-105q14 0 27.5 1t26.5 3q-41 29-65.5 75.5T444-660q0 90 63 153t153 63q55 0 101-24.5t75-65.5q2 13 3 26.5t1 27.5q0 150-105 255T480-120Zm0-80q88 0 158-48.5T740-375q-20 5-40 8t-40 3q-123 0-209.5-86.5T364-660q0-20 3-40t8-40q-78 32-126.5 102T200-480q0 116 82 198t198 82Zm-10-270Z"/></svg>
|
||||
|
After Width: | Height: | Size: 442 B |
1
TodoApp/Resources/Images/light_mode_white.svg
Normal file
1
TodoApp/Resources/Images/light_mode_white.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path fill="#FFFFFF" d="M480-360q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Zm0 80q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480q0 83-58.5 141.5T480-280ZM200-440H40v-80h160v80Zm720 0H760v-80h160v80ZM440-760v-160h80v160h-80Zm0 720v-160h80v160h-80ZM256-650l-101-97 57-59 96 100-52 56Zm492 496-97-101 53-55 101 97-57 59Zm-98-550 97-101 59 57-100 96-56-52ZM154-212l101-97 55 53-97 101-59-57Zm326-268Z"/></svg>
|
||||
|
After Width: | Height: | Size: 548 B |
@@ -38,9 +38,12 @@
|
||||
<MauiXaml Update="**/*.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Embedded Resources (icons) -->
|
||||
<!-- Images -->
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Images\*.svg" />
|
||||
<MauiImage Include="Resources\Images\*.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Import OpenMaui targets for Linux builds -->
|
||||
<Import Project="../../maui-linux/build/OpenMaui.Controls.Linux.targets" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -78,4 +78,15 @@ public class TodoItem : INotifyPropertyChanged
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces all bindings to re-evaluate by notifying all properties changed.
|
||||
/// Used when external factors (like app theme) change.
|
||||
/// </summary>
|
||||
public void RefreshBindings()
|
||||
{
|
||||
OnPropertyChanged(nameof(IsCompleted));
|
||||
OnPropertyChanged(nameof(Title));
|
||||
OnPropertyChanged(nameof(Notes));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user