Skip to content

Commit 7df3cb6

Browse files
fix(android): resolve Hebrew lexicon scraping and add book long-press action modal
1 parent f946cd0 commit 7df3cb6

2 files changed

Lines changed: 93 additions & 7 deletions

File tree

mobile/app/src/main/java/com/bytecats/metanoia/bible/BibleManager.kt

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,31 @@ class BibleManager(private val context: Context) {
211211

212212
private fun scrapeHebrewStrong(strongs: String) {
213213
val num = strongs.filter { it.isDigit() }
214-
val request = Request.Builder().url("https://biblehub.com/hebrew/$num.htm").header("User-Agent", "Mozilla/5.0").build()
214+
val formattedStrongs = if (strongs.startsWith("H") || strongs.all { it.isDigit() }) "H$num" else strongs
215+
val request = Request.Builder().url("https://biblehub.com/hebrew/$num.htm").header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)").build()
215216
try {
216217
val response = client.newCall(request).execute()
217-
val doc = Jsoup.parse(response.body?.string() ?: return)
218-
val lemma = doc.select("span.hebrew").first()?.text()?.trim() ?: ""
218+
val html = response.body?.string() ?: return
219+
val doc = Jsoup.parse(html)
220+
val lemma = doc.select("span.hebrew, span.greek").first()?.text()?.trim() ?: ""
219221
val tr = doc.select("span.translit").first()?.text()?.trim() ?: ""
220-
var def = doc.select("div.strongsnt").text().trim()
221-
if (def.isEmpty()) { val lb = doc.select("div#leftbox").first(); lb?.select("iframe, script, ins, .vheading")?.remove(); def = lb?.text()?.trim()?.take(3000) ?: "" }
222-
if (def.isNotEmpty()) { val db = getDb(false); db.execSQL("INSERT OR REPLACE INTO lexicon (strongs, language, lemma, transliteration, definition) VALUES (?, 'hebrew', ?, ?, ?)", arrayOf(strongs, lemma, tr, def)); db.close() }
222+
var def = doc.select("div.strongsnt, div.heading, div.vheading").text().trim()
223+
if (def.isEmpty()) {
224+
val lb = doc.select("div#leftbox, div.maincontent").first()
225+
lb?.select("iframe, script, ins")?.remove()
226+
def = lb?.text()?.trim()?.take(3000) ?: ""
227+
}
228+
if (def.isEmpty()) {
229+
def = doc.body().text().take(1500)
230+
}
231+
if (def.isNotEmpty()) {
232+
val db = getDb(false)
233+
db.execSQL("INSERT OR REPLACE INTO lexicon (strongs, language, lemma, transliteration, definition) VALUES (?, 'hebrew', ?, ?, ?)", arrayOf(formattedStrongs, lemma, tr, def))
234+
if (formattedStrongs != strongs) {
235+
db.execSQL("INSERT OR REPLACE INTO lexicon (strongs, language, lemma, transliteration, definition) VALUES (?, 'hebrew', ?, ?, ?)", arrayOf(strongs, lemma, tr, def))
236+
}
237+
db.close()
238+
}
223239
} catch (e: Exception) { e.printStackTrace() }
224240
}
225241

mobile/app/src/main/java/com/bytecats/metanoia/ui/screens/BibleScreen.kt

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ fun BibleScreen(viewModel: MainViewModel) {
6868
var studyVerse by remember { mutableStateOf<Int?>(null) }
6969
var lexiconWord by remember { mutableStateOf<InterlinearWord?>(null) }
7070
var lexiconDetail by remember { mutableStateOf(Pair("", "Loading...")) }
71+
var modalBook by remember { mutableStateOf<BibleBook?>(null) }
7172
var showStudySheet by remember { mutableStateOf(false) }
7273
var showLexiconSheet by remember { mutableStateOf(false) }
7374
var isSearchVisible by remember { mutableStateOf(true) }
@@ -188,7 +189,10 @@ fun BibleScreen(viewModel: MainViewModel) {
188189
val lerpedColorInt = ReadingStats.lerpColor(baseColor, readGreen, progress)
189190
val containerColor = if (progress > 0f) Color(lerpedColorInt).copy(alpha = if (progress >= 1f) 0.35f else 0.2f) else MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.4f)
190191
Card(
191-
modifier = Modifier.padding(4.dp).height(68.dp).clickable { selectedBook = book; step = "chapter"; isSearchVisible = false },
192+
modifier = Modifier.padding(4.dp).height(68.dp).combinedClickable(
193+
onClick = { selectedBook = book; step = "chapter"; isSearchVisible = false },
194+
onLongClick = { haptic.performHapticFeedback(HapticFeedbackType.LongPress); modalBook = book }
195+
),
192196
colors = CardDefaults.cardColors(containerColor = containerColor),
193197
border = if (progress >= 1f) BorderStroke(1.5.dp, Color(0xFF9ece6a)) else if (progress > 0f) BorderStroke(1.dp, Color(0xFFe0af68).copy(0.6f)) else null
194198
) {
@@ -351,4 +355,70 @@ fun BibleScreen(viewModel: MainViewModel) {
351355
}
352356
}
353357
}
358+
359+
if (modalBook != null) {
360+
val targetBook = modalBook!!
361+
var isDownloadingBook by remember { mutableStateOf(false) }
362+
var downloadStatusText by remember { mutableStateOf("") }
363+
364+
AlertDialog(
365+
onDismissRequest = { if (!isDownloadingBook) modalBook = null },
366+
title = { Text(targetBook.name, fontWeight = FontWeight.Black, style = MaterialTheme.typography.headlineSmall, color = MaterialTheme.colorScheme.primary) },
367+
text = {
368+
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
369+
Text("${targetBook.chapters} Chapters • ${targetBook.testament} Testament • ${targetBook.textTradition.name}", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.outline)
370+
if (isDownloadingBook) {
371+
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
372+
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
373+
Text(downloadStatusText, style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.primary)
374+
}
375+
} else {
376+
Button(
377+
onClick = {
378+
selectedBook = targetBook
379+
step = "chapter"
380+
modalBook = null
381+
},
382+
modifier = Modifier.fillMaxWidth()
383+
) {
384+
Text("Open Chapter Selection")
385+
}
386+
OutlinedButton(
387+
onClick = {
388+
scope.launch {
389+
isDownloadingBook = true
390+
try {
391+
for (ch in 1..targetBook.chapters) {
392+
downloadStatusText = "Downloading Chapter $ch / ${targetBook.chapters}..."
393+
withContext(Dispatchers.IO) {
394+
bibleManager.scrapeChapter(targetBook.name, ch, settings.bibleGatewayVersion)
395+
try { bibleManager.scrapeInterlinear(targetBook.name, ch) } catch (_: Exception) {}
396+
}
397+
}
398+
downloadStatusText = "Complete!"
399+
} catch (e: Exception) {
400+
downloadStatusText = "Error: ${e.message}"
401+
} finally {
402+
isDownloadingBook = false
403+
modalBook = null
404+
}
405+
}
406+
},
407+
modifier = Modifier.fillMaxWidth()
408+
) {
409+
Icon(Icons.Default.CloudDownload, contentDescription = null, modifier = Modifier.size(18.dp))
410+
Spacer(modifier = Modifier.width(8.dp))
411+
Text("Download Entire Book")
412+
}
413+
}
414+
}
415+
},
416+
confirmButton = {},
417+
dismissButton = {
418+
if (!isDownloadingBook) {
419+
TextButton(onClick = { modalBook = null }) { Text("Close") }
420+
}
421+
}
422+
)
423+
}
354424
}

0 commit comments

Comments
 (0)