Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f49d9f080f | ||
|
|
c801d88ef3 | ||
|
|
331e0544bc | ||
|
|
a725e66a9a | ||
|
|
31279bc5da | ||
|
|
23efc2afa3 | ||
|
|
3486a89b56 |
No files matched your search
@@ -111,7 +111,7 @@ fun PoemScreen(
|
|||||||
// foldable held open in portrait the page is already down to ~450dp, and a panel beside it
|
// foldable held open in portrait the page is already down to ~450dp, and a panel beside it
|
||||||
// left the verse a couple of characters a line. Where it does not fit, the sheet is the
|
// left the verse a couple of characters a line. Where it does not fit, the sheet is the
|
||||||
// better answer: it covers the foot of the poem but leaves the lines whole.
|
// better answer: it covers the foot of the poem but leaves the lines whole.
|
||||||
val roomForPanel = wide && maxWidth - DictionaryPanelWidth >= MinPageMeasure
|
val roomForPanel = dictionaryFitsBeside(maxWidth, wide)
|
||||||
|
|
||||||
Load(
|
Load(
|
||||||
key = fullUrl,
|
key = fullUrl,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.ganjoor.android.R
|
import com.ganjoor.android.R
|
||||||
import com.ganjoor.android.data.Definition
|
import com.ganjoor.android.data.Definition
|
||||||
@@ -64,6 +65,21 @@ val DictionaryPanelWidth = 216.dp
|
|||||||
*/
|
*/
|
||||||
val MinPageMeasure = 400.dp
|
val MinPageMeasure = 400.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the dictionary earns a column of its own beside a page [pageWidth] wide.
|
||||||
|
*
|
||||||
|
* Not a question about the window but about the page: by the time a poem is open the columns have
|
||||||
|
* already taken their room, and on a book-style foldable held open in portrait what is left is
|
||||||
|
* about 450dp. A panel beside that leaves the verse a couple of characters a line, so below
|
||||||
|
* [MinPageMeasure] the bottom sheet is used instead — it covers the foot of the poem but leaves
|
||||||
|
* every line whole.
|
||||||
|
*
|
||||||
|
* A pure function so the rule can be tested: the gesture that reaches it cannot be driven
|
||||||
|
* reliably, but the arithmetic behind it can.
|
||||||
|
*/
|
||||||
|
internal fun dictionaryFitsBeside(pageWidth: Dp, wide: Boolean): Boolean =
|
||||||
|
wide && pageWidth - DictionaryPanelWidth >= MinPageMeasure
|
||||||
|
|
||||||
/** English prose inside an otherwise right-to-left sheet. */
|
/** English prose inside an otherwise right-to-left sheet. */
|
||||||
@Composable
|
@Composable
|
||||||
private fun LeftToRight(content: @Composable () -> Unit) {
|
private fun LeftToRight(content: @Composable () -> Unit) {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.ganjoor.android.ui.theme
|
package com.ganjoor.android.ui.theme
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import androidx.compose.material3.Typography
|
import androidx.compose.material3.Typography
|
||||||
import androidx.compose.ui.text.ExperimentalTextApi
|
import androidx.compose.ui.text.ExperimentalTextApi
|
||||||
import androidx.compose.ui.text.PlatformTextStyle
|
import androidx.compose.ui.text.PlatformTextStyle
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.Font
|
import androidx.compose.ui.text.font.Font
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
|
||||||
import androidx.compose.ui.text.font.FontVariation
|
import androidx.compose.ui.text.font.FontVariation
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
@@ -15,24 +15,40 @@ import com.ganjoor.android.R
|
|||||||
import com.ganjoor.android.ui.ReadingFont
|
import com.ganjoor.android.ui.ReadingFont
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Both files are variable fonts with a `wght` axis, registered at four weights so a reader can
|
* Both files are variable fonts, registered at four weights so a reader can thicken the text —
|
||||||
* thicken the text — thin naskh strokes wash out on a lit screen, especially in the dark themes.
|
* thin naskh strokes wash out on a lit screen, especially in the dark themes.
|
||||||
*
|
*
|
||||||
* Real axis interpolation needs API 26+; on 24 and 25 the variation settings are ignored and
|
* Only `wght` is asked for, and deliberately: both files carry that one axis and nothing else.
|
||||||
* Android falls back to synthesising the heavier weights, which still darkens the text.
|
* `FontVariation.Settings(weight, style)` would also send `ital`, and a font with no italic axis
|
||||||
|
* is entitled to refuse the whole request rather than the part it cannot honour. A platform that
|
||||||
|
* does so leaves every weight drawing at 400 — and silently, because each entry here declares the
|
||||||
|
* weight it was asked for, so the text is never a candidate for synthetic bolding either.
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalTextApi::class)
|
@OptIn(ExperimentalTextApi::class)
|
||||||
private fun variable(resId: Int, weight: FontWeight) = Font(
|
private fun variable(resId: Int, weight: FontWeight) = Font(
|
||||||
resId = resId,
|
resId = resId,
|
||||||
weight = weight,
|
weight = weight,
|
||||||
variationSettings = FontVariation.Settings(weight, FontStyle.Normal),
|
variationSettings = FontVariation.Settings(FontVariation.weight(weight.weight)),
|
||||||
)
|
)
|
||||||
|
|
||||||
private val weights =
|
private val weights =
|
||||||
listOf(FontWeight.Normal, FontWeight.Medium, FontWeight.SemiBold, FontWeight.Bold)
|
listOf(FontWeight.Normal, FontWeight.Medium, FontWeight.SemiBold, FontWeight.Bold)
|
||||||
|
|
||||||
val Naskh = FontFamily(weights.map { variable(R.font.noto_naskh_arabic, it) })
|
/**
|
||||||
val Nastaliq = FontFamily(weights.map { variable(R.font.noto_nastaliq_urdu, it) })
|
* Variable axes need API 26. Below that the settings above are dropped, and declaring four
|
||||||
|
* weights of the same file would make the heavier ones unreachable: Android would match the
|
||||||
|
* entry claiming 700, draw it at 400, and skip synthetic bolding because the entry said it was
|
||||||
|
* already bold. One entry at its real weight instead, so asking for bold actually synthesises it.
|
||||||
|
*/
|
||||||
|
private fun scriptFamily(resId: Int): FontFamily =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
FontFamily(weights.map { variable(resId, it) })
|
||||||
|
} else {
|
||||||
|
FontFamily(Font(resId, FontWeight.Normal))
|
||||||
|
}
|
||||||
|
|
||||||
|
val Naskh = scriptFamily(R.font.noto_naskh_arabic)
|
||||||
|
val Nastaliq = scriptFamily(R.font.noto_nastaliq_urdu)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The English UI only. Libron is a reading serif (OFL, github.com/nicoverbruggen/libron) and
|
* The English UI only. Libron is a reading serif (OFL, github.com/nicoverbruggen/libron) and
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.ganjoor.android
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.ganjoor.android.ui.dictionaryFitsBeside
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rule that decides whether the dictionary opens beside the poem or as a sheet over it.
|
||||||
|
*
|
||||||
|
* Driving the gesture that reaches it — a tap landing on the glyphs of one Persian word — is not
|
||||||
|
* something adb does reliably, so the arithmetic is tested directly instead.
|
||||||
|
*/
|
||||||
|
class DictionaryPanelFitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `a tablet has room beside the poem`() {
|
||||||
|
// 1280dp window, less the poets rail and two list columns, leaves the page about 900dp.
|
||||||
|
assertTrue(dictionaryFitsBeside(900.dp, wide = true))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `a foldable open in portrait does not`() {
|
||||||
|
// 700dp window, less the rail and the newest column, leaves about 450dp — and 450 less
|
||||||
|
// the 216dp panel is 234dp, which is a cramped phone column, not a measure for a verse.
|
||||||
|
assertFalse(dictionaryFitsBeside(450.dp, wide = true))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `a phone never gets the panel, however the page is measured`() {
|
||||||
|
assertFalse(dictionaryFitsBeside(420.dp, wide = false))
|
||||||
|
assertFalse(dictionaryFitsBeside(2000.dp, wide = false))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `the boundary is the panel plus the minimum measure`() {
|
||||||
|
assertTrue(dictionaryFitsBeside(616.dp, wide = true)) // 400 + 216, exactly
|
||||||
|
assertFalse(dictionaryFitsBeside(615.dp, wide = true))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# F-Droid metadata for Ganjoor for Android.
|
||||||
|
#
|
||||||
|
# This file is not read by the app or the build; it is the recipe F-Droid's build
|
||||||
|
# server uses, kept here so it travels with the source it describes. To submit or
|
||||||
|
# update the listing, copy it into a fork of gitlab.com/fdroid/fdroiddata as
|
||||||
|
# metadata/com.ganjoor.android.yml and open a merge request.
|
||||||
|
#
|
||||||
|
# F-Droid builds from source and signs with their own key, which is why the
|
||||||
|
# release build must succeed with no keystore present — see app/build.gradle.kts.
|
||||||
|
|
||||||
|
Categories:
|
||||||
|
- Reading
|
||||||
|
License: MIT
|
||||||
|
AuthorName: Muhammad Anas Rashid
|
||||||
|
SourceCode: https://github.com/anas-rashid/ganjoorandroid
|
||||||
|
IssueTracker: https://github.com/anas-rashid/ganjoorandroid/issues
|
||||||
|
Changelog: https://github.com/anas-rashid/ganjoorandroid/releases
|
||||||
|
|
||||||
|
AutoName: گنجور
|
||||||
|
|
||||||
|
RepoType: git
|
||||||
|
Repo: https://github.com/anas-rashid/ganjoorandroid.git
|
||||||
|
|
||||||
|
Builds:
|
||||||
|
- versionName: 0.4.0
|
||||||
|
versionCode: 6
|
||||||
|
commit: v0.4.0
|
||||||
|
subdir: app
|
||||||
|
gradle:
|
||||||
|
- yes
|
||||||
|
|
||||||
|
AutoUpdateMode: Version
|
||||||
|
UpdateCheckMode: Tags
|
||||||
|
CurrentVersion: 0.4.0
|
||||||
|
CurrentVersionCode: 6
|
||||||
+3
-1
@@ -12,7 +12,8 @@ from source and signs with its own key, so these are for direct installation onl
|
|||||||
| 0.2.0 | 2 | `d92445f` | Share a poem, couplet or selection; look a word up from any app's selection menu; the optional AI assistant. |
|
| 0.2.0 | 2 | `d92445f` | Share a poem, couplet or selection; look a word up from any app's selection menu; the optional AI assistant. |
|
||||||
| 0.2.1 | 3 | `ec05989` | Assistant answers in the page rather than over it, a visible chevron for each couplet's actions, and answers remembered so scrolling doesn't re-ask. |
|
| 0.2.1 | 3 | `ec05989` | Assistant answers in the page rather than over it, a visible chevron for each couplet's actions, and answers remembered so scrolling doesn't re-ask. |
|
||||||
| 0.2.2 | 4 | `d7568d1` | Credits Material Symbols for the glyphs, and states the terms around the optional assistant. |
|
| 0.2.2 | 4 | `d7568d1` | Credits Material Symbols for the glyphs, and states the terms around the optional assistant. |
|
||||||
| 0.3.0 | 5 | `HEAD` | Pin poets to the home screen: three views (pinned, Ganjoor's order, alphabetical), as cards or a list, with a download control on each row. |
|
| 0.3.0 | 5 | `5d12a1c` | Pin poets to the home screen: three views (pinned, Ganjoor's order, alphabetical), as cards or a list, with a download control on each row. |
|
||||||
|
| 0.4.0 | 6 | `270c28c` | Columns on tablets and unfolded foldables; the dictionary and reading settings beside the poem rather than over it; couplets in cards, two hemistichs to a line where there is room; skeletons while pages load; a seek bar on recitations. |
|
||||||
|
|
||||||
## Checksums
|
## Checksums
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ from source and signs with its own key, so these are for direct installation onl
|
|||||||
5163554eb01845c131c31a9da7bdd748170bb9b5f82edaece754b4cf40b02b0c ganjoor-0.2.1.apk
|
5163554eb01845c131c31a9da7bdd748170bb9b5f82edaece754b4cf40b02b0c ganjoor-0.2.1.apk
|
||||||
e473269044710813d2cf4119de663fe180f887239df7bdb1ccee0239ef84fd3e ganjoor-0.2.2.apk
|
e473269044710813d2cf4119de663fe180f887239df7bdb1ccee0239ef84fd3e ganjoor-0.2.2.apk
|
||||||
9c38d5cacf9e809c2189ba581f8aa6eb4072d4fa0316f00d66434461cf4b1459 ganjoor-0.3.0.apk
|
9c38d5cacf9e809c2189ba581f8aa6eb4072d4fa0316f00d66434461cf4b1459 ganjoor-0.3.0.apk
|
||||||
|
1c64cefa0fb2b51bf73386460ec1b88bda3e20832fa6926c2f7f1fb863ab9fc7 ganjoor-0.4.0.apk
|
||||||
```
|
```
|
||||||
|
|
||||||
Installing: `adb install -r releases/ganjoor-<version>.apk`. A phone holding a *debug* build has
|
Installing: `adb install -r releases/ganjoor-<version>.apk`. A phone holding a *debug* build has
|
||||||
|
|||||||
Binary file not shown.
Reference in new issue
Block a user