diff --git a/Bible.App/MainPage.xaml b/Bible.App/MainPage.xaml index 82ff626..0dc665c 100644 --- a/Bible.App/MainPage.xaml +++ b/Bible.App/MainPage.xaml @@ -21,23 +21,23 @@ - - - - + SelectedIndexChanged="OnBookSelectionChanged" + WidthRequest="160" /> - - - - + SelectedIndexChanged="OnChapterSelectionChanged" + WidthRequest="70" /> + + ItemsSource="{Binding Source={x:Reference bibleBookPicker}, Path=SelectedItem, Mode=OneWay}" + Scrolled="OnCollectionViewScrolled"> + + + + - + @@ -69,7 +75,8 @@ + + + + diff --git a/Bible.App/MainPage.xaml.cs b/Bible.App/MainPage.xaml.cs index b982577..2d60cab 100644 --- a/Bible.App/MainPage.xaml.cs +++ b/Bible.App/MainPage.xaml.cs @@ -1,4 +1,5 @@ -using BibleApp.ViewModels; +using BibleApp.Models; +using BibleApp.ViewModels; using CommunityToolkit.Mvvm.DependencyInjection; namespace BibleApp @@ -20,9 +21,32 @@ protected override void OnAppearing() bibleChapterPicker.Focus(); } + private void OnBookSelectionChanged(object sender, EventArgs e) + { + _viewModel.ChapterIndex = 0; + } + + private void OnChapterSelectionChanged(object sender, EventArgs e) + { + if (sender is Picker picker && picker.SelectedItem is ChapterUiModel chapter && chapter.Id > 0 && _viewModel.ChapterIndex >= 0) + collectionView.ScrollTo(0, chapter.Id - 1, position: ScrollToPosition.Start, animate: true); + } + + private void OnVerseSelectionChanged(object sender, EventArgs e) + { + if (sender is Picker picker && picker.SelectedItem is VerseUiModel verse) + collectionView.ScrollTo(verse.Id - 1, _viewModel.ChapterIndex, position: ScrollToPosition.Center, animate: true); + } + + private void OnCollectionViewScrolled(object sender, ItemsViewScrolledEventArgs e) + { + if (e.FirstVisibleItemIndex != 0) + _viewModel.ChapterIndex = -1; + } + private void OnSwipeLeft(object sender, SwipedEventArgs e) { - if (_viewModel.SelectedBook?.Count > bibleChapterPicker.SelectedIndex + 1) + if (_viewModel.Bible?[_viewModel.BookIndex]?.Count > bibleChapterPicker.SelectedIndex + 1) bibleChapterPicker.SelectedIndex++; } diff --git a/Bible.App/Models/BibleUiModel.cs b/Bible.App/Models/BibleUiModel.cs index 4b453d9..83bbaf2 100644 --- a/Bible.App/Models/BibleUiModel.cs +++ b/Bible.App/Models/BibleUiModel.cs @@ -1,21 +1,20 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using System.Collections.ObjectModel; - namespace BibleApp.Models { - public sealed partial class BibleUiModel : ObservableObject + public sealed partial class BibleUiModel : List { - //[ObservableProperty] - //private string translation = default!; - - //[ObservableProperty] - //private IList books = new List(); + public string Translation { get; } = default!; - public string Translation { get; set; } = default!; + public BibleUiModel(string translation) : base(new List()) + { + Translation = translation; + } - public ObservableCollection Books { get; set; } = new(); + public BibleUiModel(List books, string translation) : base(books) + { + Translation = translation; + } public override string ToString() => - $"Bible: {Translation} ({Books.Count} books)"; + $"Bible: {Translation} ({this.Count} books)"; } } \ No newline at end of file diff --git a/Bible.App/Models/BookUiModel.cs b/Bible.App/Models/BookUiModel.cs index a61ead4..4899e01 100644 --- a/Bible.App/Models/BookUiModel.cs +++ b/Bible.App/Models/BookUiModel.cs @@ -1,46 +1,33 @@ +using Bible.Reader.Models; using CommunityToolkit.Mvvm.ComponentModel; using System.Collections.ObjectModel; namespace BibleApp.Models { - public sealed partial class BookUiModel : ObservableObject + [ObservableObject] + public sealed partial class BookUiModel : List { - //[ObservableProperty] - //private int id; + public int Id { get; } - //[ObservableProperty] - //private string name = default!; + public string Name { get; } = default!; - //[ObservableProperty] - //private IList chapters = new List(); + public ObservableCollection ChapterNumbers { get; } - public int Id { get; set; } - - public string Name { get; set; } = default!; - - public ObservableCollection Chapters { get; set; } = new(); - - - private int _chapterCount = 1; - public int ChapterCount + public BookUiModel(int id, string name, int chapterCount) : base(new List()) { - get => _chapterCount; - init - { - if (SetProperty(ref _chapterCount, value)) - { - _chapterNumbers = new(ParallelEnumerable.Range(1, _chapterCount)); - OnPropertyChanged(nameof(ChapterNumbers)); - } - } + Id = id; + Name = name; + ChapterNumbers = new(Enumerable.Range(1, chapterCount)); } - Lazy>? _chapterNumbers; - - public ObservableCollection ChapterNumbers => - new(_chapterNumbers?.Value ?? [1]); - + public BookUiModel(List chapters, int id, string name) : base(chapters) + { + Id = id; + Name = name; + ChapterNumbers = new(Enumerable.Range(1, chapters.Count)); + } + public override string ToString() => - $"Book #{Id}, {Name} ({ChapterCount} chapters)"; + $"Book #{Id}, {Name} ({this.Count} chapters)"; } } \ No newline at end of file diff --git a/Bible.App/Models/ChapterUiModel.cs b/Bible.App/Models/ChapterUiModel.cs index 2ad92d5..3818f5c 100644 --- a/Bible.App/Models/ChapterUiModel.cs +++ b/Bible.App/Models/ChapterUiModel.cs @@ -1,21 +1,22 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using System.Collections.ObjectModel; - namespace BibleApp.Models { - public sealed partial class ChapterUiModel : ObservableObject + public sealed partial class ChapterUiModel : List { - //[ObservableProperty] - //private int id; + public int Id { get; } - //[ObservableProperty] - //private IList verses = new List(); + public string? Copyright { get; set; } - public int Id { get; set; } + public ChapterUiModel(int id) : base(new List()) + { + Id = id; + } - public ObservableCollection Verses { get; set; } = new(); + public ChapterUiModel(List verses, int id) : base(verses) + { + Id = id; + } public override string ToString() => - $"Chapter {Id} ({Verses.Count} verses)"; + $"Chapter {Id} ({this.Count} verses)"; } } \ No newline at end of file diff --git a/Bible.App/Models/VerseUiModel.cs b/Bible.App/Models/VerseUiModel.cs index ef90906..d7370c4 100644 --- a/Bible.App/Models/VerseUiModel.cs +++ b/Bible.App/Models/VerseUiModel.cs @@ -1,21 +1,16 @@ -using CommunityToolkit.Mvvm.ComponentModel; - namespace BibleApp.Models { - public sealed partial class VerseUiModel : ObservableObject + public sealed partial class VerseUiModel { - //[ObservableProperty] - //private bool isSelected; - - //[ObservableProperty] - //private int id; - - //[ObservableProperty] - //private string text = default!; + public int Id { get; } - public int Id { get; set; } + public string Text { get; } - public string Text { get; set; } = default!; + public VerseUiModel(int id, string text) + { + Id = id; + Text = text; + } public override string ToString() => $"{Id} {Text}"; diff --git a/Bible.App/Services/BibleUiData.cs b/Bible.App/Services/BibleUiData.cs index 3f4a09d..4cf3446 100644 --- a/Bible.App/Services/BibleUiData.cs +++ b/Bible.App/Services/BibleUiData.cs @@ -15,72 +15,28 @@ public BibleUiModel Load(string fileName, string suffix = ".xml") return GetBible(_bible, translation); } - public BibleUiModel LoadMock(BibleModel bible, string translation) - { - var bibleModel = new BibleUiModel() { Translation = translation }; - if (bible != null) - { - foreach (var book in bible.Books) - { - var bibleBook = new BookUiModel - { - Id = book.Id, - Name = book.Reference.BookName, - ChapterCount = book.ChapterCount - }; - bibleModel.Books.Add(bibleBook); - } - } - return bibleModel; - } - - private static ChapterUiModel GetChapter(BibleModel? bible, byte bookIndex, byte chapterIndex) - { - var bibleChapter = new ChapterUiModel { Id = chapterIndex + 1 }; - if (bible != null) - { - foreach (var verse in bible.Books[bookIndex].Chapters[chapterIndex].Verses) - { - var bibleVerse = new VerseUiModel { Id = verse.Id, Text = verse.Text }; - bibleChapter.Verses.Add(bibleVerse); - } - } - return bibleChapter; - } - - public static ChapterUiModel? GetChapter(BibleUiModel? bible, byte bookIndex, byte chapterIndex) => - bible?.Books[bookIndex].Chapters[chapterIndex]; - - public ChapterUiModel? GetChapter(byte bookIndex, byte chapterIndex) => - GetChapter(_bible, bookIndex, chapterIndex); - public static BibleUiModel GetBible(BibleModel? bible, string translation, bool addChapters = true) { - var bibleModel = new BibleUiModel() { Translation = translation }; + var bibleModel = new BibleUiModel(translation); if (bible != null) { foreach (var book in bible.Books) { - var bibleBook = new BookUiModel - { - Id = book.Id, - Name = book.Reference.BookName, - ChapterCount = book.ChapterCount - }; + var bibleBook = new BookUiModel(book.Id, book.Reference.BookName, book.ChapterCount); if (addChapters) { foreach (var chapter in book.Chapters) { - var bibleChapter = new ChapterUiModel { Id = chapter.Id }; + var bibleChapter = new ChapterUiModel(chapter.Id) { Copyright = translation }; foreach (var verse in chapter.Verses) { - var bibleVerse = new VerseUiModel { Id = verse.Id, Text = verse.Text }; - bibleChapter.Verses.Add(bibleVerse); + var bibleVerse = new VerseUiModel(verse.Id, verse.Text); + bibleChapter.Add(bibleVerse); } - bibleBook.Chapters.Add(bibleChapter); + bibleBook.Add(bibleChapter); } } - bibleModel.Books.Add(bibleBook); + bibleModel.Add(bibleBook); } } return bibleModel; diff --git a/Bible.App/Services/TestUiData.cs b/Bible.App/Services/TestUiData.cs index 10389aa..648e765 100644 --- a/Bible.App/Services/TestUiData.cs +++ b/Bible.App/Services/TestUiData.cs @@ -1,41 +1,35 @@ using Bible.Interfaces; using BibleApp.Models; -using System.Collections.ObjectModel; namespace Bible.Reader.Services { public sealed class TestUiData : IDataService { public BibleUiModel Load(string fileName, string suffix = ".xml") => - LoadMock(66, suffix.Length * 3, fileName.Length * 3); + LoadTest(66, suffix.Length * 3, fileName.Length * 3); - public BibleUiModel LoadMock(int bookCount, int chapterCount, int verseCount, string name = "Books, Chapters, and Verses") + public BibleUiModel LoadTest(int bookCount, int chapterCount, int verseCount, string name = "Books, Chapters, and Verses") { - var books = Enumerable.Range(1, bookCount); //ParallelEnumerable + var books = Enumerable.Range(1, bookCount); var chapters = Enumerable.Range(1, chapterCount); var verses = Enumerable.Range(1, verseCount); - var bible = new BibleUiModel + + var bible = new BibleUiModel(name); + foreach (var bookId in books) { - Translation = name, - Books = new ObservableCollection(books.Select(b => - new BookUiModel + var bibleBook = new BookUiModel(bookId, $"Book #{bookId}", chapterCount); + foreach (var chapterId in chapters) + { + var bibleChapter = new ChapterUiModel(chapterId); + foreach (var verseId in verses) { - Id = b, - Name = $"Book #{b}", - ChapterCount = chapterCount, - Chapters = new ObservableCollection(chapters.Select(c => - new ChapterUiModel - { - Id = c, - Verses = new ObservableCollection(verses.Select(v => - new VerseUiModel - { - Id = v, - Text = $"Book #{b}, Chapter #{c}, Verse #{v}." - }).ToArray()) - }).ToArray()) - }).ToArray()) - }; + var bibleVerse = new VerseUiModel(verseId, $"Book #{bookId}, Chapter #{chapterId}, Verse #{verseId}."); + bibleChapter.Add(bibleVerse); + } + bibleBook.Add(bibleChapter); + } + bible.Add(bibleBook); + } return bible; } } diff --git a/Bible.App/ViewModels/MainPageViewModel.cs b/Bible.App/ViewModels/MainPageViewModel.cs index 097297f..a17a43b 100644 --- a/Bible.App/ViewModels/MainPageViewModel.cs +++ b/Bible.App/ViewModels/MainPageViewModel.cs @@ -1,5 +1,4 @@ using Bible.Interfaces; -using Bible.Reader.Services; using BibleApp.Models; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -12,12 +11,6 @@ public sealed partial class MainPageViewModel : ObservableObject [ObservableProperty] private BibleUiModel? bible; - [ObservableProperty] - private BookUiModel? selectedBook; - - [ObservableProperty] - private ChapterUiModel? selectedChapter; - private const string _testUsxBook = "zho/OCCB/GEN"; public ObservableCollection Translations { get; } = [ @@ -38,9 +31,6 @@ public sealed partial class MainPageViewModel : ObservableObject [ObservableProperty] private int chapterIndex = -1; - private byte _bookIndexChecked => BookIndex < byte.MinValue ? byte.MinValue : (byte)BookIndex; - private byte _chapterIndexChecked => ChapterIndex < byte.MinValue ? byte.MinValue : (byte)ChapterIndex; - private readonly IDataService _readerService; public MainPageViewModel(IDataService readerService) @@ -54,22 +44,5 @@ private void TranslationSelected(object? value) Bible = _readerService.Load(Translations[TranslationIndex]); BookIndex = 0; } - - [RelayCommand] - private void BookSelected(object? value) - { - ChapterIndex = 0; - } - - [RelayCommand] - private void ChapterSelected(object? value) - { - SelectedChapter = Bible?.Books[_bookIndexChecked].Chapters[_chapterIndexChecked]; - } - - internal ChapterUiModel? Chapter => - _readerService is BibleUiData reader ? - reader.GetChapter(_bookIndexChecked, _chapterIndexChecked) : - Bible?.Books[_bookIndexChecked].Chapters[_chapterIndexChecked]; } } \ No newline at end of file