Skip to content

Commit

Permalink
Refactor the new translation ui components into reusable NoorUI compo…
Browse files Browse the repository at this point in the history
…nents (#629)
  • Loading branch information
mohamede1945 authored Feb 10, 2024
1 parent bcc4d69 commit c83a53a
Show file tree
Hide file tree
Showing 13 changed files with 379 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public actor ReadingResourcesService {
.eraseToAnyPublisher()
}

public func startLoadingResources() async {
public func startLoadingResources() {
let initialReading = preferences.reading
readingsTask = Task { [weak self] in
guard let readings = self?.preferences.$reading.prepend(initialReading).values() else {
Expand Down
19 changes: 12 additions & 7 deletions Features/QuranImageFeature/ContentImageBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,7 @@ public struct ContentImageBuilder: PageViewBuilder {
self.highlightsService = highlightsService

let reading = ReadingPreferences.shared.reading
let readingDirectory = Self.readingDirectory(reading, container: container)

let imageService = ImageDataService(
ayahInfoDatabase: reading.ayahInfoDatabase(in: readingDirectory),
imagesURL: reading.images(in: readingDirectory),
cropInsets: reading.cropInsets
)
let imageService = Self.buildImageDataService(reading: reading, container: container)

let pages = reading.quran.pages
cacheableImageService = Self.createCahceableImageService(imageService: imageService, pages: pages)
Expand All @@ -53,6 +47,17 @@ public struct ContentImageBuilder: PageViewBuilder {
)
}

// MARK: Internal

static func buildImageDataService(reading: Reading, container: AppDependencies) -> ImageDataService {
let readingDirectory = Self.readingDirectory(reading, container: container)
return ImageDataService(
ayahInfoDatabase: reading.ayahInfoDatabase(in: readingDirectory),
imagesURL: reading.images(in: readingDirectory),
cropInsets: reading.cropInsets
)
}

// MARK: Private

private let container: AppDependencies
Expand Down
186 changes: 42 additions & 144 deletions Features/QuranTranslationFeature/TranslationItem+View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,180 +5,78 @@
// Created by Mohamed Afifi on 2023-12-28.
//

import Localization
import NoorUI
import QuranKit
import QuranText
import SwiftUI

extension TranslationPageHeader: View {
var body: some View {
HStack {
Text(page.localizedQuarterName)
Spacer()
page.suraNames()
.view(ofSize: .footnote, alignment: .trailing)
}
.readableInsetsPadding([.top, .horizontal])
.padding(.bottom, ContentDimension.interSpacing)
QuranPageHeader(quarterName: page.localizedQuarterName, suraNames: page.suraNames())
}
}

extension TranslationPageFooter: View {
var body: some View {
HStack {
Spacer()
Text(page.localizedNumber)
Spacer()
}
.padding(.top, ContentDimension.interSpacing)
.readableInsetsPadding([.bottom, .horizontal])
QuranPageFooter(page: page.localizedNumber)
}
}

extension TranslationVerseSeparator: View {
extension TranslationSuraName: View {
var body: some View {
Rectangle()
.fill(Color.systemGray4)
.frame(height: 1)
.frame(maxWidth: .infinity, alignment: .trailing)
.padding(.top, ContentDimension.interSpacing)
QuranSuraName(suraName: sura.localizedName(withPrefix: false), besmAllah: sura.quran.arabicBesmAllah, besmAllahFontSize: arabicFontSize)
}
}

struct TranslationSuraNameView: View {
@ScaledMetric var bottomPadding = 5
@ScaledMetric var topPadding = 10

let suraName: TranslationSuraName

extension TranslationArabicText: View {
var body: some View {
VStack {
NoorImage.suraHeader.image.resizable()
.aspectRatio(contentMode: .fit)
.overlay {
Text(suraName.sura.localizedName(withPrefix: false))
.font(.title3)
.lineLimit(1)
.minimumScaleFactor(0.3)
}
Text(suraName.sura.quran.arabicBesmAllah)
.font(.quran())
.dynamicTypeSize(suraName.arabicFontSize.dynamicTypeSize)
}
.padding(.bottom, bottomPadding)
.padding(.top, topPadding)
.readableInsetsPadding(.horizontal)
QuranArabicText(verse: verse, text: text, fontSize: arabicFontSize)
}
}

struct TranslationArabicTextView: View {
@ScaledMetric var bottomPadding = 5
@ScaledMetric var topPadding = 10

let arabicText: TranslationArabicText

var body: some View {
VStack(alignment: .leading, spacing: 0) {
Text(lFormat("translation.text.ayah-number", arabicText.verse.sura.suraNumber, arabicText.verse.ayah))
.padding(8)
.foregroundColor(.secondaryLabel)
.background(
RoundedRectangle(cornerRadius: 6)
.fill(Color.systemGray5.opacity(0.5))
)

Text(arabicText.text)
.font(.quran())
.dynamicTypeSize(arabicText.arabicFontSize.dynamicTypeSize)
.textAlignment(follows: .rightToLeft)
}
.padding(.bottom, bottomPadding)
.padding(.top, topPadding)
.readableInsetsPadding(.horizontal)
extension TranslationTextChunk {
var readMoreURL: URL {
TranslationURL.readMore(
translationId: translation.id,
sura: verse.sura.suraNumber,
ayah: verse.ayah
).url
}
}

struct TranslationTextChunkView: View {
@ScaledMetric var topPadding = 10
@ScaledMetric var baselineOffset = 5

let chunk: TranslationTextChunk

extension TranslationTextChunk: View {
var body: some View {
Text(string)
.font(chunk.translation.textFont)
.dynamicTypeSize(chunk.translationFontSize.dynamicTypeSize)
.textAlignment(follows: chunk.translation.characterDirection)
.padding(.top, chunk.chunkIndex == 0 ? topPadding : 0)
.readableInsetsPadding(.horizontal)
}

private var string: AttributedString {
let chunkRange = chunk.chunks[chunk.chunkIndex]
let chunkText = chunk.text.text[chunkRange]

var string = AttributedString(chunkText)
for (index, footnoteRange) in chunk.text.footnoteRanges.enumerated() {
if let range = string.range(from: footnoteRange, overallRange: chunkRange, overallText: chunk.text.text) {
string[range].link = TranslationURL.footnote(
translationId: chunk.translation.id,
sura: chunk.verse.sura.suraNumber,
ayah: chunk.verse.ayah,
QuranTranslationTextChunk(
text: text.text,
chunk: chunks[chunkIndex],
footnoteRanges: text.footnoteRanges,
quranRanges: text.quranRanges,
firstChunk: chunkIndex == 0,
readMoreURL: readMore ? readMoreURL : nil,
footnoteURL: { index in
TranslationURL.footnote(
translationId: translation.id,
sura: verse.sura.suraNumber,
ayah: verse.ayah,
footnoteIndex: index
).url
string[range].font = .footnote
string[range].baselineOffset = baselineOffset
}
}

for quranRange in chunk.text.quranRanges {
if let range = string.range(from: quranRange, overallRange: chunkRange, overallText: chunk.text.text) {
string[range].foregroundColor = .accentColor
}
}

if chunk.readMore {
var readMore = AttributedString("\n\(l("translation.text.read-more"))")
readMore.foregroundColor = .accentColor
readMore.link = TranslationURL.readMore(
translationId: chunk.translation.id,
sura: chunk.verse.sura.suraNumber,
ayah: chunk.verse.ayah
).url
readMore.font = .body
string.append(readMore)
}

return string
},
font: translation.textFont,
fontSize: translationFontSize,
characterDirection: translation.characterDirection
)
}
}

struct TranslationReferenceVerseView: View {
@ScaledMetric var topPadding = 10
let referenceVerse: TranslationReferenceVerse

extension TranslationReferenceVerse: View {
var body: some View {
Text(lFormat("translation.text.see-referenced-verse", referenceVerse.reference.ayah))
.font(.body)
.dynamicTypeSize(referenceVerse.translationFontSize.dynamicTypeSize)
.textAlignment(follows: referenceVerse.translation.characterDirection)
.padding(.top, topPadding)
.readableInsetsPadding(.horizontal)
QuranTranslationReferenceVerse(reference: reference, fontSize: translationFontSize, characterDirection: translation.characterDirection)
}
}

struct TranslatorTextView: View {
@ScaledMetric var bottomPadding = 10
let translator: TranslatorText
extension TranslatorText: View {
var body: some View {
Text(verbatim: "- \(translator.translation.translationName)")
.foregroundColor(.secondaryLabel)
.font(.body)
.dynamicTypeSize(translator.translationFontSize.dynamicTypeSize)
.textAlignment(follows: translator.translation.characterDirection)
.padding(.bottom, bottomPadding)
.readableInsetsPadding(.horizontal)
QuranTranslatorName(name: translation.translationName, fontSize: translationFontSize, characterDirection: translation.characterDirection)
}
}

Expand All @@ -190,18 +88,18 @@ extension TranslationItem: View {
pageHeader
case .pageFooter(let pageFooter):
pageFooter
case .verseSeparator(let separator, _):
separator
case .verseSeparator:
QuranVerseSeparator()
case .suraName(let suraName, _):
TranslationSuraNameView(suraName: suraName)
suraName
case .arabicText(let arabicText, _):
TranslationArabicTextView(arabicText: arabicText)
arabicText
case .translationTextChunk(let translationTextChunk, _):
TranslationTextChunkView(chunk: translationTextChunk)
translationTextChunk
case .translationReferenceVerse(let translationReferenceVerse, _):
TranslationReferenceVerseView(referenceVerse: translationReferenceVerse)
translationReferenceVerse
case .translatorText(let translatorText, _):
TranslatorTextView(translator: translatorText)
translatorText
}
}
.font(.footnote)
Expand Down
46 changes: 46 additions & 0 deletions UI/NoorUI/Features/Quran/QuranArabicText.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// QuranArabicText.swift
//
//
// Created by Mohamed Afifi on 2024-02-10.
//

import Localization
import QuranKit
import QuranText
import SwiftUI

public struct QuranArabicText: View {
@ScaledMetric var bottomPadding = 5
@ScaledMetric var topPadding = 10

let verse: AyahNumber
let text: String
let fontSize: FontSize

public init(verse: AyahNumber, text: String, fontSize: FontSize) {
self.verse = verse
self.text = text
self.fontSize = fontSize
}

public var body: some View {
VStack(alignment: .leading, spacing: 0) {
Text(lFormat("translation.text.ayah-number", verse.sura.suraNumber, verse.ayah))
.padding(8)
.foregroundColor(.secondaryLabel)
.background(
RoundedRectangle(cornerRadius: 6)
.fill(Color.systemGray5.opacity(0.5))
)

Text(text)
.font(.quran())
.dynamicTypeSize(fontSize.dynamicTypeSize)
.textAlignment(follows: .rightToLeft)
}
.padding(.bottom, bottomPadding)
.padding(.top, topPadding)
.readableInsetsPadding(.horizontal)
}
}
26 changes: 26 additions & 0 deletions UI/NoorUI/Features/Quran/QuranPageFooter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// QuranPageFooter.swift
//
//
// Created by Mohamed Afifi on 2024-02-10.
//

import SwiftUI

public struct QuranPageFooter: View {
let page: String

public init(page: String) {
self.page = page
}

public var body: some View {
HStack {
Spacer()
Text(page)
Spacer()
}
.padding(.top, ContentDimension.interSpacing)
.readableInsetsPadding([.bottom, .horizontal])
}
}
29 changes: 29 additions & 0 deletions UI/NoorUI/Features/Quran/QuranPageHeader.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// QuranPageHeader.swift
//
//
// Created by Mohamed Afifi on 2024-02-10.
//

import SwiftUI

public struct QuranPageHeader: View {
private let quarterName: String
private let suraNames: MultipartText

public init(quarterName: String, suraNames: MultipartText) {
self.quarterName = quarterName
self.suraNames = suraNames
}

public var body: some View {
HStack {
Text(quarterName)
Spacer()
suraNames
.view(ofSize: .footnote, alignment: .trailing)
}
.readableInsetsPadding([.top, .horizontal])
.padding(.bottom, ContentDimension.interSpacing)
}
}
File renamed without changes.
Loading

0 comments on commit c83a53a

Please sign in to comment.