Skip to content

Commit b9ea6b5

Browse files
committed
Fix confusion of search results and translations
1 parent 364dab5 commit b9ea6b5

File tree

11 files changed

+241
-85
lines changed

11 files changed

+241
-85
lines changed

app/src/main/java/com/anysoftkeyboard/janus/app/repository/TranslationRepository.kt

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.anysoftkeyboard.janus.app.repository
22

33
import com.anysoftkeyboard.janus.database.dao.TranslationDao
44
import com.anysoftkeyboard.janus.database.entities.Translation
5+
import com.anysoftkeyboard.janus.network.SearchResult
56
import com.anysoftkeyboard.janus.network.WikipediaApi
67
import kotlinx.coroutines.flow.Flow
78

@@ -13,30 +14,41 @@ open class TranslationRepository(
1314

1415
open fun getBookmarks(): Flow<List<Translation>> = translationDao.getBookmarks()
1516

16-
open suspend fun search(
17+
open suspend fun searchArticles(
1718
lang: String,
1819
term: String,
19-
): List<Translation> {
20-
val local = translationDao.findTranslation(term, lang, lang)
21-
if (local != null) return listOf(local)
22-
20+
): List<SearchResult> {
2321
val searchResponse = wikipediaApi.search(searchTerm = "$lang $term")
24-
val translations =
25-
searchResponse.query.search.map { searchResult ->
26-
Translation(
27-
sourceWord = searchResult.title,
28-
sourceLangCode = lang,
29-
sourceArticleUrl = "https://en.wikipedia.org/?curid=${searchResult.pageid}",
30-
sourceShortDescription = searchResult.snippet,
31-
sourceSummary = "summary",
32-
translatedWord = "translated",
33-
targetLangCode = "he",
34-
targetArticleUrl = "https://he.wikipedia.org/wiki/$term",
35-
targetShortDescription = "hebrew desc",
36-
targetSummary = "hebrew summary",
37-
)
38-
}
39-
translationDao.insertTranslations(translations)
40-
return translations
22+
return searchResponse.query.search ?: emptyList()
23+
}
24+
25+
open suspend fun fetchTranslation(
26+
pageId: Long,
27+
sourceLang: String,
28+
targetLang: String
29+
): Translation? {
30+
val langLinksResponse = wikipediaApi.getLangLinks(pageId)
31+
val page = langLinksResponse.query.pages.values.firstOrNull()
32+
if (page == null) return null
33+
val langLinks = page.langlinks
34+
if (langLinks == null) return null
35+
36+
val targetLink = langLinks.find { it.lang == targetLang } ?: return null
37+
38+
val translation =
39+
Translation(
40+
sourceWord = page.title,
41+
sourceLangCode = sourceLang,
42+
sourceArticleUrl = "https://en.wikipedia.org/?curid=${page.pageid}",
43+
sourceShortDescription = null,
44+
sourceSummary = null,
45+
translatedWord = targetLink.title,
46+
targetLangCode = targetLang,
47+
targetArticleUrl = "https://${targetLang}.wikipedia.org/wiki/${targetLink.title}",
48+
targetShortDescription = null,
49+
targetSummary = null,
50+
)
51+
translationDao.insertTranslation(translation)
52+
return translation
4153
}
4254
}

app/src/main/java/com/anysoftkeyboard/janus/app/ui/TranslateScreen.kt

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.anysoftkeyboard.janus.app.ui
33
import android.text.Html
44
import android.text.method.LinkMovementMethod
55
import android.widget.TextView
6+
import androidx.compose.foundation.clickable
67
import androidx.compose.foundation.layout.Arrangement
78
import androidx.compose.foundation.layout.Box
89
import androidx.compose.foundation.layout.Column
@@ -12,6 +13,8 @@ import androidx.compose.foundation.layout.fillMaxSize
1213
import androidx.compose.foundation.layout.fillMaxWidth
1314
import androidx.compose.foundation.layout.height
1415
import androidx.compose.foundation.layout.padding
16+
import androidx.compose.foundation.lazy.LazyColumn
17+
import androidx.compose.foundation.lazy.items
1518
import androidx.compose.material3.Button
1619
import androidx.compose.material3.Card
1720
import androidx.compose.material3.DropdownMenu
@@ -33,13 +36,15 @@ import androidx.compose.ui.unit.dp
3336
import androidx.compose.ui.viewinterop.AndroidView
3437
import com.anysoftkeyboard.janus.app.ui.data.UiTranslation
3538
import com.anysoftkeyboard.janus.app.viewmodels.TranslateViewModel
39+
import com.anysoftkeyboard.janus.network.SearchResult
3640

3741
@Composable
3842
fun TranslateScreen(viewModel: TranslateViewModel) {
3943
var text by remember { mutableStateOf("") }
40-
var sourceLang by remember { mutableStateOf("English") }
41-
var targetLang by remember { mutableStateOf("Spanish") }
42-
val translations by viewModel.translations.collectAsState()
44+
var sourceLang by remember { mutableStateOf("en") }
45+
var targetLang by remember { mutableStateOf("he") }
46+
val searchResults by viewModel.searchResults.collectAsState()
47+
val translation by viewModel.translation.collectAsState()
4348

4449
Column(
4550
modifier = Modifier.fillMaxSize().padding(16.dp),
@@ -61,16 +66,41 @@ fun TranslateScreen(viewModel: TranslateViewModel) {
6166
selectedLanguage = targetLang, onLanguageSelected = { targetLang = it })
6267
}
6368
Spacer(modifier = Modifier.height(16.dp))
64-
Button(onClick = { viewModel.search(sourceLang, text) }) { Text("Translate") }
69+
Button(onClick = { viewModel.searchArticles(sourceLang, text) }) { Text("Translate") }
6570
Spacer(modifier = Modifier.height(16.dp))
66-
TranslationList(translations.map { UiTranslation.fromTranslation(it) })
71+
72+
if (translation != null) {
73+
TranslationCard(UiTranslation.fromTranslation(translation!!))
74+
} else if (searchResults.isNotEmpty()) {
75+
LazyColumn {
76+
items(searchResults) { result ->
77+
SearchResultItem(result) {
78+
viewModel.fetchTranslation(result.pageid, sourceLang, targetLang)
79+
}
80+
}
81+
}
82+
}
6783
}
6884
}
6985

86+
@Composable
87+
fun SearchResultItem(result: SearchResult, onClick: () -> Unit) {
88+
Card(modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp).clickable(onClick = onClick)) {
89+
Column(modifier = Modifier.padding(16.dp)) {
90+
Text(text = result.title, style = MaterialTheme.typography.headlineSmall)
91+
AndroidView(
92+
factory = { context ->
93+
TextView(context).apply { movementMethod = LinkMovementMethod.getInstance() }
94+
},
95+
update = { it.text = Html.fromHtml(result.snippet, Html.FROM_HTML_MODE_COMPACT) })
96+
}
97+
}
98+
}
99+
70100
@Composable
71101
fun LanguageSelector(selectedLanguage: String, onLanguageSelected: (String) -> Unit) {
72102
// In a real app, you'd get this from a ViewModel
73-
val languages = listOf("English", "Spanish", "French", "German")
103+
val languages = listOf("en", "he", "fr", "de")
74104
var expanded by remember { mutableStateOf(false) }
75105

76106
Box {
@@ -103,7 +133,7 @@ fun TranslationCard(translation: UiTranslation) {
103133
TextView(context).apply { movementMethod = LinkMovementMethod.getInstance() }
104134
},
105135
update = {
106-
it.text = Html.fromHtml(translation.shortDescription, Html.FROM_HTML_MODE_COMPACT)
136+
it.text = Html.fromHtml(translation.shortDescription ?: "", Html.FROM_HTML_MODE_COMPACT)
107137
})
108138
IconButton(onClick = { /* TODO */ }) {
109139
Icon(imageVector = translation.favoriteIcon, contentDescription = "Favorite")

app/src/main/java/com/anysoftkeyboard/janus/app/viewmodels/TranslateViewModel.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.viewModelScope
55
import com.anysoftkeyboard.janus.app.repository.TranslationRepository
66
import com.anysoftkeyboard.janus.database.entities.Translation
7+
import com.anysoftkeyboard.janus.network.SearchResult
78
import dagger.hilt.android.lifecycle.HiltViewModel
89
import javax.inject.Inject
910
import kotlinx.coroutines.flow.MutableStateFlow
@@ -13,10 +14,22 @@ import kotlinx.coroutines.launch
1314
@HiltViewModel
1415
class TranslateViewModel @Inject constructor(private val repository: TranslationRepository) :
1516
ViewModel() {
16-
private val _translations = MutableStateFlow<List<Translation>>(emptyList())
17-
val translations: StateFlow<List<Translation>> = _translations
17+
private val _searchResults = MutableStateFlow<List<SearchResult>>(emptyList())
18+
val searchResults: StateFlow<List<SearchResult>> = _searchResults
1819

19-
fun search(lang: String, term: String) {
20-
viewModelScope.launch { _translations.value = repository.search(lang, term) }
20+
private val _translation = MutableStateFlow<Translation?>(null)
21+
val translation: StateFlow<Translation?> = _translation
22+
23+
fun searchArticles(lang: String, term: String) {
24+
viewModelScope.launch {
25+
_searchResults.value = repository.searchArticles(lang, term)
26+
_translation.value = null
27+
}
28+
}
29+
30+
fun fetchTranslation(pageId: Long, sourceLang: String, targetLang: String) {
31+
viewModelScope.launch {
32+
_translation.value = repository.fetchTranslation(pageId, sourceLang, targetLang)
33+
}
2134
}
2235
}

app/src/test/java/com/anysoftkeyboard/janus/app/repository/FakeTranslationRepository.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.anysoftkeyboard.janus.app.repository
22

33
import com.anysoftkeyboard.janus.database.dao.TranslationDao
44
import com.anysoftkeyboard.janus.database.entities.Translation
5+
import com.anysoftkeyboard.janus.network.SearchResult
56
import com.anysoftkeyboard.janus.network.WikipediaApi
67
import javax.inject.Inject
78
import kotlinx.coroutines.flow.Flow
@@ -15,14 +16,23 @@ constructor(private val translationDao: TranslationDao, private val wikipediaApi
1516

1617
private val _history = MutableStateFlow(emptyList<Translation>())
1718
private val _bookmarks = MutableStateFlow(emptyList<Translation>())
18-
var nextTranslations: List<Translation> = emptyList()
19+
var nextSearchResults: List<SearchResult> = emptyList()
20+
var nextTranslation: Translation? = null
1921

2022
override fun getHistory(): Flow<List<Translation>> = _history.asStateFlow()
2123

2224
override fun getBookmarks(): Flow<List<Translation>> = _bookmarks.asStateFlow()
2325

24-
override suspend fun search(lang: String, term: String): List<Translation> {
25-
return nextTranslations
26+
override suspend fun searchArticles(lang: String, term: String): List<SearchResult> {
27+
return nextSearchResults
28+
}
29+
30+
override suspend fun fetchTranslation(
31+
pageId: Long,
32+
sourceLang: String,
33+
targetLang: String
34+
): Translation? {
35+
return nextTranslation
2636
}
2737

2838
fun setHistory(history: List<Translation>) {
Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.anysoftkeyboard.janus.app.repository
22

33
import com.anysoftkeyboard.janus.database.dao.TranslationDao
4-
import com.anysoftkeyboard.janus.database.entities.Translation
54
import com.anysoftkeyboard.janus.network.ContinueData
5+
import com.anysoftkeyboard.janus.network.LangLink
6+
import com.anysoftkeyboard.janus.network.LangLinksQuery
7+
import com.anysoftkeyboard.janus.network.LangLinksResponse
8+
import com.anysoftkeyboard.janus.network.PageLangLinks
69
import com.anysoftkeyboard.janus.network.Query
710
import com.anysoftkeyboard.janus.network.SearchInfo
811
import com.anysoftkeyboard.janus.network.SearchResponse
@@ -11,11 +14,11 @@ import com.anysoftkeyboard.janus.network.WikipediaApi
1114
import kotlinx.coroutines.ExperimentalCoroutinesApi
1215
import kotlinx.coroutines.test.runTest
1316
import org.junit.Assert.assertEquals
17+
import org.junit.Assert.assertNotNull
1418
import org.junit.Before
1519
import org.junit.Test
1620
import org.mockito.kotlin.any
1721
import org.mockito.kotlin.mock
18-
import org.mockito.kotlin.never
1922
import org.mockito.kotlin.verify
2023
import org.mockito.kotlin.whenever
2124

@@ -34,32 +37,7 @@ class TranslationRepositoryTest {
3437
}
3538

3639
@Test
37-
fun `test search, term in db`() = runTest {
38-
val term = "term"
39-
val lang = "en"
40-
val translation =
41-
Translation(
42-
sourceWord = term,
43-
sourceLangCode = lang,
44-
targetLangCode = lang,
45-
sourceArticleUrl = "",
46-
sourceShortDescription = "",
47-
sourceSummary = "",
48-
translatedWord = "",
49-
targetArticleUrl = "",
50-
targetShortDescription = "",
51-
targetSummary = "")
52-
whenever(translationDao.findTranslation(term, lang, lang)).thenReturn(translation)
53-
54-
val result = repository.search(lang, term)
55-
56-
assertEquals(listOf(translation), result)
57-
verify(wikipediaApi, never()).search("$lang $term")
58-
verify(translationDao, never()).insertTranslations(any())
59-
}
60-
61-
@Test
62-
fun `test search, term not in db`() = runTest {
40+
fun `test searchArticles`() = runTest {
6341
val term = "term"
6442
val lang = "en"
6543
val searchResult =
@@ -81,15 +59,34 @@ class TranslationRepositoryTest {
8159
continueData = ContinueData(sroffset = 1, continueVal = "-|||"),
8260
query = query)
8361

84-
whenever(translationDao.findTranslation(term, lang, lang)).thenReturn(null)
8562
whenever(wikipediaApi.search(searchTerm = "$lang $term")).thenReturn(searchResponse)
8663

87-
val result = repository.search(lang, term)
64+
val result = repository.searchArticles(lang, term)
8865

8966
assertEquals(1, result.size)
90-
assertEquals("title", result[0].sourceWord)
91-
assertEquals(lang, result[0].sourceLangCode)
92-
assertEquals("snippet", result[0].sourceShortDescription)
93-
verify(translationDao).insertTranslations(any())
67+
assertEquals("title", result[0].title)
68+
}
69+
70+
@Test
71+
fun `test fetchTranslation`() = runTest {
72+
val pageId = 1L
73+
val sourceLang = "en"
74+
val targetLang = "he"
75+
val langLink = LangLink(lang = targetLang, title = "כותרת")
76+
val pageLangLinks =
77+
PageLangLinks(pageid = pageId, ns = 0, title = "title", langlinks = listOf(langLink))
78+
val langLinksQuery = LangLinksQuery(pages = mapOf(pageId.toString() to pageLangLinks))
79+
val langLinksResponse = LangLinksResponse(query = langLinksQuery)
80+
81+
whenever(wikipediaApi.getLangLinks(pageId)).thenReturn(langLinksResponse)
82+
83+
val result = repository.fetchTranslation(pageId, sourceLang, targetLang)
84+
85+
assertNotNull(result)
86+
assertEquals("title", result!!.sourceWord)
87+
assertEquals(sourceLang, result.sourceLangCode)
88+
assertEquals("כותרת", result.translatedWord)
89+
assertEquals(targetLang, result.targetLangCode)
90+
verify(translationDao).insertTranslation(any())
9491
}
9592
}

0 commit comments

Comments
 (0)