From b2a0d981922dd4f58c2e9e025d368bac7976467d Mon Sep 17 00:00:00 2001 From: cooltey Date: Tue, 6 Aug 2024 16:38:26 -0700 Subject: [PATCH 01/99] Initial commit --- .../wikipedia/views/RecommendedContentView.kt | 16 +++++++ ...tem_recommended_content_search_history.xml | 26 ++++++++++ .../res/layout/view_recommended_content.xml | 30 ++++++++++++ .../view_recommended_content_section.xml | 48 +++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 app/src/main/java/org/wikipedia/views/RecommendedContentView.kt create mode 100644 app/src/main/res/layout/item_recommended_content_search_history.xml create mode 100644 app/src/main/res/layout/view_recommended_content.xml create mode 100644 app/src/main/res/layout/view_recommended_content_section.xml diff --git a/app/src/main/java/org/wikipedia/views/RecommendedContentView.kt b/app/src/main/java/org/wikipedia/views/RecommendedContentView.kt new file mode 100644 index 00000000000..14d2075318a --- /dev/null +++ b/app/src/main/java/org/wikipedia/views/RecommendedContentView.kt @@ -0,0 +1,16 @@ +package org.wikipedia.views + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import org.wikipedia.databinding.ViewSearchEmptyBinding + +class RecommendedContentView(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) { + + private val binding = ViewSearchEmptyBinding.inflate(LayoutInflater.from(context), this) + + init { + orientation = VERTICAL + } +} diff --git a/app/src/main/res/layout/item_recommended_content_search_history.xml b/app/src/main/res/layout/item_recommended_content_search_history.xml new file mode 100644 index 00000000000..02998e3e38f --- /dev/null +++ b/app/src/main/res/layout/item_recommended_content_search_history.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/app/src/main/res/layout/view_recommended_content.xml b/app/src/main/res/layout/view_recommended_content.xml new file mode 100644 index 00000000000..9a223c9b669 --- /dev/null +++ b/app/src/main/res/layout/view_recommended_content.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/view_recommended_content_section.xml b/app/src/main/res/layout/view_recommended_content_section.xml new file mode 100644 index 00000000000..2ccff71fbe1 --- /dev/null +++ b/app/src/main/res/layout/view_recommended_content_section.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + From c384172bcc1e6f7767e8e9f1d0df216ea6a7956f Mon Sep 17 00:00:00 2001 From: cooltey Date: Wed, 7 Aug 2024 15:51:14 -0700 Subject: [PATCH 02/99] More layout included --- .../item_recommended_content_section_text.xml | 11 ++++++++ .../item_recommended_content_tab_text.xml | 17 ++++++++++++ .../res/layout/view_recommended_content.xml | 11 ++++++++ .../view_recommended_content_section.xml | 1 - .../layout/view_recommended_content_tab.xml | 26 +++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/layout/item_recommended_content_section_text.xml create mode 100644 app/src/main/res/layout/item_recommended_content_tab_text.xml create mode 100644 app/src/main/res/layout/view_recommended_content_tab.xml diff --git a/app/src/main/res/layout/item_recommended_content_section_text.xml b/app/src/main/res/layout/item_recommended_content_section_text.xml new file mode 100644 index 00000000000..7301334d3f5 --- /dev/null +++ b/app/src/main/res/layout/item_recommended_content_section_text.xml @@ -0,0 +1,11 @@ + + diff --git a/app/src/main/res/layout/item_recommended_content_tab_text.xml b/app/src/main/res/layout/item_recommended_content_tab_text.xml new file mode 100644 index 00000000000..4a13b0e1c53 --- /dev/null +++ b/app/src/main/res/layout/item_recommended_content_tab_text.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/app/src/main/res/layout/view_recommended_content.xml b/app/src/main/res/layout/view_recommended_content.xml index 9a223c9b669..710e81ea6ee 100644 --- a/app/src/main/res/layout/view_recommended_content.xml +++ b/app/src/main/res/layout/view_recommended_content.xml @@ -21,6 +21,17 @@ android:textColor="?attr/progressive_color" android:layout_marginVertical="16dp"/> + + diff --git a/app/src/main/res/layout/view_recommended_content_tab.xml b/app/src/main/res/layout/view_recommended_content_tab.xml new file mode 100644 index 00000000000..2626816be59 --- /dev/null +++ b/app/src/main/res/layout/view_recommended_content_tab.xml @@ -0,0 +1,26 @@ + + + + + + + + From b00f13943a63538b33aad25836dc7c287213a686 Mon Sep 17 00:00:00 2001 From: cooltey Date: Wed, 7 Aug 2024 16:26:58 -0700 Subject: [PATCH 03/99] Add package and view --- .../RecommendedContentView.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt new file mode 100644 index 00000000000..8d944c07382 --- /dev/null +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt @@ -0,0 +1,18 @@ +package org.wikipedia.recommendedcontent + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.LinearLayout +import org.wikipedia.databinding.ViewRecommendedContentBinding +import org.wikipedia.util.DimenUtil + +class RecommendedContentView(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) { + private val binding = ViewRecommendedContentBinding.inflate(LayoutInflater.from(context), this) + + init { + layoutParams = ViewGroup.LayoutParams(DimenUtil.roundedDpToPx(48.0f), ViewGroup.LayoutParams.MATCH_PARENT) + orientation = VERTICAL + } +} From a35a7b6080ce29bafab5d0d3e34bd9f81ffba9fd Mon Sep 17 00:00:00 2001 From: cooltey Date: Wed, 7 Aug 2024 17:08:59 -0700 Subject: [PATCH 04/99] Create functions in helper --- .../history/db/HistoryEntryWithImageDao.kt | 18 ++-- .../RecommendedContentHelper.kt | 91 +++++++++++++++++++ .../RecommendedContentView.kt | 3 +- .../res/layout/view_recommended_content.xml | 1 + 4 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt diff --git a/app/src/main/java/org/wikipedia/history/db/HistoryEntryWithImageDao.kt b/app/src/main/java/org/wikipedia/history/db/HistoryEntryWithImageDao.kt index d29620cd79e..a1bca8b6d05 100644 --- a/app/src/main/java/org/wikipedia/history/db/HistoryEntryWithImageDao.kt +++ b/app/src/main/java/org/wikipedia/history/db/HistoryEntryWithImageDao.kt @@ -41,14 +41,13 @@ interface HistoryEntryWithImageDao { else SearchResults(entries.take(3).map { SearchResult(toHistoryEntry(it).title, SearchResult.SearchResultType.HISTORY) }.toMutableList()) } + fun filterHistoryItemsWithoutTime(searchQuery: String): List { + return findEntriesBySearchTerm("%${normalizedQuery(searchQuery)}%").map { toHistoryEntry(it) } + } + fun filterHistoryItems(searchQuery: String): List { val list = mutableListOf() - val normalizedQuery = StringUtils.stripAccents(searchQuery).lowercase(Locale.getDefault()) - .replace("\\", "\\\\") - .replace("%", "\\%") - .replace("_", "\\_") - - val entries = findEntriesBySearchTerm("%$normalizedQuery%") + val entries = findEntriesBySearchTerm("%${normalizedQuery(searchQuery)}%") for (i in entries.indices) { // Check the previous item, see if the times differ enough @@ -78,6 +77,13 @@ interface HistoryEntryWithImageDao { return entries.map { toHistoryEntry(it) } } + private fun normalizedQuery(searchQuery: String): String { + return StringUtils.stripAccents(searchQuery).lowercase(Locale.getDefault()) + .replace("\\", "\\\\") + .replace("%", "\\%") + .replace("_", "\\_") + } + private fun toHistoryEntry(entryWithImage: HistoryEntryWithImage): HistoryEntry { val entry = HistoryEntry(entryWithImage.authority, entryWithImage.lang, entryWithImage.apiTitle, entryWithImage.displayTitle, 0, entryWithImage.namespace, entryWithImage.timestamp, diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt new file mode 100644 index 00000000000..4fe4c32058f --- /dev/null +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt @@ -0,0 +1,91 @@ +package org.wikipedia.recommendedcontent + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.withContext +import org.wikipedia.Constants +import org.wikipedia.WikipediaApp +import org.wikipedia.database.AppDatabase +import org.wikipedia.dataclient.ServiceFactory +import org.wikipedia.dataclient.WikiSite +import org.wikipedia.dataclient.page.PageSummary +import org.wikipedia.feed.aggregated.AggregatedFeedContent +import org.wikipedia.feed.topread.TopRead +import org.wikipedia.page.PageTitle +import org.wikipedia.util.DateUtil +import org.wikipedia.util.StringUtil + +object RecommendedContentHelper { + + suspend fun loadHistoryItems(): List { + return withContext(Dispatchers.IO) { + AppDatabase.instance.historyEntryWithImageDao().filterHistoryItemsWithoutTime("").map { + it.title + } + } + } + + suspend fun loadRecentSearches(): List { + return withContext(Dispatchers.IO) { + AppDatabase.instance.recentSearchDao().getRecentSearches().map { + PageTitle(it.text, WikipediaApp.instance.wikiSite) + } + } + } + + suspend fun loadTopRead(): List { + return withContext(Dispatchers.IO) { + val wikiSite = WikipediaApp.instance.wikiSite + val hasParentLanguageCode = !WikipediaApp.instance.languageState.getDefaultLanguageCode(wikiSite.languageCode).isNullOrEmpty() + val date = DateUtil.getUtcRequestDateFor(0) + var feedContentResponse = ServiceFactory.getRest(wikiSite).getFeedFeatured(date.year, date.month, date.day) + if (hasParentLanguageCode) { + feedContentResponse.topRead?.let { + val topReadResponse = getPagesForLanguageVariant(it.articles, wikiSite) + feedContentResponse = AggregatedFeedContent( + tfa = feedContentResponse.tfa, + news = feedContentResponse.news, + topRead = TopRead(it.date, topReadResponse), + potd = feedContentResponse.potd, + onthisday = feedContentResponse.onthisday + ) + } + } + feedContentResponse.topRead?.articles?.map { it.getPageTitle(wikiSite) } ?: emptyList() + } + } + + // TODO: borrowed from FeedClient. Refactor this method to be more generic. + private suspend fun getPagesForLanguageVariant(list: List, wikiSite: WikiSite): List { + val newList = mutableListOf() + withContext(Dispatchers.IO) { + val titles = list.joinToString(separator = "|") { it.apiTitle } + // First, get the correct description from Wikidata directly. + val wikiDataResponse = async { + ServiceFactory.get(Constants.wikidataWikiSite) + .getWikidataDescription(titles = titles, sites = wikiSite.dbName(), langCode = wikiSite.languageCode) + } + // Second, fetch varianttitles from prop=info endpoint. + val mwQueryResponse = async { + ServiceFactory.get(wikiSite).getVariantTitlesByTitles(titles) + } + + list.forEach { pageSummary -> + // Find the correct display title from the varianttitles map, and insert the new page summary to the list. + val displayTitle = mwQueryResponse.await().query?.pages?.find { StringUtil.addUnderscores(it.title) == pageSummary.apiTitle }?.varianttitles?.get(wikiSite.languageCode) + val newPageSummary = pageSummary.apply { + val newDisplayTitle = displayTitle ?: pageSummary.displayTitle + this.titles = PageSummary.Titles( + canonical = pageSummary.apiTitle, + display = newDisplayTitle + ) + this.description = wikiDataResponse.await().entities.values.firstOrNull { + it.labels[wikiSite.languageCode]?.value == newDisplayTitle + }?.descriptions?.get(wikiSite.languageCode)?.value ?: pageSummary.description + } + newList.add(newPageSummary) + } + } + return newList + } +} diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt index 8d944c07382..af8a10a6a16 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt @@ -6,13 +6,12 @@ import android.view.LayoutInflater import android.view.ViewGroup import android.widget.LinearLayout import org.wikipedia.databinding.ViewRecommendedContentBinding -import org.wikipedia.util.DimenUtil class RecommendedContentView(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) { private val binding = ViewRecommendedContentBinding.inflate(LayoutInflater.from(context), this) init { - layoutParams = ViewGroup.LayoutParams(DimenUtil.roundedDpToPx(48.0f), ViewGroup.LayoutParams.MATCH_PARENT) + layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) orientation = VERTICAL } } diff --git a/app/src/main/res/layout/view_recommended_content.xml b/app/src/main/res/layout/view_recommended_content.xml index 710e81ea6ee..94878e8cf78 100644 --- a/app/src/main/res/layout/view_recommended_content.xml +++ b/app/src/main/res/layout/view_recommended_content.xml @@ -25,6 +25,7 @@ android:id="@+id/recommendedContentTabLayout" android:layout_width="match_parent" android:layout_height="wrap_content" + android:visibility="gone" app:tabTextAppearance="@style/H3.Button" app:tabTextColor="?attr/placeholder_color" app:tabIndicatorFullWidth="true" From fc8a15104c1c594a2ac552cdac1fdaf52c95e10c Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 8 Aug 2024 15:05:59 -0700 Subject: [PATCH 05/99] Add more methods --- .../RecommendedContentHelper.kt | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt index 4fe4c32058f..73c060b5f37 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt @@ -17,6 +17,9 @@ import org.wikipedia.util.StringUtil object RecommendedContentHelper { + // TODO: introduce cache for these methods + // TODO: think about all PageSummary vs PageTitle. + suspend fun loadHistoryItems(): List { return withContext(Dispatchers.IO) { AppDatabase.instance.historyEntryWithImageDao().filterHistoryItemsWithoutTime("").map { @@ -33,7 +36,7 @@ object RecommendedContentHelper { } } - suspend fun loadTopRead(): List { + suspend fun loadFeed(): AggregatedFeedContent { return withContext(Dispatchers.IO) { val wikiSite = WikipediaApp.instance.wikiSite val hasParentLanguageCode = !WikipediaApp.instance.languageState.getDefaultLanguageCode(wikiSite.languageCode).isNullOrEmpty() @@ -51,8 +54,32 @@ object RecommendedContentHelper { ) } } - feedContentResponse.topRead?.articles?.map { it.getPageTitle(wikiSite) } ?: emptyList() + feedContentResponse + } + } + + suspend fun loadTopRead(): List { + return loadFeed().topRead?.articles ?: emptyList() + } + + suspend fun loadMoreLike(searchTerm: String): List { + // TODO: single search term vs multiple search terms. + return withContext(Dispatchers.IO) { + val wikiSite = WikipediaApp.instance.wikiSite + val moreLikeResponse = ServiceFactory.get(wikiSite).searchMoreLike("morelike:$searchTerm", Constants.SUGGESTION_REQUEST_ITEMS, Constants.SUGGESTION_REQUEST_ITEMS) + val hasParentLanguageCode = !WikipediaApp.instance.languageState.getDefaultLanguageCode(wikiSite.languageCode).isNullOrEmpty() + + val list = moreLikeResponse.query?.pages?.map { + PageSummary(it.displayTitle(wikiSite.languageCode), it.title, it.description, it.extract, it.thumbUrl(), wikiSite.languageCode) + } ?: emptyList() + + if (hasParentLanguageCode) { + getPagesForLanguageVariant(list, wikiSite) + } else { + list + } } + } // TODO: borrowed from FeedClient. Refactor this method to be more generic. From 4c8f98a5cc57fd4344dd91b5c57b477da6be62f4 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 8 Aug 2024 15:46:05 -0700 Subject: [PATCH 06/99] Add functions --- .../RecommendedContentHelper.kt | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt index 73c060b5f37..bf29e121693 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt @@ -4,15 +4,20 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.withContext import org.wikipedia.Constants +import org.wikipedia.R import org.wikipedia.WikipediaApp import org.wikipedia.database.AppDatabase import org.wikipedia.dataclient.ServiceFactory import org.wikipedia.dataclient.WikiSite +import org.wikipedia.dataclient.page.NearbyPage import org.wikipedia.dataclient.page.PageSummary import org.wikipedia.feed.aggregated.AggregatedFeedContent import org.wikipedia.feed.topread.TopRead import org.wikipedia.page.PageTitle +import org.wikipedia.places.PlacesFragment +import org.wikipedia.settings.Prefs import org.wikipedia.util.DateUtil +import org.wikipedia.util.ImageUrlUtil import org.wikipedia.util.StringUtil object RecommendedContentHelper { @@ -62,7 +67,7 @@ object RecommendedContentHelper { return loadFeed().topRead?.articles ?: emptyList() } - suspend fun loadMoreLike(searchTerm: String): List { + suspend fun loadExplore(searchTerm: String): List { // TODO: single search term vs multiple search terms. return withContext(Dispatchers.IO) { val wikiSite = WikipediaApp.instance.wikiSite @@ -82,6 +87,38 @@ object RecommendedContentHelper { } + suspend fun loadBecauseYouRead(age: Int): List { + return withContext(Dispatchers.IO) { + val entry = AppDatabase.instance.historyEntryWithImageDao().findEntryForReadMore(age, WikipediaApp.instance.resources.getInteger( + R.integer.article_engagement_threshold_sec)).last() + loadExplore(entry.title.prefixedText) + } + } + + suspend fun loadContinueReading(): List { + return withContext(Dispatchers.IO) { + WikipediaApp.instance.tabList.mapNotNull { it.backStackPositionTitle } + } + } + + suspend fun loadPlaces(): List { + val wikiSite = WikipediaApp.instance.wikiSite + return withContext(Dispatchers.IO) { + Prefs.placesLastLocationAndZoomLevel?.let { pair -> + val location = pair.first + val response = ServiceFactory.get(wikiSite).getGeoSearch("${location.latitude}|${location.longitude}", 10000, 10, 10) + val nearbyPages = response.query?.pages.orEmpty() + .filter { it.coordinates != null} + .map { + NearbyPage(it.pageId, PageTitle(it.title, wikiSite, + if (it.thumbUrl().isNullOrEmpty()) null else ImageUrlUtil.getUrlForPreferredSize(it.thumbUrl()!!, PlacesFragment.THUMB_SIZE), + it.description, it.displayTitle(wikiSite.languageCode)), it.coordinates!![0].lat, it.coordinates[0].lon) + } + nearbyPages + } ?: emptyList() + } + } + // TODO: borrowed from FeedClient. Refactor this method to be more generic. private suspend fun getPagesForLanguageVariant(list: List, wikiSite: WikiSite): List { val newList = mutableListOf() From 9dc08622064e8760f3a24ff2e9e08becfb41b84c Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 8 Aug 2024 16:02:08 -0700 Subject: [PATCH 07/99] Lint fix --- .../RecommendedContentHelper.kt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt index bf29e121693..cfb83f17428 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt @@ -84,7 +84,6 @@ object RecommendedContentHelper { list } } - } suspend fun loadBecauseYouRead(age: Int): List { @@ -108,7 +107,7 @@ object RecommendedContentHelper { val location = pair.first val response = ServiceFactory.get(wikiSite).getGeoSearch("${location.latitude}|${location.longitude}", 10000, 10, 10) val nearbyPages = response.query?.pages.orEmpty() - .filter { it.coordinates != null} + .filter { it.coordinates != null } .map { NearbyPage(it.pageId, PageTitle(it.title, wikiSite, if (it.thumbUrl().isNullOrEmpty()) null else ImageUrlUtil.getUrlForPreferredSize(it.thumbUrl()!!, PlacesFragment.THUMB_SIZE), @@ -119,6 +118,20 @@ object RecommendedContentHelper { } } + suspend fun loadRandomArticles(): List { + // TODO: define how many random articles to load. + return withContext(Dispatchers.IO) { + val wikiSite = WikipediaApp.instance.wikiSite + val list = mutableListOf() + repeat(5) { + val response = ServiceFactory.getRest(wikiSite).getRandomSummary() + list.add(response) + } + // make sure the list is distinct + list.distinct() + } + } + // TODO: borrowed from FeedClient. Refactor this method to be more generic. private suspend fun getPagesForLanguageVariant(list: List, wikiSite: WikiSite): List { val newList = mutableListOf() From 3db9245d05db66d16c0e5250273b322696975fe6 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 8 Aug 2024 16:30:26 -0700 Subject: [PATCH 08/99] Use fragment instead of view --- .../RecommendedContentFragment.kt | 52 +++++++++++++++++++ .../RecommendedContentView.kt | 17 ------ ...lper.kt => RecommendedContentViewModel.kt} | 28 ++++++++-- ...t.xml => fragment_recommended_content.xml} | 11 ++-- 4 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt delete mode 100644 app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt rename app/src/main/java/org/wikipedia/recommendedcontent/{RecommendedContentHelper.kt => RecommendedContentViewModel.kt} (87%) rename app/src/main/res/layout/{view_recommended_content.xml => fragment_recommended_content.xml} (85%) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt new file mode 100644 index 00000000000..23ea21daf0a --- /dev/null +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -0,0 +1,52 @@ +package org.wikipedia.recommendedcontent + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.launch +import org.wikipedia.Constants +import org.wikipedia.databinding.FragmentRecommendedContentBinding +import org.wikipedia.dataclient.WikiSite + +class RecommendedContentFragment: Fragment() { + private var _binding: FragmentRecommendedContentBinding? = null + private val binding get() = _binding!! + private val viewModel: RecommendedContentViewModel by viewModels { RecommendedContentViewModel.Factory(requireArguments()) } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + super.onCreateView(inflater, container, savedInstanceState) + + _binding = FragmentRecommendedContentBinding.inflate(inflater, container, false) + val view = binding.root + + + lifecycleScope.launch { + // TODO + } + + return view + } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } + + companion object { + const val ARG_IN_HISTORY = "inHistory" + const val ARG_SHOW_TABS = "showTabs" + + fun newInstance(wikiSite: WikiSite, inHistory: Boolean, showTabs: Boolean) = RecommendedContentFragment().apply { + arguments = bundleOf( + Constants.ARG_WIKISITE to wikiSite, + ARG_IN_HISTORY to inHistory, + ARG_SHOW_TABS to showTabs + ) + } + } +} diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt deleted file mode 100644 index af8a10a6a16..00000000000 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentView.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.wikipedia.recommendedcontent - -import android.content.Context -import android.util.AttributeSet -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.LinearLayout -import org.wikipedia.databinding.ViewRecommendedContentBinding - -class RecommendedContentView(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs) { - private val binding = ViewRecommendedContentBinding.inflate(LayoutInflater.from(context), this) - - init { - layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - orientation = VERTICAL - } -} diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt similarity index 87% rename from app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt rename to app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index cfb83f17428..3f7c27002bd 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentHelper.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -1,7 +1,13 @@ package org.wikipedia.recommendedcontent +import android.os.Bundle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.withContext import org.wikipedia.Constants import org.wikipedia.R @@ -11,6 +17,7 @@ import org.wikipedia.dataclient.ServiceFactory import org.wikipedia.dataclient.WikiSite import org.wikipedia.dataclient.page.NearbyPage import org.wikipedia.dataclient.page.PageSummary +import org.wikipedia.extensions.parcelable import org.wikipedia.feed.aggregated.AggregatedFeedContent import org.wikipedia.feed.topread.TopRead import org.wikipedia.page.PageTitle @@ -18,12 +25,20 @@ import org.wikipedia.places.PlacesFragment import org.wikipedia.settings.Prefs import org.wikipedia.util.DateUtil import org.wikipedia.util.ImageUrlUtil +import org.wikipedia.util.Resource import org.wikipedia.util.StringUtil -object RecommendedContentHelper { +class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { - // TODO: introduce cache for these methods - // TODO: think about all PageSummary vs PageTitle. + private val handler = CoroutineExceptionHandler { _, throwable -> + _uiState.value = Resource.Error(throwable) + } + val wikiSite: WikiSite = bundle.parcelable(Constants.ARG_WIKISITE)!! + val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) + val showTabs = bundle.getBoolean(RecommendedContentFragment.ARG_SHOW_TABS) + + private val _uiState = MutableStateFlow(Resource()) + val uiState = _uiState.asStateFlow() suspend fun loadHistoryItems(): List { return withContext(Dispatchers.IO) { @@ -165,4 +180,11 @@ object RecommendedContentHelper { } return newList } + + class Factory(private val bundle: Bundle) : ViewModelProvider.Factory { + @Suppress("unchecked_cast") + override fun create(modelClass: Class): T { + return RecommendedContentViewModel(bundle) as T + } + } } diff --git a/app/src/main/res/layout/view_recommended_content.xml b/app/src/main/res/layout/fragment_recommended_content.xml similarity index 85% rename from app/src/main/res/layout/view_recommended_content.xml rename to app/src/main/res/layout/fragment_recommended_content.xml index 94878e8cf78..72b73a8087f 100644 --- a/app/src/main/res/layout/view_recommended_content.xml +++ b/app/src/main/res/layout/fragment_recommended_content.xml @@ -1,11 +1,10 @@ - + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> - + From 2459cdaec8a9580ea3ea68169c91a0d5bcc62486 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 8 Aug 2024 16:31:35 -0700 Subject: [PATCH 09/99] Fix lint --- .../recommendedcontent/RecommendedContentFragment.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index 23ea21daf0a..8f1699679f2 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -13,7 +13,7 @@ import org.wikipedia.Constants import org.wikipedia.databinding.FragmentRecommendedContentBinding import org.wikipedia.dataclient.WikiSite -class RecommendedContentFragment: Fragment() { +class RecommendedContentFragment : Fragment() { private var _binding: FragmentRecommendedContentBinding? = null private val binding get() = _binding!! private val viewModel: RecommendedContentViewModel by viewModels { RecommendedContentViewModel.Factory(requireArguments()) } @@ -22,14 +22,12 @@ class RecommendedContentFragment: Fragment() { super.onCreateView(inflater, container, savedInstanceState) _binding = FragmentRecommendedContentBinding.inflate(inflater, container, false) - val view = binding.root - lifecycleScope.launch { // TODO } - return view + return binding.root } override fun onDestroyView() { From 0fef0461f9599ec59b132dd2790472254e782c1a Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 8 Aug 2024 16:42:37 -0700 Subject: [PATCH 10/99] ViewModel --- .../RecommendedContentViewModel.kt | 53 +++++++++++++------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index 3f7c27002bd..30696e090f8 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -3,11 +3,13 @@ package org.wikipedia.recommendedcontent import android.os.Bundle import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.wikipedia.Constants import org.wikipedia.R @@ -30,17 +32,38 @@ import org.wikipedia.util.StringUtil class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { - private val handler = CoroutineExceptionHandler { _, throwable -> - _uiState.value = Resource.Error(throwable) - } val wikiSite: WikiSite = bundle.parcelable(Constants.ARG_WIKISITE)!! - val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) + private val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) val showTabs = bundle.getBoolean(RecommendedContentFragment.ARG_SHOW_TABS) - private val _uiState = MutableStateFlow(Resource()) - val uiState = _uiState.asStateFlow() + private val _historyState = MutableStateFlow(Resource>()) + val historyState = _historyState.asStateFlow() + + private val _recommendedContentState = MutableStateFlow(Resource>()) + val recommendedContentState = _recommendedContentState.asStateFlow() + + fun loadSearchHistory() { + viewModelScope.launch(CoroutineExceptionHandler { _, throwable -> + _historyState.value = Resource.Error(throwable) + }) { + if (inHistory) { + _historyState.value = Resource.Success(loadHistoryItems()) + } else { + _historyState.value = Resource.Success(loadRecentSearches()) + } + } + } + + // TODO: think about modulating this method. + fun loadRecommendedContent(searchTerm: String) { + viewModelScope.launch(CoroutineExceptionHandler { _, throwable -> + _recommendedContentState.value = Resource.Error(throwable) + }) { +// _recommendedContentState.value = Resource.Success(loadRecommendedContent(searchTerm)) + } + } - suspend fun loadHistoryItems(): List { + private suspend fun loadHistoryItems(): List { return withContext(Dispatchers.IO) { AppDatabase.instance.historyEntryWithImageDao().filterHistoryItemsWithoutTime("").map { it.title @@ -48,7 +71,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - suspend fun loadRecentSearches(): List { + private suspend fun loadRecentSearches(): List { return withContext(Dispatchers.IO) { AppDatabase.instance.recentSearchDao().getRecentSearches().map { PageTitle(it.text, WikipediaApp.instance.wikiSite) @@ -56,7 +79,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - suspend fun loadFeed(): AggregatedFeedContent { + private suspend fun loadFeed(): AggregatedFeedContent { return withContext(Dispatchers.IO) { val wikiSite = WikipediaApp.instance.wikiSite val hasParentLanguageCode = !WikipediaApp.instance.languageState.getDefaultLanguageCode(wikiSite.languageCode).isNullOrEmpty() @@ -78,11 +101,11 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - suspend fun loadTopRead(): List { + private suspend fun loadTopRead(): List { return loadFeed().topRead?.articles ?: emptyList() } - suspend fun loadExplore(searchTerm: String): List { + private suspend fun loadExplore(searchTerm: String): List { // TODO: single search term vs multiple search terms. return withContext(Dispatchers.IO) { val wikiSite = WikipediaApp.instance.wikiSite @@ -101,7 +124,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - suspend fun loadBecauseYouRead(age: Int): List { + private suspend fun loadBecauseYouRead(age: Int): List { return withContext(Dispatchers.IO) { val entry = AppDatabase.instance.historyEntryWithImageDao().findEntryForReadMore(age, WikipediaApp.instance.resources.getInteger( R.integer.article_engagement_threshold_sec)).last() @@ -109,13 +132,13 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - suspend fun loadContinueReading(): List { + private suspend fun loadContinueReading(): List { return withContext(Dispatchers.IO) { WikipediaApp.instance.tabList.mapNotNull { it.backStackPositionTitle } } } - suspend fun loadPlaces(): List { + private suspend fun loadPlaces(): List { val wikiSite = WikipediaApp.instance.wikiSite return withContext(Dispatchers.IO) { Prefs.placesLastLocationAndZoomLevel?.let { pair -> @@ -133,7 +156,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - suspend fun loadRandomArticles(): List { + private suspend fun loadRandomArticles(): List { // TODO: define how many random articles to load. return withContext(Dispatchers.IO) { val wikiSite = WikipediaApp.instance.wikiSite From 9212f5b47cb0b0acef2ba96c3d352ee3579f0b2c Mon Sep 17 00:00:00 2001 From: cooltey Date: Mon, 12 Aug 2024 16:01:08 -0700 Subject: [PATCH 11/99] Add enum and ids --- .../org/wikipedia/history/HistoryEntry.kt | 1 + .../RecommendedContentFragment.kt | 85 ++++++++++++++++++- .../RecommendedContentSection.kt | 60 +++++++++++++ .../RecommendedContentViewModel.kt | 9 +- app/src/main/res/values/ids.xml | 8 ++ app/src/main/res/values/strings.xml | 15 ++++ 6 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt diff --git a/app/src/main/java/org/wikipedia/history/HistoryEntry.kt b/app/src/main/java/org/wikipedia/history/HistoryEntry.kt index 19f31be7ed1..5efaba9ee27 100644 --- a/app/src/main/java/org/wikipedia/history/HistoryEntry.kt +++ b/app/src/main/java/org/wikipedia/history/HistoryEntry.kt @@ -99,5 +99,6 @@ class HistoryEntry( const val SOURCE_FILE_PAGE = 39 const val SOURCE_SINGLE_WEBVIEW = 40 const val SOURCE_SUGGESTED_EDITS_RECENT_EDITS = 41 + const val SOURCE_RECOMMENDED_CONTENT = 43 } } diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index 8f1699679f2..df56484ea6a 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -7,11 +7,22 @@ import android.view.ViewGroup import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.launch import org.wikipedia.Constants +import org.wikipedia.R import org.wikipedia.databinding.FragmentRecommendedContentBinding +import org.wikipedia.databinding.ItemRecommendedContentSearchHistoryBinding import org.wikipedia.dataclient.WikiSite +import org.wikipedia.history.HistoryEntry +import org.wikipedia.page.PageActivity +import org.wikipedia.page.PageTitle +import org.wikipedia.util.Resource +import org.wikipedia.util.StringUtil class RecommendedContentFragment : Fragment() { private var _binding: FragmentRecommendedContentBinding? = null @@ -23,8 +34,34 @@ class RecommendedContentFragment : Fragment() { _binding = FragmentRecommendedContentBinding.inflate(inflater, container, false) - lifecycleScope.launch { - // TODO + + binding.historyList.layoutManager = LinearLayoutManager(requireContext()) + + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + viewModel.historyState.collect { + when (it) { + is Resource.Success -> { + binding.historyList.adapter = RecyclerViewAdapter(it.data) + } + is Resource.Error -> { + // TODO: implement error + } + } + } + } + + + repeatOnLifecycle(Lifecycle.State.CREATED) { + viewModel.recommendedContentState.collect { + when (it) { + is Resource.Success -> { + } + is Resource.Error -> { + } + } + } + } } return binding.root @@ -35,6 +72,50 @@ class RecommendedContentFragment : Fragment() { super.onDestroyView() } + private inner class RecyclerViewAdapter(val list: List) : RecyclerView.Adapter() { + override fun getItemCount(): Int { + return list.size + } + + override fun onCreateViewHolder(parent: ViewGroup, type: Int): RecyclerViewItemHolder { + return RecyclerViewItemHolder(ItemRecommendedContentSearchHistoryBinding.inflate(layoutInflater, parent)) + } + + override fun onBindViewHolder(holder: RecyclerViewItemHolder, position: Int) { + holder.bindItem(list[position]) + } + } + + private inner class RecyclerViewItemHolder(val binding: ItemRecommendedContentSearchHistoryBinding) : + RecyclerView.ViewHolder(binding.root), View.OnClickListener { + + private lateinit var pageTitle: PageTitle + + init { + itemView.setOnClickListener(this) + } + + fun bindItem(pageTitle: PageTitle) { + this.pageTitle = pageTitle + val listIcon = if (viewModel.inHistory) R.drawable.ic_history_24 else R.drawable.ic_search_white_24dp + binding.listItem.text = StringUtil.fromHtml(pageTitle.displayText) + binding.listItem.setCompoundDrawablesWithIntrinsicBounds(0, listIcon, 0, 0) + binding.deleteIcon.setOnClickListener { + // TODO: implement this method. + if (viewModel.inHistory) { + + } else { + + } + } + } + + override fun onClick(v: View) { + val entry = HistoryEntry(pageTitle, HistoryEntry.SOURCE_RECOMMENDED_CONTENT) + startActivity(PageActivity.newIntentForNewTab(requireActivity(), entry, entry.title)) + } + } + companion object { const val ARG_IN_HISTORY = "inHistory" const val ARG_SHOW_TABS = "showTabs" diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt new file mode 100644 index 00000000000..60630df0d0f --- /dev/null +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt @@ -0,0 +1,60 @@ +package org.wikipedia.recommendedcontent + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import org.wikipedia.R +import org.wikipedia.model.EnumCode + +@Suppress("unused") +enum class RecommendedContentSection constructor(val id: Int, + val viewId: Int, + @StringRes val titleResId: Int) : EnumCode { + TOP_READ(0, R.id.recommended_content_section_top_read, R.string.recommended_content_section_top_read) { + override fun select(cb: Callback) { + } + }, + EXPLORE(1, R.id.recommended_content_section_explore, R.string.recommended_content_section_explore) { + override fun select(cb: Callback) { + } + }, + ON_THIS_DAY(2, R.id.recommended_content_section_on_this_day, R.string.recommended_content_section_on_this_day) { + override fun select(cb: Callback) { + } + }, + IN_THE_NEWS(3, R.id.recommended_content_section_in_the_news, R.string.recommended_content_section_in_the_news) { + override fun select(cb: Callback) { + } + }, + PLACES_NEAR_YOU(4, R.id.recommended_content_section_places_near_you, R.string.recommended_content_section_places_near_you) { + override fun select(cb: Callback) { + } + }, + BECAUSE_YOU_READ(5, R.id.recommended_content_section_because_you_read, R.string.recommended_content_section_because_you_read) { + override fun select(cb: Callback) { + } + }, + CONTINUE_READING(6, R.id.recommended_content_section_continue_reading, R.string.recommended_content_section_continue_reading) { + override fun select(cb: Callback) { + } + }, + RANDOM(0, R.id.recommended_content_section_random, R.string.recommended_content_section_random) { + override fun select(cb: Callback) { + } + }; + + abstract fun select(cb: Callback) + + override fun code(): Int { + // This enumeration is not marshalled so tying declaration order to presentation order is + // convenient and consistent. + return ordinal + } + + interface Callback { + // TODO: implement + } + + companion object { + + } +} diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index 30696e090f8..f867f172a87 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -33,7 +33,7 @@ import org.wikipedia.util.StringUtil class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { val wikiSite: WikiSite = bundle.parcelable(Constants.ARG_WIKISITE)!! - private val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) + val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) val showTabs = bundle.getBoolean(RecommendedContentFragment.ARG_SHOW_TABS) private val _historyState = MutableStateFlow(Resource>()) @@ -42,7 +42,11 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { private val _recommendedContentState = MutableStateFlow(Resource>()) val recommendedContentState = _recommendedContentState.asStateFlow() - fun loadSearchHistory() { + init { + loadSearchHistory() + } + + private fun loadSearchHistory() { viewModelScope.launch(CoroutineExceptionHandler { _, throwable -> _historyState.value = Resource.Error(throwable) }) { @@ -59,6 +63,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { viewModelScope.launch(CoroutineExceptionHandler { _, throwable -> _recommendedContentState.value = Resource.Error(throwable) }) { + // _recommendedContentState.value = Resource.Success(loadRecommendedContent(searchTerm)) } } diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index fd210e5bc19..9ca6355bd6c 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -19,4 +19,12 @@ + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9583eacacea..99af8106d6c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1771,4 +1771,19 @@ What would you like us to change or improve? on the map.]]> + + + View more history + More recent searches + More + Top read + Explore + On this day + In the news + Continue reading + Because you read + Places near you + Random + + From 3ccef93e48b24260743654a36f97529dc52b9fe6 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 10:49:24 -0700 Subject: [PATCH 12/99] Lint --- .../RecommendedContentFragment.kt | 4 ---- .../RecommendedContentSection.kt | 17 +++++++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index df56484ea6a..49aa9d5ee0a 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -34,7 +34,6 @@ class RecommendedContentFragment : Fragment() { _binding = FragmentRecommendedContentBinding.inflate(inflater, container, false) - binding.historyList.layoutManager = LinearLayoutManager(requireContext()) viewLifecycleOwner.lifecycleScope.launch { @@ -51,7 +50,6 @@ class RecommendedContentFragment : Fragment() { } } - repeatOnLifecycle(Lifecycle.State.CREATED) { viewModel.recommendedContentState.collect { when (it) { @@ -103,9 +101,7 @@ class RecommendedContentFragment : Fragment() { binding.deleteIcon.setOnClickListener { // TODO: implement this method. if (viewModel.inHistory) { - } else { - } } } diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt index 60630df0d0f..69f52e5365e 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt @@ -1,14 +1,13 @@ package org.wikipedia.recommendedcontent -import androidx.annotation.DrawableRes import androidx.annotation.StringRes import org.wikipedia.R import org.wikipedia.model.EnumCode @Suppress("unused") -enum class RecommendedContentSection constructor(val id: Int, - val viewId: Int, - @StringRes val titleResId: Int) : EnumCode { +enum class RecommendedContentSection(val id: Int, + val viewId: Int, + @StringRes val titleResId: Int) : EnumCode { TOP_READ(0, R.id.recommended_content_section_top_read, R.string.recommended_content_section_top_read) { override fun select(cb: Callback) { } @@ -51,10 +50,16 @@ enum class RecommendedContentSection constructor(val id: Int, } interface Callback { - // TODO: implement + fun onTopReadSelect() + fun onExploreSelect() + fun onOnThisDaySelect() + fun onInTheNewsSelect() + fun onPlacesSelect() + fun onBecauseYouReadSelect() + fun onContinueReadingSelect() + fun onRandomSelect() } companion object { - } } From 1c4d9a8118ae72d8de20ef0cda800da39b4271c0 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 12:27:28 -0700 Subject: [PATCH 13/99] Make responses to use PageSummary --- .../wikipedia/dataclient/page/NearbyPage.kt | 7 +++++ .../RecommendedContentViewModel.kt | 30 ++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/wikipedia/dataclient/page/NearbyPage.kt b/app/src/main/java/org/wikipedia/dataclient/page/NearbyPage.kt index 72e212b9267..62d7a44b066 100644 --- a/app/src/main/java/org/wikipedia/dataclient/page/NearbyPage.kt +++ b/app/src/main/java/org/wikipedia/dataclient/page/NearbyPage.kt @@ -17,4 +17,11 @@ class NearbyPage( latitude = this@NearbyPage.latitude longitude = this@NearbyPage.longitude } + + val toPageSummary get() = PageSummary().apply { + titles = PageSummary.Titles(pageTitle.prefixedText, pageTitle.displayText) + lang = pageTitle.wikiSite.languageCode + description = pageTitle.description + coordinates = location + } } diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index f867f172a87..d7d5dff3b1d 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -1,5 +1,6 @@ package org.wikipedia.recommendedcontent +import android.location.Location import android.os.Bundle import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider @@ -17,7 +18,6 @@ import org.wikipedia.WikipediaApp import org.wikipedia.database.AppDatabase import org.wikipedia.dataclient.ServiceFactory import org.wikipedia.dataclient.WikiSite -import org.wikipedia.dataclient.page.NearbyPage import org.wikipedia.dataclient.page.PageSummary import org.wikipedia.extensions.parcelable import org.wikipedia.feed.aggregated.AggregatedFeedContent @@ -58,8 +58,8 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - // TODO: think about modulating this method. - fun loadRecommendedContent(searchTerm: String) { + // TODO: think about modularizing this method. + fun loadRecommendedContent(sections: List) { viewModelScope.launch(CoroutineExceptionHandler { _, throwable -> _recommendedContentState.value = Resource.Error(throwable) }) { @@ -137,26 +137,34 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - private suspend fun loadContinueReading(): List { + private suspend fun loadContinueReading(): List { return withContext(Dispatchers.IO) { - WikipediaApp.instance.tabList.mapNotNull { it.backStackPositionTitle } + WikipediaApp.instance.tabList.mapNotNull { tab -> + tab.backStackPositionTitle?.let { + PageSummary(it.displayText, it.prefixedText, it.description, null, it.thumbUrl, it.wikiSite.languageCode) + } + } } } - private suspend fun loadPlaces(): List { + private suspend fun loadPlaces(): List { val wikiSite = WikipediaApp.instance.wikiSite return withContext(Dispatchers.IO) { Prefs.placesLastLocationAndZoomLevel?.let { pair -> val location = pair.first val response = ServiceFactory.get(wikiSite).getGeoSearch("${location.latitude}|${location.longitude}", 10000, 10, 10) - val nearbyPages = response.query?.pages.orEmpty() + val pages = response.query?.pages.orEmpty() .filter { it.coordinates != null } .map { - NearbyPage(it.pageId, PageTitle(it.title, wikiSite, - if (it.thumbUrl().isNullOrEmpty()) null else ImageUrlUtil.getUrlForPreferredSize(it.thumbUrl()!!, PlacesFragment.THUMB_SIZE), - it.description, it.displayTitle(wikiSite.languageCode)), it.coordinates!![0].lat, it.coordinates[0].lon) + val thumbUrl = if (it.thumbUrl().isNullOrEmpty()) null else ImageUrlUtil.getUrlForPreferredSize(it.thumbUrl()!!, PlacesFragment.THUMB_SIZE) + PageSummary(it.displayTitle(wikiSite.languageCode), it.title, it.description, it.extract, thumbUrl, wikiSite.languageCode).apply { + this.coordinates = Location("").apply { + latitude = it.coordinates!![0].lat + longitude = it.coordinates[0].lon + } + } } - nearbyPages + pages } ?: emptyList() } } From 38602cd26a2d5d97312ee75f97905b942bc672d1 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 12:30:05 -0700 Subject: [PATCH 14/99] Update return state format --- .../wikipedia/recommendedcontent/RecommendedContentViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index d7d5dff3b1d..be6622f4562 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -39,7 +39,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { private val _historyState = MutableStateFlow(Resource>()) val historyState = _historyState.asStateFlow() - private val _recommendedContentState = MutableStateFlow(Resource>()) + private val _recommendedContentState = MutableStateFlow(Resource>>()) val recommendedContentState = _recommendedContentState.asStateFlow() init { From 9deadb9aa5911e0d07d198927689a9c7d3e4b25f Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 12:47:20 -0700 Subject: [PATCH 15/99] Add more functions --- .../RecommendedContentViewModel.kt | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index be6622f4562..5f821640a92 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -39,7 +39,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { private val _historyState = MutableStateFlow(Resource>()) val historyState = _historyState.asStateFlow() - private val _recommendedContentState = MutableStateFlow(Resource>>()) + private val _recommendedContentState = MutableStateFlow(Resource>>>()) val recommendedContentState = _recommendedContentState.asStateFlow() init { @@ -58,13 +58,25 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } } - // TODO: think about modularizing this method. fun loadRecommendedContent(sections: List) { viewModelScope.launch(CoroutineExceptionHandler { _, throwable -> _recommendedContentState.value = Resource.Error(throwable) }) { - -// _recommendedContentState.value = Resource.Success(loadRecommendedContent(searchTerm)) + val recommendedContent = mutableListOf>>() + sections.forEach { section -> + val content = when (section) { + RecommendedContentSection.TOP_READ -> loadTopRead() + RecommendedContentSection.EXPLORE -> loadExplore("") + RecommendedContentSection.ON_THIS_DAY -> loadOnThisDay() + RecommendedContentSection.IN_THE_NEWS -> loadInTheNews() + RecommendedContentSection.PLACES_NEAR_YOU -> loadPlaces() + RecommendedContentSection.BECAUSE_YOU_READ -> loadBecauseYouRead(0) + RecommendedContentSection.CONTINUE_READING -> loadContinueReading() + RecommendedContentSection.RANDOM -> loadRandomArticles() + } + recommendedContent.add(section to content) + } + _recommendedContentState.value = Resource.Success(recommendedContent) } } @@ -110,6 +122,16 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { return loadFeed().topRead?.articles ?: emptyList() } + private suspend fun loadOnThisDay(): List { + // TODO: determine which event to load. + return loadFeed().onthisday?.first()?.pages() ?: emptyList() + } + + private suspend fun loadInTheNews(): List { + // TODO: determine which news to load. + return loadFeed().news?.first()?.links?.filterNotNull() ?: emptyList() + } + private suspend fun loadExplore(searchTerm: String): List { // TODO: single search term vs multiple search terms. return withContext(Dispatchers.IO) { From d29e122fb12a4858401dc3522430bf3b1452cf3a Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 12:49:20 -0700 Subject: [PATCH 16/99] Add comment --- .../wikipedia/recommendedcontent/RecommendedContentViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index 5f821640a92..547001fd4f4 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -66,7 +66,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { sections.forEach { section -> val content = when (section) { RecommendedContentSection.TOP_READ -> loadTopRead() - RecommendedContentSection.EXPLORE -> loadExplore("") + RecommendedContentSection.EXPLORE -> loadExplore("United States") // TODO: discuss this RecommendedContentSection.ON_THIS_DAY -> loadOnThisDay() RecommendedContentSection.IN_THE_NEWS -> loadInTheNews() RecommendedContentSection.PLACES_NEAR_YOU -> loadPlaces() From b01cc92fbb9ae6fde9180e0e1fb31682718c8fcc Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 12:57:36 -0700 Subject: [PATCH 17/99] Add qq strings --- .../recommendedcontent/RecommendedContentSection.kt | 8 ++++++++ app/src/main/res/values-qq/strings.xml | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt index 69f52e5365e..5cc1bbba3be 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt @@ -10,34 +10,42 @@ enum class RecommendedContentSection(val id: Int, @StringRes val titleResId: Int) : EnumCode { TOP_READ(0, R.id.recommended_content_section_top_read, R.string.recommended_content_section_top_read) { override fun select(cb: Callback) { + cb.onTopReadSelect() } }, EXPLORE(1, R.id.recommended_content_section_explore, R.string.recommended_content_section_explore) { override fun select(cb: Callback) { + cb.onExploreSelect() } }, ON_THIS_DAY(2, R.id.recommended_content_section_on_this_day, R.string.recommended_content_section_on_this_day) { override fun select(cb: Callback) { + cb.onOnThisDaySelect() } }, IN_THE_NEWS(3, R.id.recommended_content_section_in_the_news, R.string.recommended_content_section_in_the_news) { override fun select(cb: Callback) { + cb.onInTheNewsSelect() } }, PLACES_NEAR_YOU(4, R.id.recommended_content_section_places_near_you, R.string.recommended_content_section_places_near_you) { override fun select(cb: Callback) { + cb.onPlacesSelect() } }, BECAUSE_YOU_READ(5, R.id.recommended_content_section_because_you_read, R.string.recommended_content_section_because_you_read) { override fun select(cb: Callback) { + cb.onBecauseYouReadSelect() } }, CONTINUE_READING(6, R.id.recommended_content_section_continue_reading, R.string.recommended_content_section_continue_reading) { override fun select(cb: Callback) { + cb.onContinueReadingSelect() } }, RANDOM(0, R.id.recommended_content_section_random, R.string.recommended_content_section_random) { override fun select(cb: Callback) { + cb.onRandomSelect() } }; diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index dee4d6ca29f..39a1bbdafda 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -1693,4 +1693,15 @@ Negative action button text for places survey dialog Title text for the secondary dialog which is shown as a result of an action on the main dialog for places feature - shown only to users who are very unsatisfied with the feature Empty message for the list in the current map area. Please keep the anchor link around the \"on the map\". + Label for checking more history items in the Recommended Content. + Label for checking more recent search items in the Recommended Content. + Label for checking the specific section in the Recommended Content. + Section label for the Top read in the Recommended Content. + Section label for the Explore in the Recommended Content. + Section label for the On this day in the Recommended Content. + Section label for the In the news in the Recommended Content. + Section label for the Continue reading in the Recommended Content. + Section label for the Because you read in the Recommended Content. + Section label for the Places near you in the Recommended Content. + Section label for the Randomizer in the Recommended Content. From 430f168533c320908c2f15e4ccddfe733ba9723c Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 13:29:14 -0700 Subject: [PATCH 18/99] Intent argument --- .../recommendedcontent/RecommendedContentFragment.kt | 6 ++++-- .../recommendedcontent/RecommendedContentViewModel.kt | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index 49aa9d5ee0a..c18b42ce858 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -115,12 +115,14 @@ class RecommendedContentFragment : Fragment() { companion object { const val ARG_IN_HISTORY = "inHistory" const val ARG_SHOW_TABS = "showTabs" + const val ARG_SECTIONS = "sections" - fun newInstance(wikiSite: WikiSite, inHistory: Boolean, showTabs: Boolean) = RecommendedContentFragment().apply { + fun newInstance(wikiSite: WikiSite, inHistory: Boolean, showTabs: Boolean, sections: List) = RecommendedContentFragment().apply { arguments = bundleOf( Constants.ARG_WIKISITE to wikiSite, ARG_IN_HISTORY to inHistory, - ARG_SHOW_TABS to showTabs + ARG_SHOW_TABS to showTabs, + ARG_SECTIONS to sections ) } } diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index 547001fd4f4..81fc2a3b1fd 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -20,6 +20,7 @@ import org.wikipedia.dataclient.ServiceFactory import org.wikipedia.dataclient.WikiSite import org.wikipedia.dataclient.page.PageSummary import org.wikipedia.extensions.parcelable +import org.wikipedia.extensions.parcelableArrayList import org.wikipedia.feed.aggregated.AggregatedFeedContent import org.wikipedia.feed.topread.TopRead import org.wikipedia.page.PageTitle @@ -35,6 +36,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { val wikiSite: WikiSite = bundle.parcelable(Constants.ARG_WIKISITE)!! val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) val showTabs = bundle.getBoolean(RecommendedContentFragment.ARG_SHOW_TABS) + val sections: List = bundle.parcelableArrayList(RecommendedContentFragment.ARG_SECTIONS)!! private val _historyState = MutableStateFlow(Resource>()) val historyState = _historyState.asStateFlow() From bdd76b053e5437a50234d606b272a140afc1a821 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 15:24:20 -0700 Subject: [PATCH 19/99] add recommended content blocks --- .../RecommendedContentFragment.kt | 31 +++++++-- .../RecommendedContentSection.kt | 3 + .../RecommendedContentSectionView.kt | 65 +++++++++++++++++++ .../RecommendedContentViewModel.kt | 5 +- .../wikipedia/views/RecommendedContentView.kt | 16 ----- 5 files changed, 98 insertions(+), 22 deletions(-) create mode 100644 app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt delete mode 100644 app/src/main/java/org/wikipedia/views/RecommendedContentView.kt diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index c18b42ce858..753ba515f31 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -18,6 +18,7 @@ import org.wikipedia.R import org.wikipedia.databinding.FragmentRecommendedContentBinding import org.wikipedia.databinding.ItemRecommendedContentSearchHistoryBinding import org.wikipedia.dataclient.WikiSite +import org.wikipedia.dataclient.page.PageSummary import org.wikipedia.history.HistoryEntry import org.wikipedia.page.PageActivity import org.wikipedia.page.PageTitle @@ -41,7 +42,7 @@ class RecommendedContentFragment : Fragment() { viewModel.historyState.collect { when (it) { is Resource.Success -> { - binding.historyList.adapter = RecyclerViewAdapter(it.data) + buildHistoryList(it.data) } is Resource.Error -> { // TODO: implement error @@ -54,8 +55,10 @@ class RecommendedContentFragment : Fragment() { viewModel.recommendedContentState.collect { when (it) { is Resource.Success -> { + buildRecommendedContent(it.data) } is Resource.Error -> { + // TODO: implement error } } } @@ -70,6 +73,26 @@ class RecommendedContentFragment : Fragment() { super.onDestroyView() } + private fun buildHistoryList(list: List) { + binding.historyList.adapter = RecyclerViewAdapter(list) + binding.historyMoreButton.setOnClickListener { + requireActivity().supportFragmentManager.popBackStack() + } + if (viewModel.inHistory) { + binding.historyMoreButton.text = getString(R.string.recommended_content_view_more_history) + } else { + binding.historyMoreButton.text = getString(R.string.recommended_content_more_recent_searches) + } + } + + private fun buildRecommendedContent(list: List>>) { + list.forEach { (section, pageSummaries) -> + val sectionView = RecommendedContentSectionView(requireContext()) + sectionView.buildContent(section, pageSummaries) + binding.recommendedContentContainer.addView(sectionView) + } + } + private inner class RecyclerViewAdapter(val list: List) : RecyclerView.Adapter() { override fun getItemCount(): Int { return list.size @@ -115,14 +138,14 @@ class RecommendedContentFragment : Fragment() { companion object { const val ARG_IN_HISTORY = "inHistory" const val ARG_SHOW_TABS = "showTabs" - const val ARG_SECTIONS = "sections" + const val ARG_SECTION_IDS = "sectionIds" - fun newInstance(wikiSite: WikiSite, inHistory: Boolean, showTabs: Boolean, sections: List) = RecommendedContentFragment().apply { + fun newInstance(wikiSite: WikiSite, inHistory: Boolean, showTabs: Boolean, sectionIds: List) = RecommendedContentFragment().apply { arguments = bundleOf( Constants.ARG_WIKISITE to wikiSite, ARG_IN_HISTORY to inHistory, ARG_SHOW_TABS to showTabs, - ARG_SECTIONS to sections + ARG_SECTION_IDS to sectionIds ) } } diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt index 5cc1bbba3be..9287cecde31 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSection.kt @@ -69,5 +69,8 @@ enum class RecommendedContentSection(val id: Int, } companion object { + fun find(id: Int): RecommendedContentSection { + return RecommendedContentSection.entries.find { id == it.id || id == it.viewId } ?: RecommendedContentSection.entries[0] + } } } diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt new file mode 100644 index 00000000000..a57e021e226 --- /dev/null +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt @@ -0,0 +1,65 @@ +package org.wikipedia.recommendedcontent + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import org.wikipedia.WikipediaApp +import org.wikipedia.databinding.ItemRecommendedContentSectionTextBinding +import org.wikipedia.databinding.ViewRecommendedContentSectionBinding +import org.wikipedia.dataclient.page.PageSummary +import org.wikipedia.history.HistoryEntry +import org.wikipedia.page.PageActivity +import org.wikipedia.util.StringUtil + +class RecommendedContentSectionView(context: Context, attributeSet: AttributeSet? = null) : LinearLayout(context, attributeSet) { + + private val binding = ViewRecommendedContentSectionBinding.inflate(LayoutInflater.from(context)) + + fun buildContent(section: RecommendedContentSection, pageSummaries: List) { + binding.sectionHeader.text = context.getString(section.titleResId) + binding.sectionMoreButton.setOnClickListener { + // TODO: implement + } + binding.sectionList.layoutManager = LinearLayoutManager(context) + binding.sectionList.adapter = RecyclerViewAdapter(pageSummaries) + } + + private inner class RecyclerViewAdapter(val list: List) : RecyclerView.Adapter() { + override fun getItemCount(): Int { + return list.size + } + + override fun onCreateViewHolder(parent: ViewGroup, type: Int): RecyclerViewItemHolder { + return RecyclerViewItemHolder(ItemRecommendedContentSectionTextBinding.inflate(LayoutInflater.from(parent.context), parent, false)) + } + + override fun onBindViewHolder(holder: RecyclerViewItemHolder, position: Int) { + holder.bindItem(list[position]) + } + } + + private inner class RecyclerViewItemHolder(val binding: ItemRecommendedContentSectionTextBinding) : + RecyclerView.ViewHolder(binding.root), OnClickListener { + + private lateinit var pageSummary: PageSummary + + init { + itemView.setOnClickListener(this) + } + + fun bindItem(pageSummary: PageSummary) { + this.pageSummary = pageSummary + binding.listItem.text = StringUtil.fromHtml(pageSummary.displayTitle) + } + + override fun onClick(v: View) { + val entry = HistoryEntry(pageSummary.getPageTitle(WikipediaApp.instance.wikiSite), HistoryEntry.SOURCE_RECOMMENDED_CONTENT) + context.startActivity(PageActivity.newIntentForNewTab(context, entry, entry.title)) + } + } +} diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index 81fc2a3b1fd..8152ff4f40a 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -20,7 +20,6 @@ import org.wikipedia.dataclient.ServiceFactory import org.wikipedia.dataclient.WikiSite import org.wikipedia.dataclient.page.PageSummary import org.wikipedia.extensions.parcelable -import org.wikipedia.extensions.parcelableArrayList import org.wikipedia.feed.aggregated.AggregatedFeedContent import org.wikipedia.feed.topread.TopRead import org.wikipedia.page.PageTitle @@ -36,7 +35,8 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { val wikiSite: WikiSite = bundle.parcelable(Constants.ARG_WIKISITE)!! val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) val showTabs = bundle.getBoolean(RecommendedContentFragment.ARG_SHOW_TABS) - val sections: List = bundle.parcelableArrayList(RecommendedContentFragment.ARG_SECTIONS)!! + private val sectionIds: List = bundle.getIntegerArrayList(RecommendedContentFragment.ARG_SECTION_IDS)!! + val sections = sectionIds.map { RecommendedContentSection.find(it) } private val _historyState = MutableStateFlow(Resource>()) val historyState = _historyState.asStateFlow() @@ -46,6 +46,7 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { init { loadSearchHistory() + loadRecommendedContent(sections) } private fun loadSearchHistory() { diff --git a/app/src/main/java/org/wikipedia/views/RecommendedContentView.kt b/app/src/main/java/org/wikipedia/views/RecommendedContentView.kt deleted file mode 100644 index 14d2075318a..00000000000 --- a/app/src/main/java/org/wikipedia/views/RecommendedContentView.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.wikipedia.views - -import android.content.Context -import android.util.AttributeSet -import android.view.LayoutInflater -import android.widget.LinearLayout -import org.wikipedia.databinding.ViewSearchEmptyBinding - -class RecommendedContentView(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) { - - private val binding = ViewSearchEmptyBinding.inflate(LayoutInflater.from(context), this) - - init { - orientation = VERTICAL - } -} From d2abec3f401fcc58f83639584e26a9c35977571c Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 15:41:31 -0700 Subject: [PATCH 20/99] Bind to History --- .../org/wikipedia/history/HistoryFragment.kt | 17 +++++++++++++++++ .../RecommendedContentFragment.kt | 3 +-- .../RecommendedContentViewModel.kt | 2 +- app/src/main/res/layout/fragment_history.xml | 5 +++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt index b8a79d573ff..083e7cf4927 100644 --- a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt +++ b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt @@ -33,6 +33,8 @@ import org.wikipedia.main.MainActivity import org.wikipedia.main.MainFragment import org.wikipedia.page.PageAvailableOfflineHandler import org.wikipedia.readinglist.database.ReadingList +import org.wikipedia.recommendedcontent.RecommendedContentFragment +import org.wikipedia.recommendedcontent.RecommendedContentSection import org.wikipedia.settings.Prefs import org.wikipedia.util.DimenUtil import org.wikipedia.util.FeedbackUtil @@ -90,6 +92,21 @@ class HistoryFragment : Fragment(), BackPressedHandler { onPagesDeleted() } } + + loadRecommendedContent() + } + + private fun loadRecommendedContent() { + val sectionIds = listOf( + RecommendedContentSection.TOP_READ, + RecommendedContentSection.ON_THIS_DAY, + RecommendedContentSection.IN_THE_NEWS + ).map { it.id } + + requireActivity().supportFragmentManager.beginTransaction() + .add(R.id.fragmentOverlayContainer, RecommendedContentFragment.newInstance(inHistory = true, showTabs = false, sectionIds), null) + .addToBackStack(null) + .commit() } private fun setUpScrollListener() { diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index 753ba515f31..bb6b87447f1 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -140,9 +140,8 @@ class RecommendedContentFragment : Fragment() { const val ARG_SHOW_TABS = "showTabs" const val ARG_SECTION_IDS = "sectionIds" - fun newInstance(wikiSite: WikiSite, inHistory: Boolean, showTabs: Boolean, sectionIds: List) = RecommendedContentFragment().apply { + fun newInstance(inHistory: Boolean, showTabs: Boolean, sectionIds: List) = RecommendedContentFragment().apply { arguments = bundleOf( - Constants.ARG_WIKISITE to wikiSite, ARG_IN_HISTORY to inHistory, ARG_SHOW_TABS to showTabs, ARG_SECTION_IDS to sectionIds diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index 8152ff4f40a..2000b37bdc8 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -32,7 +32,7 @@ import org.wikipedia.util.StringUtil class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { - val wikiSite: WikiSite = bundle.parcelable(Constants.ARG_WIKISITE)!! + val wikiSite = WikipediaApp.instance.wikiSite val inHistory = bundle.getBoolean(RecommendedContentFragment.ARG_IN_HISTORY) val showTabs = bundle.getBoolean(RecommendedContentFragment.ARG_SHOW_TABS) private val sectionIds: List = bundle.getIntegerArrayList(RecommendedContentFragment.ARG_SECTION_IDS)!! diff --git a/app/src/main/res/layout/fragment_history.xml b/app/src/main/res/layout/fragment_history.xml index e2399b55575..9a51f897805 100644 --- a/app/src/main/res/layout/fragment_history.xml +++ b/app/src/main/res/layout/fragment_history.xml @@ -61,4 +61,9 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" /> + + From df4cb714517f5ae0fe4d79a7262e459f2e320f91 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 16:29:26 -0700 Subject: [PATCH 21/99] Complete history list --- .../RecommendedContentFragment.kt | 19 +++-- .../RecommendedContentSectionView.kt | 2 +- .../layout/fragment_recommended_content.xml | 81 ++++++++++++------- ...tem_recommended_content_search_history.xml | 14 ++-- 4 files changed, 71 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index bb6b87447f1..6676f304603 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -13,17 +13,17 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.launch -import org.wikipedia.Constants import org.wikipedia.R import org.wikipedia.databinding.FragmentRecommendedContentBinding import org.wikipedia.databinding.ItemRecommendedContentSearchHistoryBinding -import org.wikipedia.dataclient.WikiSite import org.wikipedia.dataclient.page.PageSummary import org.wikipedia.history.HistoryEntry import org.wikipedia.page.PageActivity import org.wikipedia.page.PageTitle import org.wikipedia.util.Resource +import org.wikipedia.util.ResourceUtil import org.wikipedia.util.StringUtil +import org.wikipedia.util.log.L class RecommendedContentFragment : Fragment() { private var _binding: FragmentRecommendedContentBinding? = null @@ -33,19 +33,18 @@ class RecommendedContentFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { super.onCreateView(inflater, container, savedInstanceState) - _binding = FragmentRecommendedContentBinding.inflate(inflater, container, false) - - binding.historyList.layoutManager = LinearLayoutManager(requireContext()) + _binding = FragmentRecommendedContentBinding.inflate(layoutInflater, container, false) viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.CREATED) { viewModel.historyState.collect { when (it) { is Resource.Success -> { - buildHistoryList(it.data) + buildHistoryList(it.data) } is Resource.Error -> { // TODO: implement error + L.d(it.throwable) } } } @@ -55,10 +54,12 @@ class RecommendedContentFragment : Fragment() { viewModel.recommendedContentState.collect { when (it) { is Resource.Success -> { + L.d("Recommended content: ${it.data}") buildRecommendedContent(it.data) } is Resource.Error -> { // TODO: implement error + L.d(it.throwable) } } } @@ -74,7 +75,9 @@ class RecommendedContentFragment : Fragment() { } private fun buildHistoryList(list: List) { + binding.historyList.layoutManager = LinearLayoutManager(requireContext()) binding.historyList.adapter = RecyclerViewAdapter(list) + binding.searchCard.root.setCardBackgroundColor(ResourceUtil.getThemedColor(requireContext(), R.attr.background_color)) binding.historyMoreButton.setOnClickListener { requireActivity().supportFragmentManager.popBackStack() } @@ -99,7 +102,7 @@ class RecommendedContentFragment : Fragment() { } override fun onCreateViewHolder(parent: ViewGroup, type: Int): RecyclerViewItemHolder { - return RecyclerViewItemHolder(ItemRecommendedContentSearchHistoryBinding.inflate(layoutInflater, parent)) + return RecyclerViewItemHolder(ItemRecommendedContentSearchHistoryBinding.inflate(layoutInflater, parent, false)) } override fun onBindViewHolder(holder: RecyclerViewItemHolder, position: Int) { @@ -120,7 +123,7 @@ class RecommendedContentFragment : Fragment() { this.pageTitle = pageTitle val listIcon = if (viewModel.inHistory) R.drawable.ic_history_24 else R.drawable.ic_search_white_24dp binding.listItem.text = StringUtil.fromHtml(pageTitle.displayText) - binding.listItem.setCompoundDrawablesWithIntrinsicBounds(0, listIcon, 0, 0) + binding.listItem.setCompoundDrawablesWithIntrinsicBounds(listIcon, 0, 0, 0) binding.deleteIcon.setOnClickListener { // TODO: implement this method. if (viewModel.inHistory) { diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt index a57e021e226..2c8a684dfd1 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt @@ -18,7 +18,7 @@ import org.wikipedia.util.StringUtil class RecommendedContentSectionView(context: Context, attributeSet: AttributeSet? = null) : LinearLayout(context, attributeSet) { - private val binding = ViewRecommendedContentSectionBinding.inflate(LayoutInflater.from(context)) + private val binding = ViewRecommendedContentSectionBinding.inflate(LayoutInflater.from(context), this, true) fun buildContent(section: RecommendedContentSection, pageSummaries: List) { binding.sectionHeader.text = context.getString(section.titleResId) diff --git a/app/src/main/res/layout/fragment_recommended_content.xml b/app/src/main/res/layout/fragment_recommended_content.xml index 72b73a8087f..871087abc56 100644 --- a/app/src/main/res/layout/fragment_recommended_content.xml +++ b/app/src/main/res/layout/fragment_recommended_content.xml @@ -1,41 +1,60 @@ - + android:layout_height="match_parent" + android:background="?attr/paper_color"> - - - + android:orientation="vertical" + android:layout_marginHorizontal="16dp" + android:background="?attr/paper_color"> - + - + + + + + + + + + + + - diff --git a/app/src/main/res/layout/item_recommended_content_search_history.xml b/app/src/main/res/layout/item_recommended_content_search_history.xml index 02998e3e38f..74772bb142b 100644 --- a/app/src/main/res/layout/item_recommended_content_search_history.xml +++ b/app/src/main/res/layout/item_recommended_content_search_history.xml @@ -1,16 +1,19 @@ - + android:layout_width="match_parent" + android:layout_height="wrap_content"> @@ -20,7 +23,8 @@ android:layout_height="match_parent" android:contentDescription="@string/reading_list_delete_lists_dialog_delete_button_text" android:scaleType="center" + android:background="?android:attr/selectableItemBackground" app:srcCompat="@drawable/ic_close_black_24dp" app:tint="?android:attr/textColorTertiary" /> - + From d05171df8c219c36509f6c78bafad09e044af2a7 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 16:55:37 -0700 Subject: [PATCH 22/99] Fix stuff --- .../org/wikipedia/history/HistoryFragment.kt | 4 +- .../RecommendedContentFragment.kt | 41 ++++++++++--------- .../RecommendedContentSectionView.kt | 7 ++-- .../RecommendedContentViewModel.kt | 16 ++++++-- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt index 083e7cf4927..539c3e611ac 100644 --- a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt +++ b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt @@ -98,9 +98,7 @@ class HistoryFragment : Fragment(), BackPressedHandler { private fun loadRecommendedContent() { val sectionIds = listOf( - RecommendedContentSection.TOP_READ, - RecommendedContentSection.ON_THIS_DAY, - RecommendedContentSection.IN_THE_NEWS + RecommendedContentSection.EXPLORE ).map { it.id } requireActivity().supportFragmentManager.beginTransaction() diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt index 6676f304603..fe96c74b3a9 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentFragment.kt @@ -37,29 +37,29 @@ class RecommendedContentFragment : Fragment() { viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.CREATED) { - viewModel.historyState.collect { - when (it) { - is Resource.Success -> { - buildHistoryList(it.data) - } - is Resource.Error -> { - // TODO: implement error - L.d(it.throwable) + launch { + viewModel.historyState.collect { + when (it) { + is Resource.Success -> { + buildHistoryList(it.data) + } + is Resource.Error -> { + // TODO: implement error + L.d(it.throwable) + } } } } - } - - repeatOnLifecycle(Lifecycle.State.CREATED) { - viewModel.recommendedContentState.collect { - when (it) { - is Resource.Success -> { - L.d("Recommended content: ${it.data}") - buildRecommendedContent(it.data) - } - is Resource.Error -> { - // TODO: implement error - L.d(it.throwable) + launch { + viewModel.recommendedContentState.collect { + when (it) { + is Resource.Success -> { + buildRecommendedContent(it.data) + } + is Resource.Error -> { + // TODO: implement error + L.d(it.throwable) + } } } } @@ -89,6 +89,7 @@ class RecommendedContentFragment : Fragment() { } private fun buildRecommendedContent(list: List>>) { + L.d("buildRecommendedContent list: $list") list.forEach { (section, pageSummaries) -> val sectionView = RecommendedContentSectionView(requireContext()) sectionView.buildContent(section, pageSummaries) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt index 2c8a684dfd1..0430b5d3c6c 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt @@ -1,11 +1,10 @@ package org.wikipedia.recommendedcontent import android.content.Context -import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.LinearLayout +import android.widget.FrameLayout import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import org.wikipedia.WikipediaApp @@ -16,9 +15,9 @@ import org.wikipedia.history.HistoryEntry import org.wikipedia.page.PageActivity import org.wikipedia.util.StringUtil -class RecommendedContentSectionView(context: Context, attributeSet: AttributeSet? = null) : LinearLayout(context, attributeSet) { +class RecommendedContentSectionView(context: Context) : FrameLayout(context) { - private val binding = ViewRecommendedContentSectionBinding.inflate(LayoutInflater.from(context), this, true) + private val binding = ViewRecommendedContentSectionBinding.inflate(LayoutInflater.from(context)) fun buildContent(section: RecommendedContentSection, pageSummaries: List) { binding.sectionHeader.text = context.getString(section.titleResId) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index 2000b37bdc8..31abdc0ae12 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -19,7 +19,6 @@ import org.wikipedia.database.AppDatabase import org.wikipedia.dataclient.ServiceFactory import org.wikipedia.dataclient.WikiSite import org.wikipedia.dataclient.page.PageSummary -import org.wikipedia.extensions.parcelable import org.wikipedia.feed.aggregated.AggregatedFeedContent import org.wikipedia.feed.topread.TopRead import org.wikipedia.page.PageTitle @@ -29,6 +28,7 @@ import org.wikipedia.util.DateUtil import org.wikipedia.util.ImageUrlUtil import org.wikipedia.util.Resource import org.wikipedia.util.StringUtil +import org.wikipedia.util.log.L class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { @@ -77,8 +77,10 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { RecommendedContentSection.CONTINUE_READING -> loadContinueReading() RecommendedContentSection.RANDOM -> loadRandomArticles() } + L.d("Recommended content for $section: $content") recommendedContent.add(section to content) } + L.d("Recommended content: $recommendedContent") _recommendedContentState.value = Resource.Success(recommendedContent) } } @@ -122,17 +124,23 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { } private suspend fun loadTopRead(): List { - return loadFeed().topRead?.articles ?: emptyList() + return withContext(Dispatchers.IO) { + loadFeed().topRead?.articles ?: emptyList() + } } private suspend fun loadOnThisDay(): List { // TODO: determine which event to load. - return loadFeed().onthisday?.first()?.pages() ?: emptyList() + return withContext(Dispatchers.IO) { + loadFeed().onthisday?.first()?.pages() ?: emptyList() + } } private suspend fun loadInTheNews(): List { // TODO: determine which news to load. - return loadFeed().news?.first()?.links?.filterNotNull() ?: emptyList() + return withContext(Dispatchers.IO) { + loadFeed().news?.first()?.links?.filterNotNull() ?: emptyList() + } } private suspend fun loadExplore(searchTerm: String): List { From 3b1df705358e28ed9688565448d49457359e1b3b Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 17:53:00 -0700 Subject: [PATCH 23/99] Use correct divider --- app/src/main/res/layout/fragment_recommended_content.xml | 3 ++- app/src/main/res/layout/view_recommended_content_section.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_recommended_content.xml b/app/src/main/res/layout/fragment_recommended_content.xml index 871087abc56..13b3e0d7d69 100644 --- a/app/src/main/res/layout/fragment_recommended_content.xml +++ b/app/src/main/res/layout/fragment_recommended_content.xml @@ -51,7 +51,8 @@ diff --git a/app/src/main/res/layout/view_recommended_content_section.xml b/app/src/main/res/layout/view_recommended_content_section.xml index 244b490dbda..bea652d6e1d 100644 --- a/app/src/main/res/layout/view_recommended_content_section.xml +++ b/app/src/main/res/layout/view_recommended_content_section.xml @@ -9,7 +9,7 @@ android:id="@+id/sectionDivider" android:layout_width="match_parent" android:layout_height="1dp" - android:background="?attr/divider" + android:background="?attr/list_divider" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> From 4ed27602739cef7b3b17b3b5df146af264cb0b19 Mon Sep 17 00:00:00 2001 From: cooltey Date: Thu, 15 Aug 2024 17:54:21 -0700 Subject: [PATCH 24/99] Layout --- app/src/main/res/layout/fragment_recommended_content.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_recommended_content.xml b/app/src/main/res/layout/fragment_recommended_content.xml index 13b3e0d7d69..871087abc56 100644 --- a/app/src/main/res/layout/fragment_recommended_content.xml +++ b/app/src/main/res/layout/fragment_recommended_content.xml @@ -51,8 +51,7 @@ From 37a478e92b8f159f0f336e2c6061c140043c4205 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Fri, 16 Aug 2024 08:30:03 -0700 Subject: [PATCH 25/99] Fix inflate layout --- .../recommendedcontent/RecommendedContentSectionView.kt | 3 ++- app/src/main/res/layout/fragment_recommended_content.xml | 5 +++-- app/src/main/res/layout/view_recommended_content_section.xml | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt index 0430b5d3c6c..90e04a74598 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentSectionView.kt @@ -17,7 +17,7 @@ import org.wikipedia.util.StringUtil class RecommendedContentSectionView(context: Context) : FrameLayout(context) { - private val binding = ViewRecommendedContentSectionBinding.inflate(LayoutInflater.from(context)) + private val binding = ViewRecommendedContentSectionBinding.inflate(LayoutInflater.from(context), this, true) fun buildContent(section: RecommendedContentSection, pageSummaries: List) { binding.sectionHeader.text = context.getString(section.titleResId) @@ -26,6 +26,7 @@ class RecommendedContentSectionView(context: Context) : FrameLayout(context) { } binding.sectionList.layoutManager = LinearLayoutManager(context) binding.sectionList.adapter = RecyclerViewAdapter(pageSummaries) + binding.root.requestLayout() } private inner class RecyclerViewAdapter(val list: List) : RecyclerView.Adapter() { diff --git a/app/src/main/res/layout/fragment_recommended_content.xml b/app/src/main/res/layout/fragment_recommended_content.xml index 871087abc56..2bc4f98da99 100644 --- a/app/src/main/res/layout/fragment_recommended_content.xml +++ b/app/src/main/res/layout/fragment_recommended_content.xml @@ -24,8 +24,9 @@ + android:layout_height="wrap_content" + android:nestedScrollingEnabled="false" + android:scrollbars="vertical"/> From a82d96fcee47c9f10aba457268dc72523d5ca14b Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Fri, 16 Aug 2024 08:58:50 -0700 Subject: [PATCH 26/99] Adjust view --- .../res/layout/item_recommended_content_search_history.xml | 1 + .../res/layout/item_recommended_content_section_text.xml | 6 ++++-- .../main/res/layout/view_recommended_content_section.xml | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/item_recommended_content_search_history.xml b/app/src/main/res/layout/item_recommended_content_search_history.xml index 74772bb142b..23527d0c8f5 100644 --- a/app/src/main/res/layout/item_recommended_content_search_history.xml +++ b/app/src/main/res/layout/item_recommended_content_search_history.xml @@ -24,6 +24,7 @@ android:contentDescription="@string/reading_list_delete_lists_dialog_delete_button_text" android:scaleType="center" android:background="?android:attr/selectableItemBackground" + android:layout_marginEnd="-16dp" app:srcCompat="@drawable/ic_close_black_24dp" app:tint="?android:attr/textColorTertiary" /> diff --git a/app/src/main/res/layout/item_recommended_content_section_text.xml b/app/src/main/res/layout/item_recommended_content_section_text.xml index 7301334d3f5..e435334b267 100644 --- a/app/src/main/res/layout/item_recommended_content_section_text.xml +++ b/app/src/main/res/layout/item_recommended_content_section_text.xml @@ -4,8 +4,10 @@ xmlns:tools="http://schemas.android.com/tools" style="@style/OverflowMenuItem" android:id="@+id/listItem" - android:layout_width="wrap_content" + android:layout_width="match_parent" + android:padding="8dp" android:drawablePadding="16dp" - app:drawableEndCompat="@drawable/ic_trending_up_black_24dp" + android:paddingHorizontal="0dp" + android:layout_marginHorizontal="-16dp" app:drawableTint="?attr/success_color" tools:text="Article title" /> diff --git a/app/src/main/res/layout/view_recommended_content_section.xml b/app/src/main/res/layout/view_recommended_content_section.xml index 6102969d492..dab7df9fb1d 100644 --- a/app/src/main/res/layout/view_recommended_content_section.xml +++ b/app/src/main/res/layout/view_recommended_content_section.xml @@ -19,7 +19,7 @@ style="@style/H3.MaterialListTitle" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="16dp" + android:layout_marginStart="8dp" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/sectionDivider" @@ -30,7 +30,7 @@ android:id="@+id/sectionMoreButton" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="16dp" + android:layout_marginEnd="8dp" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@id/sectionDivider" app:layout_constraintEnd_toEndOf="parent" @@ -41,7 +41,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" - android:layout_margin="16dp" + android:layout_margin="8dp" android:nestedScrollingEnabled="false" app:layout_constraintTop_toBottomOf="@id/sectionHeader"/> From dc2c5c3608274a7d658193ed8aa3909c6112c9f8 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Fri, 16 Aug 2024 09:01:02 -0700 Subject: [PATCH 27/99] Put multiple sections --- app/src/main/java/org/wikipedia/history/HistoryFragment.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt index 539c3e611ac..6f2ff2b6e8b 100644 --- a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt +++ b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt @@ -98,7 +98,9 @@ class HistoryFragment : Fragment(), BackPressedHandler { private fun loadRecommendedContent() { val sectionIds = listOf( - RecommendedContentSection.EXPLORE + RecommendedContentSection.EXPLORE, + RecommendedContentSection.TOP_READ, + RecommendedContentSection.IN_THE_NEWS ).map { it.id } requireActivity().supportFragmentManager.beginTransaction() From 59038a91139f081d5b6dc5910d762e399cd10c99 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Fri, 16 Aug 2024 09:20:01 -0700 Subject: [PATCH 28/99] More view adjustment --- .../main/res/layout/fragment_recommended_content.xml | 10 +++++++--- .../layout/item_recommended_content_search_history.xml | 7 ++----- .../layout/item_recommended_content_section_text.xml | 5 +---- .../res/layout/view_recommended_content_section.xml | 2 -- app/src/main/res/values/styles.xml | 10 ++++++++++ 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/src/main/res/layout/fragment_recommended_content.xml b/app/src/main/res/layout/fragment_recommended_content.xml index 2bc4f98da99..d8439be8521 100644 --- a/app/src/main/res/layout/fragment_recommended_content.xml +++ b/app/src/main/res/layout/fragment_recommended_content.xml @@ -10,7 +10,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:layout_marginHorizontal="16dp" + android:paddingBottom="8dp" android:background="?attr/paper_color"> + android:orientation="vertical" + android:layout_marginHorizontal="16dp"/> diff --git a/app/src/main/res/layout/item_recommended_content_search_history.xml b/app/src/main/res/layout/item_recommended_content_search_history.xml index 23527d0c8f5..00f1a14aafb 100644 --- a/app/src/main/res/layout/item_recommended_content_search_history.xml +++ b/app/src/main/res/layout/item_recommended_content_search_history.xml @@ -7,13 +7,11 @@ @@ -24,7 +22,6 @@ android:contentDescription="@string/reading_list_delete_lists_dialog_delete_button_text" android:scaleType="center" android:background="?android:attr/selectableItemBackground" - android:layout_marginEnd="-16dp" app:srcCompat="@drawable/ic_close_black_24dp" app:tint="?android:attr/textColorTertiary" /> diff --git a/app/src/main/res/layout/item_recommended_content_section_text.xml b/app/src/main/res/layout/item_recommended_content_section_text.xml index e435334b267..5bd2dacfa7c 100644 --- a/app/src/main/res/layout/item_recommended_content_section_text.xml +++ b/app/src/main/res/layout/item_recommended_content_section_text.xml @@ -2,12 +2,9 @@ diff --git a/app/src/main/res/layout/view_recommended_content_section.xml b/app/src/main/res/layout/view_recommended_content_section.xml index dab7df9fb1d..2fcb0e69c46 100644 --- a/app/src/main/res/layout/view_recommended_content_section.xml +++ b/app/src/main/res/layout/view_recommended_content_section.xml @@ -19,7 +19,6 @@ style="@style/H3.MaterialListTitle" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="8dp" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/sectionDivider" @@ -41,7 +40,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" - android:layout_margin="8dp" android:nestedScrollingEnabled="false" app:layout_constraintTop_toBottomOf="@id/sectionHeader"/> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ac312fc3494..3f9f189a3f2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -363,6 +363,16 @@ true + + - + + + + + + From 21b1ad8d52ab8be90e6849a11571cd3478712271 Mon Sep 17 00:00:00 2001 From: cooltey Date: Wed, 4 Sep 2024 10:15:20 -0700 Subject: [PATCH 93/99] Code review addressed --- .../org/wikipedia/history/HistoryFragment.kt | 9 ++---- .../RecommendedContentViewModel.kt | 4 +-- .../res/layout/dialog_feedback_options.xml | 13 +++++---- .../view_recommended_content_section.xml | 15 ++++------ app/src/main/res/values/strings.xml | 2 +- app/src/main/res/values/styles.xml | 29 ++++--------------- 6 files changed, 24 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt index 6d474a36cd7..b8a79d573ff 100644 --- a/app/src/main/java/org/wikipedia/history/HistoryFragment.kt +++ b/app/src/main/java/org/wikipedia/history/HistoryFragment.kt @@ -103,6 +103,7 @@ class HistoryFragment : Fragment(), BackPressedHandler { override fun onResume() { super.onResume() + viewModel.reloadHistoryItems() } override fun onPause() { @@ -221,10 +222,6 @@ class HistoryFragment : Fragment(), BackPressedHandler { onLoadItemsFinished(emptyList()) } - fun openSearchActivity(source: Constants.InvokeSource, query: String?, view: View) { - (requireParentFragment() as MainFragment).openSearchActivity(source, query, view) - } - private class HeaderViewHolder(itemView: View) : DefaultViewHolder(itemView) { var headerText = itemView.findViewById(R.id.section_header_text)!! @@ -265,9 +262,7 @@ class HistoryFragment : Fragment(), BackPressedHandler { val voiceSearchButton = itemView.findViewById(R.id.voice_search_button) historyFilterButton = itemView.findViewById(R.id.history_filter) clearHistoryButton = itemView.findViewById(R.id.history_delete) - searchCardView.setOnClickListener { - openSearchActivity(Constants.InvokeSource.NAV_MENU, null, it) - } + searchCardView.setOnClickListener { (requireParentFragment() as MainFragment).openSearchActivity(Constants.InvokeSource.NAV_MENU, null, it) } voiceSearchButton.isVisible = WikipediaApp.instance.voiceRecognitionAvailable voiceSearchButton.setOnClickListener { (requireParentFragment() as MainFragment).onFeedVoiceSearchRequested() } historyFilterButton.setOnClickListener { diff --git a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt index a20bb8a3298..79fdded13fd 100644 --- a/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt +++ b/app/src/main/java/org/wikipedia/recommendedcontent/RecommendedContentViewModel.kt @@ -194,13 +194,13 @@ class RecommendedContentViewModel(bundle: Bundle) : ViewModel() { private suspend fun loadOnThisDay(): List { return withContext(Dispatchers.IO) { - loadFeed().onthisday?.first()?.pages() ?: emptyList() + loadFeed().onthisday?.mapNotNull { it.pages()?.firstOrNull() } ?: emptyList() } } private suspend fun loadInTheNews(): List { return withContext(Dispatchers.IO) { - loadFeed().news?.first()?.links?.filterNotNull() ?: emptyList() + loadFeed().news?.mapNotNull { it.links.firstOrNull() } ?: emptyList() } } diff --git a/app/src/main/res/layout/dialog_feedback_options.xml b/app/src/main/res/layout/dialog_feedback_options.xml index 154db8fc61b..87ab6937d39 100644 --- a/app/src/main/res/layout/dialog_feedback_options.xml +++ b/app/src/main/res/layout/dialog_feedback_options.xml @@ -16,11 +16,12 @@ - + android:layout_height="wrap_content" + android:orientation="vertical"> + android:layout_marginTop="12dp" /> - + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4e93e25cf66..c533fddb149 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1785,7 +1785,7 @@ You might like Help improve recommended content. Are you satisfied with this recommended search result? - Additional Feedback + Additional feedback Feedback submitted. Thank you! diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index d6461344646..d6e91701270 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -169,14 +169,6 @@ normal - - - - -