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) + } +}