Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor preview list fetch mechanism #4501

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package org.wikipedia.readinglist

import android.content.Context
import android.util.Base64
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.int
import org.wikipedia.R
import org.wikipedia.WikipediaApp
import org.wikipedia.dataclient.Service
import org.wikipedia.dataclient.ServiceFactory
import org.wikipedia.dataclient.WikiSite
import org.wikipedia.dataclient.mwapi.MwQueryPage
import org.wikipedia.json.JsonUtil
import org.wikipedia.readinglist.database.ReadingList
import org.wikipedia.readinglist.database.ReadingListPage
import org.wikipedia.settings.Prefs
import org.wikipedia.util.DateUtil
import org.wikipedia.util.ImageUrlUtil
import org.wikipedia.util.StringUtil
import java.util.Date

class PreviewReadingListRepository(
private val context: Context = WikipediaApp.instance,
private val prefs: Prefs = Prefs
) {

suspend fun getPreviewReadingList(): ReadingList? {
val encodedJson = prefs.receiveReadingListsData
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if use Prefs.receiveReadingListsData directly.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've converted it to a variable so as to support constructor injection (and easily write tests later with mocks). What do you think?

if (encodedJson.isNullOrEmpty()) {
return null
}

return fetchReadingListsFromServer(encodedJson)
}

private suspend fun fetchReadingListsFromServer(encodedJson: String): ReadingList? {
val readingListData = getExportedReadingLists(encodedJson) ?: return null

val listTitle = readingListData.name.orEmpty()
.ifEmpty { context.getString(R.string.reading_lists_preview_header_title) }
val listDescription = readingListData.description.orEmpty()
.ifEmpty { DateUtil.getTimeAndDateString(context, Date()) }

val readingLists = readingListData.list
val listPages = readingLists
.map { fetchPagesForReadingList(it) }
.reduce { allPages, currentPayload -> allPages + currentPayload }
.sortedBy { it.apiTitle }

val readingList = ReadingList(listTitle, listDescription)
readingList.pages.addAll(listPages)

return readingList
}

private suspend fun fetchPagesForReadingList(
list: Map.Entry<String, Collection<JsonPrimitive>>
): List<ReadingListPage> {
val wikiSite = WikiSite.forLanguageCode(list.key)
val chunks = list.value.chunked(ReadingListsShareHelper.API_MAX_SIZE)
val pages = mutableListOf<MwQueryPage>()
for (chunk in chunks) {
pages += fetchPagesForChunk(wikiSite, chunk)
}

return pages.map { page ->
ReadingListPage(
wikiSite,
page.namespace(),
page.displayTitle(wikiSite.languageCode),
StringUtil.addUnderscores(page.title),
page.description,
ImageUrlUtil.getUrlForPreferredSize(
original = page.thumbUrl().orEmpty(),
size = Service.PREFERRED_THUMB_SIZE
),
lang = wikiSite.languageCode
)
}
}

private suspend fun fetchPagesForChunk(
wikiSite: WikiSite,
payload: List<JsonPrimitive>
): MutableList<MwQueryPage> {
val pages = mutableListOf<MwQueryPage>()
val listOfTitles = payload.filter { it.isString }.map { it.content }
val listOfIds = payload.filter { !it.isString }.map { it.int }
if (listOfIds.isNotEmpty()) {
val pagesById = ServiceFactory.get(wikiSite)
.getInfoByPageIdsOrTitles(
pageIds = listOfIds.joinToString(separator = "|")
)
.query?.pages.orEmpty()
pages.addAll(pagesById)
}
if (listOfTitles.isNotEmpty()) {
val pagesByTitles = ServiceFactory.get(wikiSite)
.getInfoByPageIdsOrTitles(titles = listOfTitles.joinToString(separator = "|"))
.query?.pages.orEmpty()
pages.addAll(pagesByTitles)
}

return pages
}

private fun getExportedReadingLists(
encodedJson: String
): ReadingListsShareHelper.ExportedReadingLists? {
return JsonUtil.decodeFromString(String(Base64.decode(encodedJson, Base64.NO_WRAP)))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class ReadingListFragment : Fragment(), MenuProvider, ReadingListItemActionsDial
private var _binding: FragmentReadingListBinding? = null
private val binding get() = _binding!!

private val previewReadingListRepository = PreviewReadingListRepository()

private lateinit var touchCallback: SwipeableItemTouchHelperCallback
private lateinit var headerView: ReadingListItemView
private var previewSaveDialog: AlertDialog? = null
Expand Down Expand Up @@ -299,21 +301,18 @@ class ReadingListFragment : Fragment(), MenuProvider, ReadingListItemActionsDial
private fun updateReadingListData() {
if (isPreview) {
if (readingList == null) {
val encodedJson = Prefs.receiveReadingListsData
if (!encodedJson.isNullOrEmpty()) {
lifecycleScope.launch(CoroutineExceptionHandler { _, throwable ->
L.e(throwable)
FeedbackUtil.showError(requireActivity(), throwable)
requireActivity().finish()
}) {
withContext(Dispatchers.Main) {
readingList = ReadingListsReceiveHelper.receiveReadingLists(requireContext(), encodedJson)
readingList?.let {
ReadingListsAnalyticsHelper.logReceivePreview(requireContext(), it)
binding.searchEmptyView.setEmptyText(getString(R.string.search_reading_list_no_results, it.title))
}
update()
lifecycleScope.launch(CoroutineExceptionHandler { _, throwable ->
L.e(throwable)
FeedbackUtil.showError(requireActivity(), throwable)
requireActivity().finish()
}) {
withContext(Dispatchers.Main) {
readingList = previewReadingListRepository.getPreviewReadingList()
readingList?.let {
ReadingListsAnalyticsHelper.logReceivePreview(requireContext(), it)
binding.searchEmptyView.setEmptyText(getString(R.string.search_reading_list_no_results, it.title))
}
update()
}
}
} else {
Expand Down

This file was deleted.

Loading