Recently Written · git

subread-android

SubRead for Android: times an audiobook against its ebook on the device

git clone https://github.com/equwal/subread-android

Log | Files | Refs


commit 8bf84aebd6a34014149301bd257a698153daa461
equwal <13551856+equwal@users.noreply.github.com>
2026-09-26 13:43:20 -0700

Add a More apps section with links to the other apps

The end of the main screen shows the other sites and apps of the author.
A tap on an entry opens its page in the browser.

The Google Play build (-PplayStore=true) does not show the section. It
does not show the Ko-fi link either.

Add a More projects section to the README.

 README.md                                          | 24 +++++++++++++++++
 .../main/kotlin/space/subread/app/MainActivity.kt  | 27 +++++++++++++++++++
 app/src/main/kotlin/space/subread/app/MoreApps.kt  | 29 ++++++++++++++++++++
 .../test/kotlin/space/subread/app/MoreAppsTest.kt  | 31 ++++++++++++++++++++++
 4 files changed, 111 insertions(+)
diff --git a/README.md b/README.md
index 6d059dc..2e2eae2 100644
--- a/README.md
+++ b/README.md
@@ -125,6 +125,30 @@ instructions (anything from 2018 on). Transcription runs at a small multiple of
 real time, so a long book takes hours. The job runs only while the app is open
 and keeps the screen on. An interrupted job continues from its last finished chunk.
 
+## More projects
+
+- [SubRead](https://subread.space/): read along with an audiobook, in the browser.
+  Also [for Android](https://github.com/equwal/subread-android/releases/latest),
+  [for YouTube](https://github.com/equwal/subread-extension/releases/latest)
+  and [for KOReader](https://github.com/equwal/subread.koplugin).
+- [SubRead Overlay](https://github.com/equwal/subread-overlay/releases/latest): subtitle lines over any Android media player.
+- [SubRead Dictionary](https://github.com/equwal/subread-dictionary/releases/latest): a pop-up dictionary for Android that reads Yomitan dictionaries.
+- [SubRead Anki](https://github.com/equwal/subread-anki): one tap makes an Anki card from any Android app.
+- [Subrep](https://github.com/equwal/subrep-android/releases/latest): live captions of the sound of your phone.
+- [Book Simulator](https://booksimulator.com/): a reading room for Aozora Bunko and Project Gutenberg books.
+- [honjimaku.com](https://honjimaku.com/): subtitles for Japanese audiobooks.
+- [sbm Sync](https://sbmsync.com/): your bookmarks, the same on every device,
+  with [sbm](https://github.com/equwal/sbm) for dmenu,
+  [sbm for Android](https://github.com/equwal/sbm-android/releases/latest)
+  and the [sbm add-on](https://github.com/equwal/sbm-extension/releases/latest) for Firefox and Chrome.
+- [Rebind](https://github.com/equwal/rebind/releases): remap the hardware buttons of e-ink readers and Android,
+  with [Ink Recents](https://github.com/equwal/ink-recents/releases/latest),
+  [Ink Dim](https://github.com/equwal/ink-dim/releases/latest)
+  and [Ink Update](https://github.com/equwal/ink-update/releases/latest).
+- [dickt.store](https://dickt.store/): language-learning tools, flashcards and web toys.
+- [hentaibun.online](https://hentaibun.online/): learn kanbun and kobun.
+- [Recently Written](https://recentlywritten.com/): the blog, and a list of [all projects](https://recentlywritten.com/projects.html).
+
 ## Licence
 
 AGPL-3.0: see `LICENSE`. You may use, change and host this, and you must give
diff --git a/app/src/main/kotlin/space/subread/app/MainActivity.kt b/app/src/main/kotlin/space/subread/app/MainActivity.kt
index 4e7bf73..fec4fc3 100644
--- a/app/src/main/kotlin/space/subread/app/MainActivity.kt
+++ b/app/src/main/kotlin/space/subread/app/MainActivity.kt
@@ -11,6 +11,7 @@ import androidx.activity.ComponentActivity
 import androidx.activity.compose.rememberLauncherForActivityResult
 import androidx.activity.compose.setContent
 import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -43,6 +44,7 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.unit.dp
 import androidx.core.content.FileProvider
 import androidx.core.content.IntentCompat
@@ -383,6 +385,11 @@ private fun App(
                     onShare = { status.srt?.let { share(context, it) } },
                     onVideo = { pickVideoFolder.launch(null) })
 
+                // The Google Play build (-PplayStore=true) has no Ko-fi link, and no More apps either.
+                if (BuildConfig.DONATE_LINK) {
+                    HorizontalDivider(color = Color.Black)
+                    MoreApps()
+                }
 
             }
         }
@@ -593,6 +600,26 @@ private fun Outputs(
     }
 }
 
+/** The other sites and apps of the same author. A tap opens the page in the browser. */
+@Composable
+private fun MoreApps() {
+    val context = LocalContext.current
+    Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
+        Text("More apps", fontWeight = FontWeight.Bold)
+        for (app in MORE_APPS) {
+            Column(
+                Modifier.fillMaxWidth().clickable {
+                    // Opens the browser. The app itself still has no network permission.
+                    runCatching { context.startActivity(Intent(Intent.ACTION_VIEW, app.url.toUri())) }
+                },
+            ) {
+                Text(app.name, style = MaterialTheme.typography.bodyMedium, textDecoration = TextDecoration.Underline)
+                Text(app.line, style = MaterialTheme.typography.bodySmall)
+            }
+        }
+    }
+}
+
 private fun share(context: Context, srt: File) {
     val uri = FileProvider.getUriForFile(context, "${context.packageName}.files", srt)
     val send = Intent(Intent.ACTION_SEND)
diff --git a/app/src/main/kotlin/space/subread/app/MoreApps.kt b/app/src/main/kotlin/space/subread/app/MoreApps.kt
new file mode 100644
index 0000000..c494629
--- /dev/null
+++ b/app/src/main/kotlin/space/subread/app/MoreApps.kt
@@ -0,0 +1,29 @@
+package space.subread.app
+
+/** One link of the "More apps" section: a name, one line about it, and the page that a tap opens. */
+data class MoreApp(val name: String, val line: String, val url: String)
+
+/**
+ * The other sites and apps of the same author, in the order of the catalog: the sites,
+ * then the Android apps, then the list of all projects. SubRead for Android is not in it.
+ */
+val MORE_APPS = listOf(
+    MoreApp("SubRead", "Read along with an audiobook.", "https://subread.space/"),
+    MoreApp("Book Simulator", "A reading room for Aozora Bunko and Project Gutenberg books.", "https://booksimulator.com/"),
+    MoreApp("honjimaku.com", "Subtitles for Japanese audiobooks.", "https://honjimaku.com/"),
+    MoreApp("sbm Sync", "Your bookmarks, the same on every device.", "https://sbmsync.com/"),
+    MoreApp("SubRead Overlay", "Subtitle lines over any Android media player.",
+        "https://github.com/equwal/subread-overlay/releases/latest"),
+    MoreApp("SubRead Dictionary", "Pop-up dictionary that reads Yomitan dictionaries.",
+        "https://github.com/equwal/subread-dictionary/releases/latest"),
+    MoreApp("SubRead Anki", "One tap makes an Anki card from any app.", "https://github.com/equwal/subread-anki"),
+    MoreApp("Subrep", "Live captions of the sound of your phone.",
+        "https://github.com/equwal/subrep-android/releases/latest"),
+    MoreApp("sbm for Android", "Fuzzy search for your bookmarks.", "https://github.com/equwal/sbm-android/releases/latest"),
+    MoreApp("Rebind", "Remap the hardware buttons of e-ink readers and Android.", "https://github.com/equwal/rebind/releases"),
+    MoreApp("Ink Recents", "A recent-apps switcher for e-ink.", "https://github.com/equwal/ink-recents/releases/latest"),
+    MoreApp("Ink Dim", "Frontlight below the lowest system level.", "https://github.com/equwal/ink-dim/releases/latest"),
+    MoreApp("Ink Update", "Tells you when Rebind and its extensions update.",
+        "https://github.com/equwal/ink-update/releases/latest"),
+    MoreApp("All projects", "Everything, with source code.", "https://recentlywritten.com/projects.html"),
+)
diff --git a/app/src/test/kotlin/space/subread/app/MoreAppsTest.kt b/app/src/test/kotlin/space/subread/app/MoreAppsTest.kt
new file mode 100644
index 0000000..5a24208
--- /dev/null
+++ b/app/src/test/kotlin/space/subread/app/MoreAppsTest.kt
@@ -0,0 +1,31 @@
+package space.subread.app
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+/** The list of the "More apps" section. No Android, so this runs on a laptop. */
+class MoreAppsTest {
+
+    @Test
+    fun theListLeavesOutThisApp() {
+        assertFalse(MORE_APPS.any { it.name == "SubRead for Android" || "equwal/subread-android" in it.url })
+    }
+
+    @Test
+    fun eachLinkOpensAnHttpsPage() {
+        for (app in MORE_APPS) assertTrue(app.url, app.url.startsWith("https://"))
+    }
+
+    @Test
+    fun theListKeepsTheOrderOfTheCatalog() {
+        assertEquals(
+            listOf("SubRead", "Book Simulator", "honjimaku.com", "sbm Sync"),
+            MORE_APPS.take(4).map { it.name },
+        )
+        assertEquals("All projects", MORE_APPS.last().name)
+        // The catalog has 15 entries. This app is the one that is not in the list.
+        assertEquals(14, MORE_APPS.size)
+    }
+}