diff --git a/BookReader/Resources/Raw/wwwroot/index.html b/BookReader/Resources/Raw/wwwroot/index.html index 4f76275..59471ff 100644 --- a/BookReader/Resources/Raw/wwwroot/index.html +++ b/BookReader/Resources/Raw/wwwroot/index.html @@ -154,6 +154,7 @@ isBookLoaded: false, fb2CurrentPage: 0, fb2TotalPages: 1, + toc: [] }; // ========== УТИЛИТЫ ========== @@ -287,16 +288,17 @@ try { const toc = state.book.navigation.toc || []; - const chapters = toc.map(ch => ({ + state.toc = toc.map(ch => ({ label: (ch.label || '').trim(), href: ch.href || '' })); - sendMessage('chaptersLoaded', { chapters }); + sendMessage('chaptersLoaded', { chapters: state.toc }); } catch (e) { debugLog('TOC error: ' + e.message); } + const charsPerScreen = Math.max(600, Math.floor((window.innerWidth * window.innerHeight) / 400)); - return state.book.locations.generate(1600); + return state.book.locations.generate(charsPerScreen); }) .then(() => { state.totalPages = state.book.locations.length(); @@ -309,13 +311,29 @@ state.rendition.on('relocated', location => { if (!location || !location.start) return; state.currentCfi = location.start.cfi; + // 1. Достаем страницы ВНУТРИ главы + // Если epub.js не успел посчитать (бывает на долю секунды), ставим 1 + const chapterPage = location.start.displayed ? location.start.displayed.page : 1; + const chapterTotal = location.start.displayed ? location.start.displayed.total : 1; + + // 2. Ищем красивое название главы по её href + const currentHref = location.start.href || ''; + let chapterName = currentHref; // По умолчанию системное имя + + // Пытаемся найти точное совпадение в сохраненном оглавлении + const foundChapter = state.toc.find(ch => currentHref.includes(ch.href)); + if (foundChapter) { + chapterName = foundChapter.label; + } try { sendMessage('progressUpdate', { progress: state.book.locations.percentageFromCfi(state.currentCfi) || 0, cfi: state.currentCfi, - currentPage: location.start.location || 0, - totalPages: state.totalPages, - chapter: location.start.href || '' + currentPage: location.start.location || 0, // Глобальная страница + totalPages: state.totalPages, // Всего глобальных страниц + chapterCurrentPage: chapterPage, // <--- Страница в главе! + chapterTotalPages: chapterTotal, // <--- Всего страниц в главе! + chapter: chapterName // <--- Красивое имя главы }); } catch (e) { debugLog('Relocated error: ' + e.message); diff --git a/BookReader/ViewModels/ReaderViewModel.cs b/BookReader/ViewModels/ReaderViewModel.cs index 079d078..899a319 100644 --- a/BookReader/ViewModels/ReaderViewModel.cs +++ b/BookReader/ViewModels/ReaderViewModel.cs @@ -33,6 +33,19 @@ public partial class ReaderViewModel : BaseViewModel [ObservableProperty] private string? _selectedChapter; + [ObservableProperty] + private int _chapterCurrentPage = 1; + + [ObservableProperty] + private int _chapterTotalPages = 1; + + // Это свойство будет обновляться автоматически при изменении любого из полей выше + public string ChapterProgressText => $"{ChapterCurrentPage} из {ChapterTotalPages}"; + + // Чтобы ChapterProgressText уведомлял интерфейс, добавим частичные методы (особенность Toolkit) + partial void OnChapterCurrentPageChanged(int value) => OnPropertyChanged(nameof(ChapterProgressText)); + partial void OnChapterTotalPagesChanged(int value) => OnPropertyChanged(nameof(ChapterProgressText)); + public List AvailableFonts { get; } = new() { "serif", diff --git a/BookReader/Views/ReaderPage.xaml b/BookReader/Views/ReaderPage.xaml index 0c0651c..7d16e3b 100644 --- a/BookReader/Views/ReaderPage.xaml +++ b/BookReader/Views/ReaderPage.xaml @@ -20,6 +20,21 @@ DefaultFile="index.html" HorizontalOptions="Fill" VerticalOptions="Fill" /> + + + - //{ - // if (_isActive) await SaveCurrentProgress(); - //}; } protected override async void OnAppearing() @@ -207,6 +203,15 @@ public partial class ReaderPage : ContentPage var chapter = data["chapter"]?.ToString(); var currentPage = data["currentPage"]?.Value() ?? 0; var totalPages = data["totalPages"]?.Value() ?? 0; + + // Ловим новые данные по главе + var chapterPage = data["chapterCurrentPage"]?.Value() ?? 1; + var chapterTotal = data["chapterTotalPages"]?.Value() ?? 1; + // Обновляем ViewModel на главном потоке + MainThread.BeginInvokeOnMainThread(() => { + _viewModel.ChapterCurrentPage = chapterPage; + _viewModel.ChapterTotalPages = chapterTotal; + }); await _viewModel.SaveProgressAsync(progress, cfi, chapter, currentPage, totalPages); } break;