👔 💄 🖖 🚧 WIP MVVM album detail

pull/1/head
Alexis Drai 2 years ago
parent 4201f8f766
commit c36734dbd7

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>
<Nullable>enable</Nullable>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
@ -52,9 +53,14 @@
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<MauiXaml Update="Views\AlbumPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
</ItemGroup>
<ItemGroup>
<Folder Include="Pages\" />
<Folder Include="Views\" />
</ItemGroup>
</Project>

@ -2,10 +2,10 @@
public partial class App : Application
{
public App()
{
InitializeComponent();
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
MainPage = new AppShell();
}
}

@ -2,8 +2,8 @@
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
public AppShell()
{
InitializeComponent();
}
}

@ -3,39 +3,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AD_MAUI.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
<Button
x:Name="RdmBtn"
Text="DO IT"
Clicked="OnRdmBtnClicked"
/>
</ContentPage>

@ -1,24 +1,20 @@
namespace AD_MAUI;
using AD_MAUI.ViewModel;
using AD_MAUI.Views;
namespace AD_MAUI;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
public MainPage()
{
InitializeComponent();
}
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
// TODO use commands (or navigation methods?) in VMApp instead
private void OnRdmBtnClicked(object sender, EventArgs e)
{
Navigation.PushAsync(new AlbumPage(new AlbumViewModel(null)));
}
SemanticScreenReader.Announce(CounterBtn.Text);
}
}

@ -4,21 +4,21 @@ namespace AD_MAUI;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if DEBUG
builder.Logging.AddDebug();
builder.Logging.AddDebug();
#endif
return builder.Build();
}
return builder.Build();
}
}

@ -0,0 +1,12 @@
namespace AD_MAUI.Model
{
public class Album
{
public int Id { get; set; }
public string Title { get; set; }
public string Artist { get; set; }
public string CoverImage { get; set; }
public List<Song> Songs { get; set; }
}
}

@ -0,0 +1,9 @@
namespace AD_MAUI.Model
{
public class Song
{
public int Id { get; set; }
public string Title { get; set; }
public int Duration { get; set; }
}
}

@ -1,6 +1,5 @@
using Android.App;
using Android.Content.PM;
using Android.OS;
namespace AD_MAUI;

@ -6,10 +6,10 @@ namespace AD_MAUI;
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -5,5 +5,5 @@ namespace AD_MAUI;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -1,15 +1,14 @@
using ObjCRuntime;
using UIKit;
using UIKit;
namespace AD_MAUI;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}

@ -1,6 +1,4 @@
using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure,
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace AD_MAUI.WinUI;
@ -10,15 +8,15 @@ namespace AD_MAUI.WinUI;
/// </summary>
public partial class App : MauiWinUIApplication
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -5,5 +5,5 @@ namespace AD_MAUI;
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

@ -1,15 +1,14 @@
using ObjCRuntime;
using UIKit;
using UIKit;
namespace AD_MAUI;
public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}

@ -0,0 +1,86 @@
using AD_MAUI.Model;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace AD_MAUI.ViewModel
{
// TODO make sure not to notify change if not necessary!
public class AlbumViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private readonly Album album = new();
public int Id { get => album.Id; }
public string Title
{
get => album.Title;
set
{
if (album.Title != value)
{
album.Title = value;
OnPropertyChanged();
}
}
}
public string Artist
{
get => album.Artist;
set
{
if (album.Artist != value)
{
album.Artist = value;
OnPropertyChanged();
}
}
}
public string CoverImage
{
get => album.CoverImage;
set
{
if (album.CoverImage != value)
{
album.CoverImage = value;
OnPropertyChanged();
}
}
}
public ReadOnlyObservableCollection<SongViewModel> Songs { get => new(songs); }
private readonly ObservableCollection<SongViewModel> songs;
public AlbumViewModel(Album? album)
{
// Mocked data for testing
this.album = album ?? new Album
{
Id = 1,
Title = "Test Album",
Artist = "Test Artist",
CoverImage = "dotnet_bot.png", // make this a path?
Songs = new List<Song>
{
new Song { Id = 1, Title = "Test Song 1", Duration = 210 },
new Song { Id = 2, Title = "Test Song 2", Duration = 260 },
new Song { Id = 3, Title = "Test Song 3", Duration = 817 },
}
};
songs = new ObservableCollection<SongViewModel>(this.album.Songs.Select(song => new SongViewModel(song)));
}
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

@ -0,0 +1,51 @@
using AD_MAUI.Model;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace AD_MAUI.ViewModel
{
// TODO make sure not to notify change if not necessary!
public class SongViewModel : INotifyPropertyChanged
{
private readonly Song song;
public event PropertyChangedEventHandler? PropertyChanged;
public string Title
{
get => song.Title;
set
{
if (song.Title != value)
{
song.Title = value;
OnPropertyChanged();
}
}
}
public int Duration
{
get => song.Duration;
set
{
if (song.Duration != value)
{
song.Duration = value;
OnPropertyChanged();
}
}
}
public SongViewModel(Song? song)
{
this.song = song ?? new();
}
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:AD_MAUI.ViewModel"
x:Class="AD_MAUI.Views.AlbumPage"
x:DataType="local:AlbumViewModel">
<ScrollView>
<StackLayout>
<Image Source="{Binding CoverImage}" Aspect="AspectFit" />
<Label Text="{Binding Title}" FontSize="Large" />
<Label Text="{Binding Artist}" FontSize="Medium" />
<ListView ItemsSource="{Binding Songs}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:SongViewModel">
<TextCell
Text="{Binding Title}"
Detail="{Binding Duration, StringFormat='\{0\} second(s)'}"
/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ScrollView>
</ContentPage>

@ -0,0 +1,17 @@
using AD_MAUI.ViewModel;
namespace AD_MAUI.Views
{
public partial class AlbumPage : ContentPage
{
private readonly AlbumViewModel viewModel;
public AlbumPage(AlbumViewModel? albumViewModel)
{
InitializeComponent();
viewModel = albumViewModel ?? new AlbumViewModel(null);
BindingContext = viewModel;
}
}
}
Loading…
Cancel
Save