Skip to content

Commit

Permalink
Add manga support
Browse files Browse the repository at this point in the history
  • Loading branch information
jerry08 committed Feb 2, 2024
1 parent efb157b commit 1903024
Show file tree
Hide file tree
Showing 51 changed files with 4,759 additions and 17 deletions.
15 changes: 12 additions & 3 deletions Anikin/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ public App(IServiceProvider provider)

Services = provider;

AlertService = Services.GetService<IAlertService>()!;
AlertService = Services.GetRequiredService<IAlertService>();

var settingsService = Services.GetService<SettingsService>()!;
var settingsService = Services.GetRequiredService<SettingsService>();
settingsService.Load();

IsInDeveloperMode = settingsService.EnableDeveloperMode;
Expand Down Expand Up @@ -112,7 +112,7 @@ public static void ApplyTheme(bool force = false)
if (Current is null)
return;

var settingsService = Services.GetService<SettingsService>()!;
var settingsService = Services.GetRequiredService<SettingsService>();
settingsService.Load();

if (force)
Expand All @@ -121,6 +121,15 @@ public static void ApplyTheme(bool force = false)
}

Current.UserAppTheme = settingsService.AppTheme;

//if (Shell.Current.CurrentPage is not null)
//{
// Berry.Maui.Controls.Insets.SetEdgeToEdge(Shell.Current.CurrentPage, true);
// Berry.Maui.Controls.Insets.SetStatusBarStyle(
// Shell.Current.CurrentPage,
// Berry.Maui.Controls.StatusBarStyle.DarkContent
// );
//}
}

protected override void OnAppLinkRequestReceived(Uri uri)
Expand Down
4 changes: 4 additions & 0 deletions Anikin/AppShell.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Anikin.Services;
using Anikin.ViewModels.Framework;
using Anikin.Views;
using Anikin.Views.Manga;
using Anikin.Views.Settings;
using CommunityToolkit.Maui.Alerts;
using CommunityToolkit.Maui.Core;
Expand All @@ -23,7 +24,10 @@ public AppShell()
InitializeComponent();

Routing.RegisterRoute(nameof(SearchView), typeof(SearchView));
Routing.RegisterRoute(nameof(MangaSearchView), typeof(MangaSearchView));
Routing.RegisterRoute(nameof(EpisodePage), typeof(EpisodePage));
Routing.RegisterRoute(nameof(MangaPage), typeof(MangaPage));
Routing.RegisterRoute(nameof(MangaReaderPage), typeof(MangaReaderPage));
Routing.RegisterRoute(nameof(AnilistLoginView), typeof(AnilistLoginView));
Routing.RegisterRoute(nameof(ExtensionsView), typeof(ExtensionsView));

Expand Down
219 changes: 219 additions & 0 deletions Anikin/Controls/PinchZoom.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui;
using Microsoft.Maui.Controls;

namespace Anikin.Controls;

// Taken from https://github.com/TBertuzzi/Bertuzzi.MAUI.PinchZoomImage
public partial class PinchZoom : ContentView
{
private double _currentScale = 1;
private double _startScale = 1;
private double _xOffset = 0;
private double _yOffset = 0;
private bool _secondDoubleTap = false;

public bool IsPinching { get; set; }

public PinchZoom()
{
var pinchGesture = new PinchGestureRecognizer();
pinchGesture.PinchUpdated += PinchUpdated;
GestureRecognizers.Add(pinchGesture);

var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(panGesture);

var tapGesture = new TapGestureRecognizer { NumberOfTapsRequired = 2 };
tapGesture.Tapped += DoubleTapped;
GestureRecognizers.Add(tapGesture);
}

private void PinchUpdated(object? sender, PinchGestureUpdatedEventArgs e)
{
switch (e.Status)
{
case GestureStatus.Started:
IsPinching = true;
_startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
break;

case GestureStatus.Running:
{
_currentScale += (e.Scale - 1) * _startScale;
_currentScale = Math.Max(1, _currentScale);

var renderedX = Content.X + _xOffset;
var deltaX = renderedX / Width;
var deltaWidth = Width / (Content.Width * _startScale);
var originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;

var renderedY = Content.Y + _yOffset;
var deltaY = renderedY / Height;
var deltaHeight = Height / (Content.Height * _startScale);
var originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;

var targetX = _xOffset - (originX * Content.Width) * (_currentScale - _startScale);
var targetY = _yOffset - (originY * Content.Height) * (_currentScale - _startScale);

Content.TranslationX = Math.Min(
0,
Math.Max(targetX, -Content.Width * (_currentScale - 1))
);
Content.TranslationY = Math.Min(
0,
Math.Max(targetY, -Content.Height * (_currentScale - 1))
);

Content.Scale = _currentScale;
break;
}

case GestureStatus.Completed:
_xOffset = Content.TranslationX;
_yOffset = Content.TranslationY;
IsPinching = false;
break;
}
}

public void OnPanUpdated(object? sender, PanUpdatedEventArgs e)
{
if (Content.Scale == 1)
{
return;
}

switch (e.StatusType)
{
case GestureStatus.Running:

var newX = (e.TotalX * Scale) + _xOffset;
var newY = (e.TotalY * Scale) + _yOffset;

var width = (Content.Width * Content.Scale);
var height = (Content.Height * Content.Scale);

var canMoveX = width > Application.Current.MainPage.Width;
var canMoveY = height > Application.Current.MainPage.Height;

if (canMoveX)
{
var minX = (width - (Application.Current.MainPage.Width / 2)) * -1;
var maxX = Math.Min(Application.Current.MainPage.Width / 2, width / 2);

if (newX < minX)
{
newX = minX;
}

if (newX > maxX)
{
newX = maxX;
}
}
else
{
newX = 0;
}

if (canMoveY)
{
var minY = (height - (Application.Current.MainPage.Height / 2)) * -1;
var maxY = Math.Min(Application.Current.MainPage.Width / 2, height / 2);

if (newY < minY)
{
newY = minY;
}

if (newY > maxY)
{
newY = maxY;
}
}
else
{
newY = 0;
}

Content.TranslationX = newX;
Content.TranslationY = newY;
break;
case GestureStatus.Completed:
_xOffset = Content.TranslationX;
_yOffset = Content.TranslationY;
break;
case GestureStatus.Started:
break;
case GestureStatus.Canceled:
break;
default:
throw new ArgumentOutOfRangeException();
}
}

public async void DoubleTapped(object? sender, TappedEventArgs e)
{
var multiplicator = Math.Pow(2, 1.0 / 10.0);
_startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;

for (var i = 0; i < 10; i++)
{
if (!_secondDoubleTap) //if it's not the second double tap we enlarge the scale
{
_currentScale *= multiplicator;
}
else //if it's the second double tap we make the scale smaller again
{
_currentScale /= multiplicator;
}

var renderedX = Content.X + _xOffset;
var deltaX = renderedX / Width;
var deltaWidth = Width / (Content.Width * _startScale);
var originX = (0.5 - deltaX) * deltaWidth;

var renderedY = Content.Y + _yOffset;
var deltaY = renderedY / Height;
var deltaHeight = Height / (Content.Height * _startScale);
var originY = (0.5 - deltaY) * deltaHeight;

var targetX = _xOffset - (originX * Content.Width) * (_currentScale - _startScale);
var targetY = _yOffset - (originY * Content.Height) * (_currentScale - _startScale);

Content.TranslationX = Math.Min(
0,
Math.Max(targetX, -Content.Width * (_currentScale - 1))
);
Content.TranslationY = Math.Min(
0,
Math.Max(targetY, -Content.Height * (_currentScale - 1))
);

Content.Scale = _currentScale;
await Task.Delay(10);
}

//if (_secondDoubleTap)
// Content.Margin = new(
// -(Content.Margin.HorizontalThickness * Content.Scale),
// -(Content.Margin.VerticalThickness * Content.Scale)
// );
//else
// Content.Margin = new(
// +(Content.Margin.HorizontalThickness / Content.Scale),
// +(Content.Margin.VerticalThickness / Content.Scale)
// );

_secondDoubleTap = !_secondDoubleTap;
_xOffset = Content.TranslationX;
_yOffset = Content.TranslationY;
}
}
23 changes: 19 additions & 4 deletions Anikin/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Anikin.Services;
using Anikin.Services.AlertDialog;
using Anikin.ViewModels;
using Anikin.ViewModels.Home;
using Anikin.Views;
using Anikin.Views.Settings;
using Berry.Maui;
Expand All @@ -15,6 +16,12 @@
using Microsoft.Maui.Hosting;
using Microsoft.Maui.LifecycleEvents;
using Woka;
using Anikin.Views.Home;
using Anikin.ViewModels.Manga;
using Anikin.Views.Manga;



#if ANDROID
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
#endif
Expand Down Expand Up @@ -108,19 +115,27 @@ public static MauiApp CreateMauiApp()

// Views
builder.Services.AddTransient<HomeView>();
builder.Services.AddTransient<SearchView>();
builder.Services.AddTransient<MangaSearchView>();
builder.Services.AddTransient<AnimeTabView>();
builder.Services.AddTransient<EpisodePage>();
builder.Services.AddTransient<MangaPage>();
builder.Services.AddTransient<MangaReaderPage>();
builder.Services.AddTransient<ProfileTabView>();
builder.Services.AddTransient<SearchView>();
builder.Services.AddTransient<ExtensionsView>();
builder.Services.AddTransient<EpisodePage>();
builder.Services.AddTransient<AnilistLoginView>();

// ViewModels
builder.Services.AddTransient<HomeViewModel>();
builder.Services.AddTransient<ProfileViewModel>();
builder.Services.AddTransient<SearchViewModel>();
builder.Services.AddTransient<ExtensionsViewModel>();
builder.Services.AddTransient<MangaSearchViewModel>();
builder.Services.AddTransient<AnimeHomeViewModel>();
builder.Services.AddTransient<EpisodeViewModel>();
builder.Services.AddTransient<MangaHomeViewModel>();
builder.Services.AddTransient<MangaItemViewModel>();
builder.Services.AddTransient<MangaReaderViewModel>();
builder.Services.AddTransient<ProfileViewModel>();
builder.Services.AddTransient<ExtensionsViewModel>();

// Services
builder.Services.AddTransient(x => AniClientFactory());
Expand Down
8 changes: 8 additions & 0 deletions Anikin/Models/HomeTabs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Anikin.Models;

public enum HomeTabs
{
Anime,
Profile,
Manga
}
23 changes: 23 additions & 0 deletions Anikin/Models/Manga/MangaChapterRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using CommunityToolkit.Mvvm.ComponentModel;
using Juro.Core.Models.Manga;

namespace Anikin.Models.Manga;

public partial class MangaChapterRange : ObservableObject
{
public string Name { get; set; } = default!;

public List<IMangaChapter> Chapters { get; set; } = [];

[ObservableProperty]
private bool _isSelected;

public MangaChapterRange(IEnumerable<IMangaChapter> episodes, int startIndex, int endIndex)
{
Chapters.AddRange(episodes);
Name = $"{startIndex} - {endIndex}";
}

public override string ToString() => Name;
}
36 changes: 36 additions & 0 deletions Anikin/Models/Manga/MangaHomeRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using Anikin.Utils;
using Anikin.Utils.Extensions;
using CommunityToolkit.Mvvm.ComponentModel;
using Jita.AniList.Models;

namespace Anikin.Models.Manga;

public partial class MangaHomeRange : ObservableObject
{
public string Name { get; set; }

[ObservableProperty]
bool _isLoading;

public MangaHomeTypes Type { get; set; }

public ObservableRangeCollection<Media> Medias { get; set; } = [];

[ObservableProperty]
private bool _isSelected;

public MangaHomeRange(MangaHomeTypes type)
{
Type = type;
Name = Type.GetBestDisplayName();
}

public MangaHomeRange(MangaHomeTypes type, IEnumerable<Media> medias)
: this(type)
{
Medias.AddRange(medias);
}

public override string ToString() => Name;
}
Loading

0 comments on commit 1903024

Please sign in to comment.