diff --git a/Anikin/Models/AnimeHomeRange.cs b/Anikin/Models/AnimeHomeRange.cs new file mode 100644 index 0000000..f67267f --- /dev/null +++ b/Anikin/Models/AnimeHomeRange.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Anikin.Utils; +using Anikin.Utils.Extensions; +using CommunityToolkit.Mvvm.ComponentModel; +using Jita.AniList.Models; + +namespace Anikin.Models; + +public partial class AnimeHomeRange : ObservableObject +{ + public string Name { get; set; } + + [ObservableProperty] + bool _isLoading; + + public AnimeHomeTypes Type { get; set; } + + public ObservableRangeCollection Medias { get; set; } = new(); + + [ObservableProperty] + private bool _isSelected; + + public AnimeHomeRange(AnimeHomeTypes type) + { + Type = type; + Name = Type.GetBestDisplayName(); + } + + public AnimeHomeRange(AnimeHomeTypes type, IEnumerable medias) : this(type) + { + Medias.AddRange(medias); + } + + public override string ToString() => Name; +} diff --git a/Anikin/Models/AnimeHomeTypes.cs b/Anikin/Models/AnimeHomeTypes.cs new file mode 100644 index 0000000..abfef52 --- /dev/null +++ b/Anikin/Models/AnimeHomeTypes.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; + +namespace Anikin.Models; + +public enum AnimeHomeTypes +{ + [Description("Popular")] + Popular, + + [Description("Recently Updated")] + LastUpdated, + + [Description("Current Season")] + CurrentSeason, + + [Description("Trending")] + Trending, + + [Description("New Season")] + NewSeason, + + [Description("Feminine Audience")] + FeminineMedia, + + [Description("Male Audience")] + MaleMedia, + + [Description("Trash Anime")] + TrashMedia +} diff --git a/Anikin/ViewModels/HomeViewModel.cs b/Anikin/ViewModels/HomeViewModel.cs index aed98dd..a2d68b2 100644 --- a/Anikin/ViewModels/HomeViewModel.cs +++ b/Anikin/ViewModels/HomeViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Anikin.Models; using Anikin.Services; using Anikin.Utils; using Anikin.Utils.Extensions; @@ -24,20 +25,20 @@ public partial class HomeViewModel : BaseViewModel private int Page { get; set; } - public ObservableRangeCollection PopularAnimes { get; set; } = new(); public ObservableRangeCollection CurrentSeasonAnimes { get; set; } = new(); - public ObservableRangeCollection TrendingAnimes { get; set; } = new(); + public ObservableRangeCollection PopularAnimes { get; set; } = new(); public ObservableRangeCollection LastUpdatedAnimes { get; set; } = new(); - public ObservableRangeCollection NewSeasonAnimes { get; set; } = new(); - public ObservableRangeCollection FeminineMedia { get; set; } = new(); - public ObservableRangeCollection TrashMedia { get; set; } = new(); - public ObservableRangeCollection MaleMedia { get; set; } = new(); [ObservableProperty] private int _selectedViewModelIndex; public ProfileViewModel ProfileViewModel { get; set; } + public ObservableRangeCollection Ranges { get; set; } = new(); + + [ObservableProperty] + AnimeHomeRange _selectedRange; + public HomeViewModel( AniClient anilistClient, ProfileViewModel profileViewModel, @@ -51,6 +52,12 @@ SettingsService settingsService _settingsService.Load(); //Load(); + + var homeTypes = Enum.GetValues(typeof(AnimeHomeTypes)).Cast(); + Ranges.AddRange(homeTypes.Select(x => new AnimeHomeRange(x))); + Ranges[0].IsSelected = true; + + SelectedRange = Ranges[0]; } protected override async Task LoadCore() @@ -61,16 +68,18 @@ protected override async Task LoadCore() if (!IsRefreshing) IsBusy = true; + RangeSelected(SelectedRange); + try { LoadPopular(); - LoadCurrentSeason(); - LoadTrending(); LoadLastUpdated(); - LoadNewSeason(); - LoadFeminineMedia(); - LoadMaleMedia(); - LoadTrashMedia(); + LoadCurrentSeason(); + //LoadTrending(); + //LoadNewSeason(); + //LoadFeminineMedia(); + //LoadMaleMedia(); + //LoadTrashMedia(); //var pages2 = await _anilistClient.GetTrendingMediaAsync(); //var schedulesResult = await _anilistClient.GetMediaSchedulesAsync( @@ -134,10 +143,53 @@ async Task GoToSearch() await Shell.Current.GoToAsync(nameof(SearchView)); } + [RelayCommand] + void RangeSelected(AnimeHomeRange range) + { + for (var i = 0; i < Ranges.Count; i++) + { + Ranges[i].IsSelected = false; + } + + range.IsSelected = true; + + SelectedRange = range; + + switch (range.Type) + { + case AnimeHomeTypes.Popular: + break; + case AnimeHomeTypes.LastUpdated: + break; + case AnimeHomeTypes.CurrentSeason: + break; + case AnimeHomeTypes.Trending: + LoadTrending(); + break; + case AnimeHomeTypes.NewSeason: + LoadNewSeason(); + break; + case AnimeHomeTypes.FeminineMedia: + LoadFeminineMedia(); + break; + case AnimeHomeTypes.MaleMedia: + LoadMaleMedia(); + break; + case AnimeHomeTypes.TrashMedia: + LoadTrashMedia(); + break; + } + } + private async void LoadMaleMedia() { + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.MaleMedia); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + var result = await _anilistClient.SearchMediaAsync( new SearchMediaFilter() { @@ -148,24 +200,31 @@ private async void LoadMaleMedia() } ); - var data = result - .Data + var data = result.Data .Where(x => _settingsService.ShowNonJapaneseAnime || x.CountryOfOrigin == "JP") .ToList(); - MaleMedia.Clear(); - MaleMedia.Push(data); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } private async void LoadFeminineMedia() { + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.FeminineMedia); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + var result = await _anilistClient.SearchMediaAsync( new SearchMediaFilter() { @@ -176,24 +235,31 @@ private async void LoadFeminineMedia() } ); - var data = result - .Data + var data = result.Data .Where(x => _settingsService.ShowNonJapaneseAnime || x.CountryOfOrigin == "JP") .ToList(); - FeminineMedia.Clear(); - FeminineMedia.Push(data); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } private async void LoadTrashMedia() { + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.TrashMedia); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + var result = await _anilistClient.SearchMediaAsync( new SearchMediaFilter() { @@ -204,46 +270,60 @@ private async void LoadTrashMedia() } ); - var data = result - .Data + var data = result.Data .Where(x => _settingsService.ShowNonJapaneseAnime || x.CountryOfOrigin == "JP") .ToList(); - TrashMedia.Clear(); - TrashMedia.Push(data); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } private async void LoadNewSeason() { + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.NewSeason); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + var result = await _anilistClient.SearchMediaAsync( new SearchMediaFilter { Season = MediaSeason.Winter } ); - var data = result - .Data + var data = result.Data .Where(x => _settingsService.ShowNonJapaneseAnime || x.CountryOfOrigin == "JP") .ToList(); - NewSeasonAnimes.Clear(); - NewSeasonAnimes.Push(data); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } private async void LoadLastUpdated() { + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.LastUpdated); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + var recentlyUpdateResult = await _anilistClient.GetMediaSchedulesAsync( new MediaSchedulesFilter { @@ -256,8 +336,7 @@ private async void LoadLastUpdated() new AniPaginationOptions(1, 50) ); - var data = recentlyUpdateResult - .Data + var data = recentlyUpdateResult.Data .Where( x => x.Media is not null @@ -273,24 +352,35 @@ x.Media is not null LastUpdatedAnimes.Clear(); LastUpdatedAnimes.Push(data); + + rangeItem.Medias.Clear(); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } private async void LoadTrending() { + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.Trending); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + var result = await _anilistClient.GetTrendingMediaAsync( new MediaTrendFilter() { Sort = MediaTrendSort.Popularity }, new AniPaginationOptions() ); - var data = result - .Data + var data = result.Data .Where( x => x.Media is not null @@ -301,13 +391,17 @@ x.Media is not null .Select(x => x.Media!) .ToList(); - TrendingAnimes.Clear(); - TrendingAnimes.Push(data); + rangeItem.Medias.Clear(); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } private async void LoadCurrentSeason() @@ -321,8 +415,13 @@ private async void LoadCurrentSeason() _ => MediaSeason.Winter, }; + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.CurrentSeason); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + var result = await _anilistClient.SearchMediaAsync( new SearchMediaFilter() { @@ -333,24 +432,35 @@ private async void LoadCurrentSeason() } ); - var data = result - .Data + var data = result.Data .Where(x => _settingsService.ShowNonJapaneseAnime || x.CountryOfOrigin == "JP") .ToList(); CurrentSeasonAnimes.Clear(); CurrentSeasonAnimes.Push(data); + + rangeItem.Medias.Clear(); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } private async void LoadPopular() { + var rangeItem = Ranges.First(x => x.Type == AnimeHomeTypes.Popular); + try { + rangeItem.IsLoading = true; + rangeItem.Medias.Clear(); + //var result = await _anilistClient.SearchMediaAsync(new SearchMediaFilter() //{ // Query = "demon slayer", @@ -366,17 +476,23 @@ private async void LoadPopular() } ); - var data = result - .Data + var data = result.Data .Where(x => _settingsService.ShowNonJapaneseAnime || x.CountryOfOrigin == "JP") .ToList(); PopularAnimes.Clear(); PopularAnimes.Push(data); + + rangeItem.Medias.Clear(); + rangeItem.Medias.Push(data); } catch (Exception ex) { await Toast.Make(ex.ToString()).Show(); } + finally + { + rangeItem.IsLoading = false; + } } } diff --git a/Anikin/Views/Templates/AnimeTypeRangeTemplateView.xaml b/Anikin/Views/Templates/AnimeTypeRangeTemplateView.xaml new file mode 100644 index 0000000..4e4760e --- /dev/null +++ b/Anikin/Views/Templates/AnimeTypeRangeTemplateView.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Anikin/Views/Templates/AnimeTypeRangeTemplateView.xaml.cs b/Anikin/Views/Templates/AnimeTypeRangeTemplateView.xaml.cs new file mode 100644 index 0000000..63eb466 --- /dev/null +++ b/Anikin/Views/Templates/AnimeTypeRangeTemplateView.xaml.cs @@ -0,0 +1,19 @@ +using Microsoft.Maui.Controls; + +namespace Anikin.Views.Templates; + +public partial class AnimeTypeRangeTemplateView +{ + public AnimeTypeRangeTemplateView() + { + InitializeComponent(); + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + + Scale = 0.4; + this.ScaleTo(1, 150); + } +}