diff --git a/Domain/AnnotationsService/Sources/QuranHighlightsService.swift b/Domain/AnnotationsService/Sources/QuranHighlightsService.swift new file mode 100644 index 00000000..5aa9493b --- /dev/null +++ b/Domain/AnnotationsService/Sources/QuranHighlightsService.swift @@ -0,0 +1,28 @@ +// +// QuranHighlightsService.swift +// +// +// Created by Mohamed Afifi on 2023-12-23. +// + +import Combine +import QuranAnnotations +import VLogging + +public final class QuranHighlightsService { + // MARK: Lifecycle + + public init() { } + + // MARK: Public + + @Published public var highlights = QuranHighlights() { + didSet { + logger.info("Highlights updated") + } + } + + public func reset() { + highlights = QuranHighlights() + } +} diff --git a/Features/QuranContentFeature/ContentBuilder.swift b/Features/QuranContentFeature/ContentBuilder.swift index 16ead39e..2d68cd80 100644 --- a/Features/QuranContentFeature/ContentBuilder.swift +++ b/Features/QuranContentFeature/ContentBuilder.swift @@ -17,8 +17,9 @@ import UIKit public struct ContentBuilder { // MARK: Lifecycle - public init(container: AppDependencies) { + public init(container: AppDependencies, highlightsService: QuranHighlightsService) { self.container = container + self.highlightsService = highlightsService } // MARK: Public @@ -33,8 +34,9 @@ public struct ContentBuilder { noteService: noteService, lastPageUpdater: lastPageUpdater, quran: quran, - imageDataSourceBuilder: ContentImageBuilder(container: container), - translationDataSourceBuilder: ContentTranslationBuilder(container: container) + highlightsService: highlightsService, + imageDataSourceBuilder: ContentImageBuilder(container: container, highlightsService: highlightsService), + translationDataSourceBuilder: ContentTranslationBuilder(container: container, highlightsService: highlightsService) ) let viewModel = ContentViewModel(deps: interactorDeps, input: input) @@ -47,4 +49,5 @@ public struct ContentBuilder { // MARK: Private private let container: AppDependencies + private let highlightsService: QuranHighlightsService } diff --git a/Features/QuranContentFeature/ContentViewController.swift b/Features/QuranContentFeature/ContentViewController.swift index 7ad324e2..c01f25f4 100644 --- a/Features/QuranContentFeature/ContentViewController.swift +++ b/Features/QuranContentFeature/ContentViewController.swift @@ -50,7 +50,7 @@ final class ContentViewController: UIViewController, UIGestureRecognizerDelegate setUpPagingStrategyChanges() setUpDataSourceChanges() setUpBackgroundListener() - setUpQuranUITraitsListener() + setUpHighlightsListener() } func gestureRecognizer( @@ -84,26 +84,29 @@ final class ContentViewController: UIViewController, UIGestureRecognizerDelegate private var pageController: PageController? private let viewModel: ContentViewModel private var cancellables: Set = [] + private var lastHighlights: QuranHighlights? // MARK: - Scrolling - private func setUpQuranUITraitsListener() { - viewModel.$quranUITraits + private func setUpHighlightsListener() { + viewModel.deps.highlightsService.$highlights .receive(on: DispatchQueue.main) - .sink { [weak self] newTraits in - self?.quranUITraitsUpdatedTo(newTraits) + .sink { [weak self] newHighlights in + self?.highlightsUpdatedTo(newHighlights) } .store(in: &cancellables) } - private func quranUITraitsUpdatedTo(_ quranUITraits: QuranUITraits) { - guard let dataSource = viewModel.dataSource else { + private func highlightsUpdatedTo(_ highlights: QuranHighlights) { + defer { + lastHighlights = highlights + } + + guard let oldValue = lastHighlights else { return } - let oldValue = dataSource.quranUITraits - dataSource.quranUITraits = quranUITraits - if let ayah = quranUITraits.highlights.verseToScrollTo(comparingTo: oldValue.highlights) { + if let ayah = highlights.verseToScrollTo(comparingTo: oldValue) { scrollTo(page: ayah.page, animated: true, forceReload: false) } } @@ -179,7 +182,7 @@ final class ContentViewController: UIViewController, UIGestureRecognizerDelegate dataSource.scrollToPage(viewModel.lastViewedPage, animated: false, forceReload: true) viewModel.visiblePagesLoaded() - quranUITraitsUpdatedTo(viewModel.quranUITraits) + highlightsUpdatedTo(viewModel.deps.highlightsService.highlights) } // MARK: - Gestures diff --git a/Features/QuranContentFeature/ContentViewModel.swift b/Features/QuranContentFeature/ContentViewModel.swift index 31a48477..43b7688e 100644 --- a/Features/QuranContentFeature/ContentViewModel.swift +++ b/Features/QuranContentFeature/ContentViewModel.swift @@ -38,6 +38,8 @@ public final class ContentViewModel { let lastPageUpdater: LastPageUpdater let quran: Quran + let highlightsService: QuranHighlightsService + let imageDataSourceBuilder: PageDataSourceBuilder let translationDataSourceBuilder: PageDataSourceBuilder } @@ -61,21 +63,12 @@ public final class ContentViewModel { twoPagesEnabled = deps.quranContentStatePreferences.twoPagesEnabled verticalScrollingEnabled = deps.quranContentStatePreferences.verticalScrollingEnabled - quranUITraits.translationFontSize = deps.fontSizePreferences.translationFontSize - quranUITraits.arabicFontSize = deps.fontSizePreferences.arabicFontSize - deps.quranContentStatePreferences.$twoPagesEnabled .sink { [weak self] in self?.twoPagesEnabled = $0 } .store(in: &cancellables) deps.quranContentStatePreferences.$verticalScrollingEnabled .sink { [weak self] in self?.verticalScrollingEnabled = $0 } .store(in: &cancellables) - deps.fontSizePreferences.$arabicFontSize - .sink { [weak self] in self?.quranUITraits.arabicFontSize = $0 } - .store(in: &cancellables) - deps.fontSizePreferences.$translationFontSize - .sink { [weak self] in self?.quranUITraits.translationFontSize = $0 } - .store(in: &cancellables) deps.quranContentStatePreferences.$quranMode .sink { [weak self] _ in self?.loadNewElementModule() } .store(in: &cancellables) @@ -89,8 +82,6 @@ public final class ContentViewModel { // MARK: Public - @Published public private(set) var quranUITraits = QuranUITraits() - public var visiblePages: [Page] { dataSource?.visiblePages ?? [] } public func removeAyahMenuHighlight() { @@ -103,7 +94,7 @@ public final class ContentViewModel { } public func highlightWord(_ word: Word?) { - quranUITraits.highlights.pointedWord = word + deps.highlightsService.highlights.pointedWord = word } public func word(at point: CGPoint, in view: UIView) -> Word? { @@ -111,7 +102,7 @@ public final class ContentViewModel { } public func highlightReadingAyah(_ ayah: AyahNumber?) { - quranUITraits.highlights.readingVerses = [ayah].compactMap { $0 } + deps.highlightsService.highlights.readingVerses = [ayah].compactMap { $0 } } // MARK: Internal @@ -121,6 +112,8 @@ public final class ContentViewModel { @Published var twoPagesEnabled: Bool @Published var dataSource: PageDataSource? + let deps: Deps + var verticalScrollingEnabled: Bool { didSet { loadNewElementModule() } } @@ -154,7 +147,7 @@ public final class ContentViewModel { func visiblePagesUpdated() { // remove search highlight when page changes - quranUITraits.highlights.searchVerses = [] + deps.highlightsService.highlights.searchVerses = [] visiblePagesLoaded() } @@ -205,13 +198,12 @@ public final class ContentViewModel { private var cancellables: Set = [] - private let deps: Deps private let input: QuranInput private var pages: [Page] private var longPressData: LongPressData? { didSet { - quranUITraits.highlights.shareVerses = selectedVerses ?? [] + deps.highlightsService.highlights.shareVerses = selectedVerses ?? [] } } @@ -247,7 +239,7 @@ public final class ContentViewModel { private func configureAsInitialPage() { deps.lastPageUpdater.configure(initialPage: input.initialPage, lastPage: input.lastPage) loadNewElementModule() - quranUITraits.highlights.searchVerses = [input.highlightingSearchAyah].compactMap { $0 } + deps.highlightsService.highlights.searchVerses = [input.highlightingSearchAyah].compactMap { $0 } } private func loadNewElementModule() { @@ -267,7 +259,7 @@ public final class ContentViewModel { deps.noteService.notes(quran: deps.quran) .map { notes in notes.flatMap { note in note.verses.map { ($0, note) } } } .receive(on: DispatchQueue.main) - .sink { [weak self] in self?.quranUITraits.highlights.noteVerses = Self.dictionaryFrom($0) } + .sink { [weak self] in self?.deps.highlightsService.highlights.noteVerses = Self.dictionaryFrom($0) } .store(in: &cancellables) } } diff --git a/Features/QuranImageFeature/ContentImageBuilder.swift b/Features/QuranImageFeature/ContentImageBuilder.swift index 37253cd5..4e3b35b5 100644 --- a/Features/QuranImageFeature/ContentImageBuilder.swift +++ b/Features/QuranImageFeature/ContentImageBuilder.swift @@ -6,6 +6,7 @@ // Copyright © 2019 Quran.com. All rights reserved. // +import AnnotationsService import AppDependencies import Caching import Foundation @@ -23,8 +24,9 @@ import VLogging public struct ContentImageBuilder: PageDataSourceBuilder { // MARK: Lifecycle - public init(container: AppDependencies) { + public init(container: AppDependencies, highlightsService: QuranHighlightsService) { self.container = container + self.highlightsService = highlightsService } // MARK: Public @@ -45,7 +47,8 @@ public struct ContentImageBuilder: PageDataSourceBuilder { let controller = ContentImageViewController( page: page, dataService: cacheableImageService, - pageMarkerService: cacheablePageMarkers + pageMarkerService: cacheablePageMarkers, + highlightsService: highlightsService ) return controller } @@ -54,6 +57,7 @@ public struct ContentImageBuilder: PageDataSourceBuilder { // MARK: Private private let container: AppDependencies + private let highlightsService: QuranHighlightsService private func readingDirectory(_ reading: Reading) -> URL { let remoteResource = container.remoteResources?.resource(for: reading) diff --git a/Features/QuranImageFeature/ContentImageView.swift b/Features/QuranImageFeature/ContentImageView.swift index 1b57b39e..c7fab099 100644 --- a/Features/QuranImageFeature/ContentImageView.swift +++ b/Features/QuranImageFeature/ContentImageView.swift @@ -6,6 +6,8 @@ // Copyright © 2019 Quran.com. All rights reserved. // +import AnnotationsService +import Combine import ImageService import Localization import NoorUI @@ -19,21 +21,13 @@ import VLogging class ContentImageView: UIView { // MARK: Lifecycle - init() { + init(highlightsService: QuranHighlightsService) { + self.highlightsService = highlightsService imageView = ContentImageContentView(topView: topView, bottomView: bottomView, fullWindowView: true) super.init(frame: .zero) - addAutoLayoutSubview(imageView) - imageView.vc.edges() - - setupTopView(topView) - setupBottomView(bottomView) - - for label in [juzLabel, suraLabel, pageLabel] { - label.font = UIFont.systemFont(ofSize: 14) - label.textColor = .label - } - pageLabel.textAlignment = .center + setUpViews() + setUpHighlights() } @available(*, unavailable) @@ -43,20 +37,6 @@ class ContentImageView: UIView { // MARK: Internal - // MARK: - PageView - - var quranUITraits = QuranUITraits() { - didSet { - logger.info("Quran Image: quranUITraits changed") - - highlightingView.highlights = quranUITraits.highlights - - if quranUITraits.highlights.needsScrolling(comparingTo: oldValue.highlights) { - scrollToVerseIfNeeded() - } - } - } - var page: Page? { didSet { imageView.image = nil @@ -103,6 +83,9 @@ class ContentImageView: UIView { private let suraLabel = UILabel() private let pageLabel = UILabel() + private let highlightsService: QuranHighlightsService + private var cancellables: Set = [] + private var highlightingView: QuranImageHighlightingView { imageView.highlightingView } @@ -111,6 +94,36 @@ class ContentImageView: UIView { imageView.plainView.scrollView } + private func setUpViews() { + addAutoLayoutSubview(imageView) + imageView.vc.edges() + + setupTopView(topView) + setupBottomView(bottomView) + + for label in [juzLabel, suraLabel, pageLabel] { + label.font = UIFont.systemFont(ofSize: 14) + label.textColor = .label + } + pageLabel.textAlignment = .center + } + + private func setUpHighlights() { + highlightsService.$highlights + .zip(highlightsService.$highlights.dropFirst()) + .sink { [weak self] oldValue, newValue in + if newValue.needsScrolling(comparingTo: oldValue) { + self?.scrollToVerseIfNeeded() + } + } + .store(in: &cancellables) + + highlightsService.$highlights + .print("Afifi: Highlights") + .sink { [weak self] in self?.highlightingView.highlights = $0 } + .store(in: &cancellables) + } + private func setupTopView(_ topView: UIView) { topView.addAutoLayoutSubview(juzLabel) juzLabel.vc.verticalEdges() @@ -131,7 +144,7 @@ class ContentImageView: UIView { } private func scrollToVerseIfNeededSynchronously() { - guard let ayah = quranUITraits.highlights.firstScrollingVerse() else { + guard let ayah = highlightsService.highlights.firstScrollingVerse() else { return } diff --git a/Features/QuranImageFeature/ContentImageViewController.swift b/Features/QuranImageFeature/ContentImageViewController.swift index 85c8b512..9759d6da 100644 --- a/Features/QuranImageFeature/ContentImageViewController.swift +++ b/Features/QuranImageFeature/ContentImageViewController.swift @@ -6,10 +6,10 @@ // Copyright © 2020 Quran.com. All rights reserved. // +import AnnotationsService import Caching import Crashing import ImageService -import QuranAnnotations import QuranGeometry import QuranKit import QuranPagesFeature @@ -21,8 +21,10 @@ class ContentImageViewController: UIViewController, PageView { init( page: Page, dataService: PagesCacheableService, - pageMarkerService: PagesCacheableService? + pageMarkerService: PagesCacheableService?, + highlightsService: QuranHighlightsService ) { + contentView = ContentImageView(highlightsService: highlightsService) self.dataService = dataService self.pageMarkerService = pageMarkerService super.init(nibName: nil, bundle: nil) @@ -40,11 +42,6 @@ class ContentImageViewController: UIViewController, PageView { // MARK: Internal - var quranUITraits: QuranUITraits { - get { contentView.quranUITraits } - set { contentView.quranUITraits = newValue } - } - var page: Page { contentView.page! } @@ -63,7 +60,7 @@ class ContentImageViewController: UIViewController, PageView { // MARK: Private - private let contentView = ContentImageView() + private let contentView: ContentImageView private let dataService: PagesCacheableService private let pageMarkerService: PagesCacheableService? diff --git a/Features/QuranPagesFeature/PageDataSource.swift b/Features/QuranPagesFeature/PageDataSource.swift index 3c36b83b..b41df6f1 100644 --- a/Features/QuranPagesFeature/PageDataSource.swift +++ b/Features/QuranPagesFeature/PageDataSource.swift @@ -6,7 +6,6 @@ // Copyright © 2019 Quran.com. All rights reserved. // -import QuranAnnotations import QuranKit import UIKit import VLogging @@ -20,8 +19,6 @@ public protocol PageDataSourceBuilder { public protocol PageView: UIViewController { var page: Page { get } - var quranUITraits: QuranUITraits { get set } - func word(at point: CGPoint) -> Word? func verse(at point: CGPoint) -> AyahNumber? } @@ -56,12 +53,6 @@ public class PageDataSource { } } - public var quranUITraits: QuranUITraits = QuranUITraits() { - didSet { - loadedViews.forEach { $0.quranUITraits = quranUITraits } - } - } - public var visiblePages: [Page] { pageController?.visibleIndices.map { items[$0] } ?? [] } public func usePageViewController(_ pageController: PageController) { @@ -159,7 +150,6 @@ public class PageDataSource { } else { let view = viewBuilder(page) view.view.backgroundColor = nil - view.quranUITraits = quranUITraits return view } } diff --git a/Features/QuranTranslationFeature/ContentTranslationBuilder.swift b/Features/QuranTranslationFeature/ContentTranslationBuilder.swift index eb3185f1..0ccce04e 100644 --- a/Features/QuranTranslationFeature/ContentTranslationBuilder.swift +++ b/Features/QuranTranslationFeature/ContentTranslationBuilder.swift @@ -6,6 +6,7 @@ // Copyright © 2019 Quran.com. All rights reserved. // +import AnnotationsService import AppDependencies import Caching import Foundation @@ -17,8 +18,9 @@ import Utilities public struct ContentTranslationBuilder: PageDataSourceBuilder { // MARK: Lifecycle - public init(container: AppDependencies) { + public init(container: AppDependencies, highlightsService: QuranHighlightsService) { self.container = container + self.highlightsService = highlightsService } // MARK: Public @@ -26,13 +28,14 @@ public struct ContentTranslationBuilder: PageDataSourceBuilder { public func build(actions: PageDataSourceActions, pages: [Page]) -> PageDataSource { let dataService = createElementLoader(pages: pages) return PageDataSource(actions: actions) { page in - ContentTranslationViewController(dataService: dataService, page: page) + ContentTranslationViewController(dataService: dataService, page: page, highlightsService: highlightsService) } } // MARK: Private private let container: AppDependencies + private let highlightsService: QuranHighlightsService private func createElementLoader(pages: [Page]) -> PagesCacheableService { let cache = Cache() diff --git a/Features/QuranTranslationFeature/ContentTranslationView.swift b/Features/QuranTranslationFeature/ContentTranslationView.swift index 5c312569..2dd89c88 100644 --- a/Features/QuranTranslationFeature/ContentTranslationView.swift +++ b/Features/QuranTranslationFeature/ContentTranslationView.swift @@ -6,6 +6,8 @@ // Copyright © 2019 Quran.com. All rights reserved. // +import AnnotationsService +import Combine import Crashing import NoorUI import QuranAnnotations @@ -19,10 +21,11 @@ import VLogging class ContentTranslationView: UIView { // MARK: Lifecycle - override init(frame: CGRect) { + init(highlightsService: QuranHighlightsService) { + self.highlightsService = highlightsService collectionView = QuranTranslationDiffableDataSource.translationCollectionView() - dataSource = QuranTranslationDiffableDataSource(collectionView: collectionView) - super.init(frame: frame) + dataSource = QuranTranslationDiffableDataSource(collectionView: collectionView, highlightsService: highlightsService) + super.init(frame: .zero) setUp() } @@ -37,19 +40,6 @@ class ContentTranslationView: UIView { // MARK: - PageView - var quranUITraits: QuranUITraits { - get { dataSource.quranUITraits } - set { - logger.info("Quran Translation: set quranUITraits") - let oldTraits = dataSource.quranUITraits - dataSource.quranUITraits = newValue - - if newValue.highlights.needsScrolling(comparingTo: oldTraits.highlights) { - scrollToVerseIfNeeded() - } - } - } - var page: Page? { didSet { logger.info("Quran Translation: set page \(String(describing: page))") @@ -75,13 +65,22 @@ class ContentTranslationView: UIView { // MARK: Private + private let highlightsService: QuranHighlightsService private let dataSource: QuranTranslationDiffableDataSource - private var lastPage: TranslatedPage? + private var cancellable: AnyCancellable? private func setUp() { addAutoLayoutSubview(collectionView) collectionView.vc.edges() + + cancellable = highlightsService.$highlights + .zip(highlightsService.$highlights.dropFirst()) + .sink { [weak self] oldValue, newValue in + if newValue.needsScrolling(comparingTo: oldValue) { + self?.scrollToVerseIfNeeded() + } + } } private func setPageText(_ page: TranslatedPage) { @@ -100,7 +99,7 @@ class ContentTranslationView: UIView { // layout views if needed layoutIfNeeded() - guard let ayah = dataSource.quranUITraits.highlights.firstScrollingVerse() else { + guard let ayah = highlightsService.highlights.firstScrollingVerse() else { return } guard let indexPath = dataSource.firstIndexPath(forAyah: ayah) else { diff --git a/Features/QuranTranslationFeature/ContentTranslationViewController.swift b/Features/QuranTranslationFeature/ContentTranslationViewController.swift index ca4d60eb..6c5e1696 100644 --- a/Features/QuranTranslationFeature/ContentTranslationViewController.swift +++ b/Features/QuranTranslationFeature/ContentTranslationViewController.swift @@ -6,6 +6,7 @@ // Copyright © 2020 Quran.com. All rights reserved. // +import AnnotationsService import Caching import Combine import Crashing @@ -21,8 +22,9 @@ import Utilities class ContentTranslationViewController: UIViewController, PageView { // MARK: Lifecycle - init(dataService: PagesCacheableService, page: Page) { + init(dataService: PagesCacheableService, page: Page, highlightsService: QuranHighlightsService) { self.dataService = dataService + contentView = ContentTranslationView(highlightsService: highlightsService) super.init(nibName: nil, bundle: nil) contentView.page = page reloadData() @@ -39,11 +41,6 @@ class ContentTranslationViewController: UIViewController, PageView { contentView.page! } - var quranUITraits: QuranUITraits { - get { contentView.quranUITraits } - set { contentView.quranUITraits = newValue } - } - override func loadView() { view = contentView } @@ -58,7 +55,7 @@ class ContentTranslationViewController: UIViewController, PageView { // MARK: Private - private let contentView = ContentTranslationView() + private let contentView: ContentTranslationView private let dataService: PagesCacheableService private func reloadData() { diff --git a/Features/QuranTranslationFeature/QuranTranslationDiffableDataSource.swift b/Features/QuranTranslationFeature/QuranTranslationDiffableDataSource.swift index c72c869f..441a1e93 100644 --- a/Features/QuranTranslationFeature/QuranTranslationDiffableDataSource.swift +++ b/Features/QuranTranslationFeature/QuranTranslationDiffableDataSource.swift @@ -6,6 +6,7 @@ // Copyright © 2022 Quran.com. All rights reserved. // +import AnnotationsService import Foundation import GenericDataSources import Localization @@ -51,11 +52,14 @@ public class QuranTranslationDiffableDataSource { // MARK: - Configuration - init(collectionView: UICollectionView) { + init(collectionView: UICollectionView, highlightsService: QuranHighlightsService) { self.collectionView = collectionView + cellProvider = TranslationCellProvider
(collapsedNumberOfLines: 10, highlightsService: highlightsService) dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { [weak self] collectionView, indexPath, itemId in self?.cellProvider.provideCell(collectionView: collectionView, indexPath: indexPath, itemId: itemId) } + cellProvider.dataSource = dataSource + cellProvider.collectionView = collectionView cellProvider.expansionHandler = TranslationExpansionHandler(dataSource: dataSource) } @@ -96,14 +100,6 @@ public class QuranTranslationDiffableDataSource { // MARK: Internal - var quranUITraits: QuranUITraits { - get { cellProvider.quranUITraits } - set { - cellProvider.quranUITraits = newValue - cellProvider.updateQuranUITraits(dataSource: dataSource, collectionView: collectionView) - } - } - var translatedPage: TranslatedPage? { didSet { guard let translatedPage else { @@ -132,7 +128,7 @@ public class QuranTranslationDiffableDataSource { private weak var collectionView: UICollectionView? private var dataSource: UICollectionViewDiffableDataSource! // swiftlint:disable:this implicitly_unwrapped_optional - private let cellProvider = TranslationCellProvider
(collapsedNumberOfLines: 10) + private let cellProvider: TranslationCellProvider
// MARK: - Data diff --git a/Features/QuranTranslationFeature/TranslationCellProvider.swift b/Features/QuranTranslationFeature/TranslationCellProvider.swift index 8435c5bd..fa8ef706 100644 --- a/Features/QuranTranslationFeature/TranslationCellProvider.swift +++ b/Features/QuranTranslationFeature/TranslationCellProvider.swift @@ -6,10 +6,13 @@ // Copyright © 2022 Quran.com. All rights reserved. // +import AnnotationsService +import Combine import Foundation import Localization import QuranAnnotations import QuranText +import QuranTextKit import UIKit @MainActor @@ -19,16 +22,52 @@ public class TranslationCellProvider { // MARK: Lifecycle - public init(collapsedNumberOfLines: UInt = 10) { + public init(collapsedNumberOfLines: UInt, highlightsService: QuranHighlightsService) { self.collapsedNumberOfLines = collapsedNumberOfLines + self.highlightsService = highlightsService + highlights = highlightsService.highlights + translationFontSize = fontSizePreferences.translationFontSize + arabicFontSize = fontSizePreferences.arabicFontSize + + highlightsService.$highlights + .sink { [weak self] in self?.highlights = $0 } + .store(in: &cancellables) + + fontSizePreferences.$translationFontSize + .sink { [weak self] in self?.translationFontSize = $0 } + .store(in: &cancellables) + + fontSizePreferences.$arabicFontSize + .sink { [weak self] in self?.arabicFontSize = $0 } + .store(in: &cancellables) } // MARK: Public + public weak var dataSource: UICollectionViewDiffableDataSource? + public weak var collectionView: UICollectionView? + public var translatedVerses: [TranslatedVerse] = [] - public var quranUITraits: QuranUITraits = QuranUITraits() public var expansionHandler: TranslationExpansionHandler
! + public var highlights: QuranHighlights { + didSet { + reconfigureAllItems() + } + } + + public var translationFontSize: FontSize { + didSet { + reconfigureAllItems() + } + } + + public var arabicFontSize: FontSize { + didSet { + reconfigureAllItems() + } + } + public func provideCell(collectionView: UICollectionView, indexPath: IndexPath, itemId: ItemId) -> UICollectionViewCell { let baseCell: QuranTranslationBaseCollectionViewCell switch itemId { @@ -60,7 +99,9 @@ public class TranslationCellProvider { configure(cell: cell, translationId: translationId) baseCell = cell } - baseCell.quranUITraits = quranUITraits + baseCell.highlights = highlights + baseCell.translationFontSize = translationFontSize + baseCell.arabicFontSize = arabicFontSize return baseCell } @@ -91,10 +132,17 @@ public class TranslationCellProvider { snapshot.appendItems(verseText.arabicSuffix.map { .arabic(verse, text: $0, alignment: .center) }) } - public func updateQuranUITraits( - dataSource: UICollectionViewDiffableDataSource, - collectionView: UICollectionView? - ) { + // MARK: Private + + private let collapsedNumberOfLines: UInt + private let highlightsService: QuranHighlightsService + private let fontSizePreferences = FontSizePreferences.shared + private var cancellables: Set = [] + + private func reconfigureAllItems() { + guard let dataSource else { + return + } if #available(iOS 15.0, *) { var snapshot = dataSource.snapshot() // reconfigure all items @@ -106,12 +154,6 @@ public class TranslationCellProvider { } } - // MARK: Internal - - let collapsedNumberOfLines: UInt - - // MARK: Private - private func configure(cell: QuranTranslationTextCollectionViewCell, translationId: TranslationId) { let verse = translatedVerses.first { $0.verse == translationId.verse }! let translationIndex = verse.translations.translations.firstIndex(of: translationId.translation)! diff --git a/Features/QuranTranslationFeature/cells/QuranTranslationArabicTextCollectionViewCell.swift b/Features/QuranTranslationFeature/cells/QuranTranslationArabicTextCollectionViewCell.swift index a1fa8f73..02f811f8 100644 --- a/Features/QuranTranslationFeature/cells/QuranTranslationArabicTextCollectionViewCell.swift +++ b/Features/QuranTranslationFeature/cells/QuranTranslationArabicTextCollectionViewCell.swift @@ -38,7 +38,7 @@ class QuranTranslationArabicTextCollectionViewCell: QuranTranslationItemCollecti override func configure(with item: (text: String, alignment: NSTextAlignment)) { super.configure(with: item) label.attributedText = NSAttributedString(string: item.text, attributes: [ - .font: UIFont.arabicQuranText(ofSize: quranUITraits.arabicFontSize), + .font: UIFont.arabicQuranText(ofSize: arabicFontSize), ]) label.textAlignment = item.alignment } diff --git a/Features/QuranTranslationFeature/cells/QuranTranslationBaseCollectionViewCell.swift b/Features/QuranTranslationFeature/cells/QuranTranslationBaseCollectionViewCell.swift index 087c6e00..bd60eecb 100644 --- a/Features/QuranTranslationFeature/cells/QuranTranslationBaseCollectionViewCell.swift +++ b/Features/QuranTranslationFeature/cells/QuranTranslationBaseCollectionViewCell.swift @@ -21,6 +21,7 @@ import NoorUI import QuranAnnotations import QuranKit +import QuranText import UIKit class QuranTranslationBaseCollectionViewCell: UICollectionViewCell { @@ -40,9 +41,12 @@ class QuranTranslationBaseCollectionViewCell: UICollectionViewCell { var ayah: AyahNumber? - var quranUITraits = QuranUITraits() { + var translationFontSize: FontSize = .xSmall + var arabicFontSize: FontSize = .xSmall + + var highlights = QuranHighlights() { didSet { - let versesByHighlights = quranUITraits.highlights.versesByHighlights() + let versesByHighlights = highlights.versesByHighlights() backgroundColor = ayah.flatMap { versesByHighlights[$0] } } } @@ -89,9 +93,19 @@ class QuranTranslationBaseCollectionViewCell: UICollectionViewCell { class QuranTranslationItemCollectionViewCell: QuranTranslationBaseCollectionViewCell { var item: Item? - override var quranUITraits: QuranUITraits { + override var arabicFontSize: FontSize { + didSet { + if arabicFontSize != oldValue { + if let item { + configure(with: item) + } + } + } + } + + override var translationFontSize: FontSize { didSet { - if quranUITraits != oldValue { + if translationFontSize != oldValue { if let item { configure(with: item) } diff --git a/Features/QuranTranslationFeature/cells/QuranTranslationTextCollectionViewCell.swift b/Features/QuranTranslationFeature/cells/QuranTranslationTextCollectionViewCell.swift index fd3ca90b..ab66cee8 100644 --- a/Features/QuranTranslationFeature/cells/QuranTranslationTextCollectionViewCell.swift +++ b/Features/QuranTranslationFeature/cells/QuranTranslationTextCollectionViewCell.swift @@ -101,7 +101,7 @@ class QuranTranslationTextCollectionViewCell: QuranTranslationItemCollectionView shadow.shadowColor = UIColor.label translatorLabel.isHidden = !item.showTranslator - translatorLabel.font = item.translation.preferredTranslatorNameFont(ofSize: quranUITraits.translationFontSize) + translatorLabel.font = item.translation.preferredTranslatorNameFont(ofSize: translationFontSize) translatorLabel.text = item.translation.translationName translationLabel.collapsedNumberOfLines = item.collapsedNumberOfLines @@ -185,11 +185,11 @@ class QuranTranslationTextCollectionViewCell: QuranTranslationItemCollectionView } private func textFont(translation: Translation) -> UIFont { - translation.preferredTextFont(ofSize: quranUITraits.translationFontSize) + translation.preferredTextFont(ofSize: translationFontSize) } private func footerFont(translation: Translation) -> UIFont { - translation.preferredTextFont(ofSize: quranUITraits.translationFontSize, factor: 0.7) + translation.preferredTextFont(ofSize: translationFontSize, factor: 0.7) } private func attributedText( diff --git a/Features/QuranViewFeature/QuranBuilder.swift b/Features/QuranViewFeature/QuranBuilder.swift index 47edb707..ec424aa4 100644 --- a/Features/QuranViewFeature/QuranBuilder.swift +++ b/Features/QuranViewFeature/QuranBuilder.swift @@ -32,6 +32,8 @@ public struct QuranBuilder { // MARK: Public public func build(input: QuranInput) -> UIViewController { + let highlightsService = QuranHighlightsService() + let quran = ReadingPreferences.shared.reading.quran let pageBookmarkService = PageBookmarkService(persistence: container.pageBookmarkPersistence) let interactorDeps = QuranInteractor.Deps( @@ -44,7 +46,7 @@ public struct QuranBuilder { audioBannerBuilder: AudioBannerBuilder(container: container), wordPointerBuilder: WordPointerBuilder(container: container), noteEditorBuilder: NoteEditorBuilder(container: container), - contentBuilder: ContentBuilder(container: container), + contentBuilder: ContentBuilder(container: container, highlightsService: highlightsService), translationsSelectionBuilder: TranslationsListBuilder(container: container), translationVerseBuilder: TranslationVerseBuilder(container: container), resources: container.readingResources diff --git a/Features/QuranViewFeature/QuranInteractor.swift b/Features/QuranViewFeature/QuranInteractor.swift index bc486408..4a28a7c0 100644 --- a/Features/QuranViewFeature/QuranInteractor.swift +++ b/Features/QuranViewFeature/QuranInteractor.swift @@ -218,13 +218,12 @@ final class QuranInteractor: WordPointerListener, ContentListener, NoteEditorLis } func showTranslation(_ verses: [AyahNumber]) { - guard let contentViewModel, let verse = verses.first else { + guard let verse = verses.first else { return } let viewController = deps.translationVerseBuilder.build( startingVerse: verse, - quranUITraits: contentViewModel.quranUITraits, actions: .init(updateCurrentVerseTo: { [weak self] verse in self?.contentViewModel?.highlightTranslationVerse(verse) }) @@ -323,7 +322,6 @@ final class QuranInteractor: WordPointerListener, ContentListener, NoteEditorLis private let readingPreferences = ReadingPreferences.shared private let contentStatePreferences = QuranContentStatePreferences.shared - private let fontSizePreferences = FontSizePreferences.shared private let selectedTranslationsPreferences = SelectedTranslationsPreferences.shared private let themeService = ThemeService.shared diff --git a/Features/TranslationVerseFeature/TranslationVerseBuilder.swift b/Features/TranslationVerseFeature/TranslationVerseBuilder.swift index 2a156873..04421cd7 100644 --- a/Features/TranslationVerseFeature/TranslationVerseBuilder.swift +++ b/Features/TranslationVerseFeature/TranslationVerseBuilder.swift @@ -6,6 +6,7 @@ // Copyright © 2022 Quran.com. All rights reserved. // +import AnnotationsService import AppDependencies import Caching import Foundation @@ -26,7 +27,7 @@ public struct TranslationVerseBuilder { // MARK: Public - public func build(startingVerse: AyahNumber, quranUITraits: QuranUITraits, actions: TranslationVerseActions) -> UIViewController { + public func build(startingVerse: AyahNumber, actions: TranslationVerseActions) -> UIViewController { let dataService = QuranTextDataService( databasesURL: container.databasesURL, quranFileURL: container.quranUthmaniV2Database @@ -34,9 +35,10 @@ public struct TranslationVerseBuilder { let viewModel = TranslationVerseViewModel(startingVerse: startingVerse, dataService: dataService, actions: actions) let viewController = TranslationVerseViewController( viewModel: viewModel, - quranUITraits: quranUITraits, moreMenuBuilder: MoreMenuBuilder(), - translationsSelectionBuilder: TranslationsListBuilder(container: container) + translationsSelectionBuilder: TranslationsListBuilder(container: container), + // Pass a new highlights service that will always be empty + highlightsService: QuranHighlightsService() ) let navigationController = UINavigationController(rootViewController: viewController) return navigationController diff --git a/Features/TranslationVerseFeature/TranslationVerseDataSource.swift b/Features/TranslationVerseFeature/TranslationVerseDataSource.swift index e381ed32..6615bba1 100644 --- a/Features/TranslationVerseFeature/TranslationVerseDataSource.swift +++ b/Features/TranslationVerseFeature/TranslationVerseDataSource.swift @@ -6,6 +6,7 @@ // Copyright © 2022 Quran.com. All rights reserved. // +import AnnotationsService import Foundation import Localization import QuranAnnotations @@ -26,26 +27,19 @@ class TranslationVerseDataSource { // MARK: - Configuration - init(collectionView: UICollectionView) { + init(collectionView: UICollectionView, highlightsService: QuranHighlightsService) { self.collectionView = collectionView + cellProvider = TranslationCellProvider
(collapsedNumberOfLines: 10, highlightsService: highlightsService) dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { [weak self] collectionView, indexPath, itemId in self?.cellProvider.provideCell(collectionView: collectionView, indexPath: indexPath, itemId: itemId) } + cellProvider.dataSource = dataSource + cellProvider.collectionView = collectionView cellProvider.expansionHandler = TranslationExpansionHandler(dataSource: dataSource) } // MARK: Internal - // MARK: - APIs - - var quranUITraits: QuranUITraits { - get { cellProvider.quranUITraits } - set { - cellProvider.quranUITraits = newValue - cellProvider.updateQuranUITraits(dataSource: dataSource, collectionView: collectionView) - } - } - var translatedVerse: TranslatedVerse? { didSet { guard let translatedVerse else { @@ -60,7 +54,7 @@ class TranslationVerseDataSource { private weak var collectionView: UICollectionView? private var dataSource: UICollectionViewDiffableDataSource! // swiftlint:disable:this implicitly_unwrapped_optional - private let cellProvider = TranslationCellProvider
(collapsedNumberOfLines: 10) + private let cellProvider: TranslationCellProvider
// MARK: - Data diff --git a/Features/TranslationVerseFeature/TranslationVerseViewController.swift b/Features/TranslationVerseFeature/TranslationVerseViewController.swift index eb4d08f2..be43d980 100644 --- a/Features/TranslationVerseFeature/TranslationVerseViewController.swift +++ b/Features/TranslationVerseFeature/TranslationVerseViewController.swift @@ -6,12 +6,11 @@ // Copyright © 2022 Quran.com. All rights reserved. // +import AnnotationsService import Combine import MoreMenuFeature import NoorUI -import QuranAnnotations import QuranKit -import QuranTextKit import QuranTranslationFeature import TranslationService import TranslationsFeature @@ -24,17 +23,16 @@ class TranslationVerseViewController: UIViewController { init( viewModel: TranslationVerseViewModel, - quranUITraits: QuranUITraits, moreMenuBuilder: MoreMenuBuilder, - translationsSelectionBuilder: TranslationsListBuilder + translationsSelectionBuilder: TranslationsListBuilder, + highlightsService: QuranHighlightsService ) { self.viewModel = viewModel self.moreMenuBuilder = moreMenuBuilder self.translationsSelectionBuilder = translationsSelectionBuilder collectionView = QuranTranslationDiffableDataSource.translationCollectionView() - dataSource = TranslationVerseDataSource(collectionView: collectionView) + dataSource = TranslationVerseDataSource(collectionView: collectionView, highlightsService: highlightsService) super.init(nibName: nil, bundle: nil) - self.quranUITraits = quranUITraits } @available(*, unavailable) @@ -91,21 +89,10 @@ class TranslationVerseViewController: UIViewController { private let moreMenuBuilder: MoreMenuBuilder private let translationsSelectionBuilder: TranslationsListBuilder - private let fontSizePreferences = FontSizePreferences.shared private let selectedTranslationsPreferences = SelectedTranslationsPreferences.shared private var firstTime = true - private var quranUITraits: QuranUITraits { - get { dataSource.quranUITraits } - set { - logger.info("Verse Translation: set quranUITraits") - var newQuranUITraits = newValue - newQuranUITraits.removeHighlights() - dataSource.quranUITraits = newQuranUITraits - } - } - private func configureCollectionView() { collectionView.contentInsetAdjustmentBehavior = .automatic view.addAutoLayoutSubview(collectionView) @@ -168,12 +155,6 @@ class TranslationVerseViewController: UIViewController { selectedTranslationsPreferences.$selectedTranslations .sink { [weak self] _ in self?.viewModel.reload() } .store(in: &cancellables) - fontSizePreferences.$arabicFontSize - .sink { [weak self] in self?.quranUITraits.arabicFontSize = $0 } - .store(in: &cancellables) - fontSizePreferences.$translationFontSize - .sink { [weak self] in self?.quranUITraits.translationFontSize = $0 } - .store(in: &cancellables) } @objc diff --git a/Model/QuranAnnotations/QuranUITraits.swift b/Model/QuranAnnotations/QuranUITraits.swift deleted file mode 100644 index 931ead67..00000000 --- a/Model/QuranAnnotations/QuranUITraits.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// QuranUITraits.swift -// Quran -// -// Created by Afifi, Mohamed on 10/29/21. -// Copyright © 2021 Quran.com. All rights reserved. -// - -import Foundation -import QuranKit -import QuranText - -public struct QuranUITraits: Equatable { - // MARK: Lifecycle - - public init() { } - - // MARK: Public - - public var highlights = QuranHighlights() - - public var translationFontSize: FontSize = .xSmall - public var arabicFontSize: FontSize = .xSmall - - public mutating func removeHighlights() { - highlights = QuranHighlights() - } -}