diff --git a/app/src/main/java/com/ganjoor/android/ui/PoetsScreen.kt b/app/src/main/java/com/ganjoor/android/ui/PoetsScreen.kt
index b10ad89..7e456f0 100644
--- a/app/src/main/java/com/ganjoor/android/ui/PoetsScreen.kt
+++ b/app/src/main/java/com/ganjoor/android/ui/PoetsScreen.kt
@@ -55,6 +55,11 @@ import coil3.compose.AsyncImage
import java.text.Collator
import java.util.Locale
import com.ganjoor.android.R
+import com.ganjoor.android.ui.theme.downloaded
+import com.ganjoor.android.data.Offline
+import com.ganjoor.android.data.Downloads
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material.icons.filled.CheckCircle
import com.ganjoor.android.data.Ganjoor
import com.ganjoor.android.data.PoetRef
@@ -249,6 +254,49 @@ private fun PinMark(modifier: Modifier = Modifier) {
)
}
+/**
+ * Fetch a poet's poems, or say they are already here. Three states and no menu: downloading shows
+ * its progress and cancels on a tap, downloaded is a green tick, and anything else offers the
+ * download. Deleting stays on the downloads page, where the sizes are — a tap next to a poet's
+ * name should never be the thing that throws their poems away.
+ */
+@Composable
+private fun DownloadAction(slug: String) {
+ val progress = Downloads.running[slug]
+ val saved = remember(slug, Downloads.revision) { Offline.isSaved(slug) }
+
+ when {
+ progress != null -> IconButton(onClick = { Downloads.cancel(slug) }) {
+ CircularProgressIndicator(
+ strokeWidth = 2.dp,
+ modifier = Modifier.size(18.dp),
+ )
+ }
+
+ // In a box the size of an IconButton, even though nothing here is tappable: a bare icon
+ // sits where the button's padding would have put it, so the ticks and the arrows would
+ // not line up down the column.
+ saved -> Box(
+ modifier = Modifier.size(48.dp),
+ contentAlignment = Alignment.Center,
+ ) {
+ Icon(
+ imageVector = Icons.Default.CheckCircle,
+ contentDescription = stringResource(R.string.downloaded_poet),
+ tint = MaterialTheme.colorScheme.downloaded,
+ )
+ }
+
+ else -> IconButton(onClick = { Downloads.start(slug) }) {
+ Icon(
+ painter = painterResource(R.drawable.ic_download),
+ contentDescription = stringResource(R.string.download),
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+ }
+}
+
/** One poet as a row, for readers who would rather scan names than faces. */
@Composable
private fun PoetRow(poet: PoetRef, pinned: Boolean, onClick: () -> Unit, onPin: () -> Unit) {
@@ -271,7 +319,15 @@ private fun PoetRow(poet: PoetRef, pinned: Boolean, onClick: () -> Unit, onPin:
)
}
},
- trailingContent = { if (pinned) PinMark() },
+ trailingContent = {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ if (pinned) PinMark()
+ DownloadAction(poet.slug)
+ }
+ },
modifier = Modifier.combinedClickable(onClick = onClick, onLongClick = onPin),
)
}
diff --git a/app/src/main/java/com/ganjoor/android/ui/theme/Theme.kt b/app/src/main/java/com/ganjoor/android/ui/theme/Theme.kt
index 3be6baf..2872848 100644
--- a/app/src/main/java/com/ganjoor/android/ui/theme/Theme.kt
+++ b/app/src/main/java/com/ganjoor/android/ui/theme/Theme.kt
@@ -9,6 +9,7 @@ import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalView
@@ -202,3 +203,13 @@ fun GanjoorTheme(
content = content,
)
}
+
+/**
+ * The green on a poet whose poems are already on the device.
+ *
+ * Material's palette has no success colour, and a fixed green goes muddy on the sepia schemes and
+ * glares on OLED black. Picking by the surface's luminance covers all five schemes without each
+ * of them having to declare one.
+ */
+val ColorScheme.downloaded: Color
+ get() = if (surface.luminance() < 0.5f) Color(0xFF81C784) else Color(0xFF2E7D32)
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index 0b18f2c..58ad7ff 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -113,4 +113,5 @@
برای نگهداشتن یک شاعر در اینجا، انگشت را روی او نگه دارید
نمایش کارتی
نمایش فهرستی
+ پیشتر دریافت شده
diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml
index 43fa119..c6a95da 100644
--- a/app/src/main/res/values-ur/strings.xml
+++ b/app/src/main/res/values-ur/strings.xml
@@ -113,4 +113,5 @@
کسی شاعر کو یہاں رکھنے کے لیے اُس پر دبا کر رکھیں
کارڈ کی صورت
فہرست کی صورت
+ پہلے سے محفوظ ہے
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c7f3e98..fd37aa3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -118,4 +118,5 @@
Press and hold a poet to keep them here
Show as cards
Show as a list
+ Already downloaded
diff --git a/fastlane/metadata/android/en-US/changelogs/5.txt b/fastlane/metadata/android/en-US/changelogs/5.txt
index 6f76539..eb371a8 100644
--- a/fastlane/metadata/android/en-US/changelogs/5.txt
+++ b/fastlane/metadata/android/en-US/changelogs/5.txt
@@ -6,3 +6,6 @@ alphabetical listing a tap away. Until you pin anything the shelf is simply
Ganjoor's order, so there is never an empty screen.
Poets can be shown as cards or as a list, whichever reads better.
+
+Each poet in the list view carries a download button, and a green tick once their
+poems are on the device. Text only — recitations are still streamed when you play them.
diff --git a/fastlane/metadata/android/fa/changelogs/5.txt b/fastlane/metadata/android/fa/changelogs/5.txt
index b9cd46b..733fbca 100644
--- a/fastlane/metadata/android/fa/changelogs/5.txt
+++ b/fastlane/metadata/android/fa/changelogs/5.txt
@@ -6,3 +6,6 @@
صفحهای خالی نمیبینید.
شاعران را میتوان کارتی یا فهرستی دید، هرکدام که خواناتر است.
+
+هر شاعر در نمایش فهرستی یک دکمهٔ دریافت دارد، و پس از ذخیرهشدن شعرهایش یک تیک سبز.
+فقط متن؛ خوانشها همچنان هنگام پخش از اینترنت میآیند.
diff --git a/fastlane/metadata/android/ur/changelogs/5.txt b/fastlane/metadata/android/ur/changelogs/5.txt
index 5b6e2f3..49cc684 100644
--- a/fastlane/metadata/android/ur/changelogs/5.txt
+++ b/fastlane/metadata/android/ur/changelogs/5.txt
@@ -7,3 +7,6 @@
سو خالی صفحہ کبھی نہیں ملتا۔
شاعروں کو کارڈ کی صورت یا فہرست کی صورت، جو بہتر لگے، دیکھا جا سکتا ہے۔
+
+فہرست کی صورت میں ہر شاعر کے ساتھ ڈاؤن لوڈ کا بٹن ہے، اور اُن کا کلام محفوظ ہو جانے پر
+سبز نشان۔ صرف متن؛ تلاوتیں اب بھی سنتے وقت آن لائن چلتی ہیں۔
diff --git a/releases/README.md b/releases/README.md
index a63eb5d..f65eb4a 100644
--- a/releases/README.md
+++ b/releases/README.md
@@ -12,7 +12,7 @@ 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.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.3.0 | 5 | `HEAD` | Pin poets to the home screen: three views (pinned, Ganjoor's order, alphabetical), as cards or a list. |
+| 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. |
## Checksums
@@ -21,7 +21,7 @@ from source and signs with its own key, so these are for direct installation onl
43d78b773efca2b1aa2bf790c689b3086389d66c4ea0ffb72c9dba8bddb50770 ganjoor-0.2.0.apk
5163554eb01845c131c31a9da7bdd748170bb9b5f82edaece754b4cf40b02b0c ganjoor-0.2.1.apk
e473269044710813d2cf4119de663fe180f887239df7bdb1ccee0239ef84fd3e ganjoor-0.2.2.apk
-d9c49f109854793a0d96a3bd42dffff931dc37825dc49b4ed80cc4de1349ff72 ganjoor-0.3.0.apk
+5ac991ab8fe8676f89f4bc09a1a5d7464e32b6f74d789e7f29038b85f2c64f4a ganjoor-0.3.0.apk
```
Installing: `adb install -r releases/ganjoor-.apk`. A phone holding a *debug* build has
diff --git a/releases/ganjoor-0.3.0.apk b/releases/ganjoor-0.3.0.apk
index c1654b1..ba35dcf 100644
Binary files a/releases/ganjoor-0.3.0.apk and b/releases/ganjoor-0.3.0.apk differ