From 06f49e1e25ace1611f8223578362bc693f4bffbb Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 20 Mar 2020 21:33:21 -0300 Subject: [PATCH 01/58] Added Tenor library and API key reference --- WordPress/build.gradle | 2 ++ gradle.properties-example | 1 + 2 files changed, 3 insertions(+) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index e2db1d6e8ea5..81a728e6c5be 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -290,6 +290,8 @@ dependencies { exclude group: 'com.google.dagger' } + implementation 'com.github.Tenor-Inc:tenor-android-core:0.5.1' + lintChecks 'org.wordpress:lint:1.0.1' // Sentry diff --git a/gradle.properties-example b/gradle.properties-example index a650834a517b..0855ee223728 100644 --- a/gradle.properties-example +++ b/gradle.properties-example @@ -26,6 +26,7 @@ wp.zendesk.domain=https://www.google.com/ wp.zendesk.oauth_client_id=wordpress wp.reset_db_on_downgrade = false wp.sentry.dsn=https://00000000000000000000000000000000@sentry.io/00000000 +wp.tenor.api_key=wordpress # Needed to use the Google Maps component aka the PlacePicker (Post Settings -> Location) wp.res.com.google.android.geo.api.key = geo-api-key From be9e11874573e85ebed850671d1b44f2eba9193f Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sun, 22 Mar 2020 03:31:23 -0300 Subject: [PATCH 02/58] Changed giphy package name to gifs --- .../main/java/org/wordpress/android/modules/AppComponent.java | 2 +- .../android/ui/{giphy => gifs}/GiphyMediaViewHolder.kt | 2 +- .../android/ui/{giphy => gifs}/GiphyPickerActivity.kt | 4 ++-- .../android/ui/{giphy => gifs}/GiphyPickerPagedListAdapter.kt | 4 ++-- .../android/ui/{giphy => gifs}/LifecycleOwnerViewHolder.kt | 2 +- .../wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy => gifs}/GiphyMediaViewHolder.kt (99%) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy => gifs}/GiphyPickerActivity.kt (99%) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy => gifs}/GiphyPickerPagedListAdapter.kt (94%) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy => gifs}/LifecycleOwnerViewHolder.kt (99%) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java index a9edf87b9af5..801bb6f2185c 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java @@ -40,7 +40,7 @@ import org.wordpress.android.ui.domains.DomainRegistrationActivity; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment; import org.wordpress.android.ui.domains.DomainSuggestionsFragment; -import org.wordpress.android.ui.giphy.GiphyPickerActivity; +import org.wordpress.android.ui.gifs.GiphyPickerActivity; import org.wordpress.android.ui.history.HistoryAdapter; import org.wordpress.android.ui.history.HistoryDetailContainerFragment; import org.wordpress.android.ui.main.AddContentAdapter; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt similarity index 99% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt index 09b47f52aceb..dc0efeac17ae 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gifs import android.view.LayoutInflater import android.view.View diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt similarity index 99% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt index c977e783fdc9..7d7db09fa44c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gifs import android.app.Activity import android.content.Intent @@ -20,7 +20,7 @@ import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.ui.ActionableEmptyView import org.wordpress.android.ui.LocaleAwareActivity -import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions +import org.wordpress.android.ui.gifs.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.ui.media.MediaPreviewActivity import org.wordpress.android.util.AniUtils import org.wordpress.android.util.DisplayUtils diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt similarity index 94% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt index 0087e18a2731..3da7e8038ff1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt @@ -1,9 +1,9 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gifs import android.view.ViewGroup import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil.ItemCallback -import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions +import org.wordpress.android.ui.gifs.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/LifecycleOwnerViewHolder.kt similarity index 99% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gifs/LifecycleOwnerViewHolder.kt index 7c207dc25c48..fd6f0ba464bf 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/LifecycleOwnerViewHolder.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gifs import android.view.View import android.view.View.OnAttachStateChangeListener diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt index 7661aabff81f..a64ac84ef4e6 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt @@ -24,7 +24,7 @@ import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject /** - * Holds the data for [org.wordpress.android.ui.giphy.GiphyPickerActivity] + * Holds the data for [org.wordpress.android.ui.gifs.GiphyPickerActivity] * * This creates a [PagedList] which can be bound to by a [PagedListAdapter] and also manages the logic of the * selected media. That includes but not limited to keeping the [GiphyMediaViewModel.selectionNumber] continuous. From 47ac89acc5a3a8c7a821fd7a25abecb19d38cfc5 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sun, 22 Mar 2020 03:33:04 -0300 Subject: [PATCH 03/58] Created TenorProvider infrastructure and basic search --- WordPress/build.gradle | 1 + .../android/ui/gifs/provider/GifProvider.kt | 18 +++ .../android/ui/gifs/provider/TenorProvider.kt | 69 +++++++++++ WordPress/src/main/res/values/strings.xml | 3 + .../ui/gifs/provider/TenorProviderTest.kt | 109 ++++++++++++++++++ .../gifs/provider/TenorProviderTestUtils.kt | 27 +++++ 6 files changed, 227 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTest.kt create mode 100644 WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTestUtils.kt diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 81a728e6c5be..91202c04a861 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -225,6 +225,7 @@ dependencies { testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0' testImplementation "org.assertj:assertj-core:$assertJVersion" testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.2.1' + testImplementation 'androidx.test:core:1.2.0' androidTestImplementation 'org.mockito:mockito-android:2.27.0' androidTestImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0' diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt new file mode 100644 index 000000000000..fe60ca3ed0b0 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt @@ -0,0 +1,18 @@ +package org.wordpress.android.ui.gifs.provider + +import org.wordpress.android.R + +interface GifProvider { + fun search( + query: String, + onSuccess: (List) -> Unit, + onFailure: (String) -> Unit + ) + + data class Gif(val url: String) + + companion object { + const val queryReturnedNothingStringId = R.string.gifs_list_search_nothing_found + const val unknownErrorStringId = R.string.error + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt new file mode 100644 index 000000000000..7edc209cabe9 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt @@ -0,0 +1,69 @@ +package org.wordpress.android.ui.gifs.provider + +import android.content.Context +import com.tenor.android.core.constant.AspectRatioRange +import com.tenor.android.core.constant.MediaFilter +import com.tenor.android.core.network.ApiClient +import com.tenor.android.core.network.ApiService +import com.tenor.android.core.network.IApiClient +import com.tenor.android.core.response.WeakRefCallback +import com.tenor.android.core.response.impl.GifsResponse +import org.wordpress.android.BuildConfig +import org.wordpress.android.ui.gifs.provider.GifProvider.Gif + +internal class TenorProvider( + val context: Context, + client: IApiClient? = null +) : GifProvider { + private val tenorClient: IApiClient + private val searchResultLimit = 10 + + init { + ApiService.Builder(context, IApiClient::class.java).apply { + apiKey(BuildConfig.TENOR_API_KEY) + ApiClient.init(context, this) + tenorClient = client ?: ApiClient.getInstance(context) + } + } + + override fun search( + query: String, + onSuccess: (List) -> Unit, + onFailure: (String) -> Unit + ) { + tenorClient.simpleSearch(query, + onSuccess = { response -> + response?.run { results.map { Gif(it.url) } } + ?.let { onSuccess(it) } + ?: onFailure(context.getString(GifProvider.unknownErrorStringId)) + }, + onFail = { + onFailure(context.getString(GifProvider.queryReturnedNothingStringId)) + } + ) + } + + private inline fun IApiClient.simpleSearch( + query: String, + crossinline onSuccess: (GifsResponse?) -> Unit, + crossinline onFail: (Throwable?) -> Unit + ) { + search( + ApiClient.getServiceIds(context), + query, + searchResultLimit, + "", + MediaFilter.BASIC, + AspectRatioRange.ALL + + ).enqueue(object : WeakRefCallback(context) { + override fun success(ctx: Context, response: GifsResponse?) { + onSuccess(response) + } + + override fun failure(ctx: Context, throwable: Throwable?) { + onFail(throwable) + } + }) + } +} diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index c5067d92b343..911baee17772 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2658,6 +2658,9 @@ Search posts No posts matching your search + + No gifs matching your search + Default diff --git a/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTest.kt new file mode 100644 index 000000000000..293ec3bd10d6 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTest.kt @@ -0,0 +1,109 @@ +package org.wordpress.android.ui.gifs.provider + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.times +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import com.tenor.android.core.network.IApiClient +import com.tenor.android.core.response.WeakRefCallback +import com.tenor.android.core.response.impl.GifsResponse +import junit.framework.Assert.assertEquals +import junit.framework.Assert.fail +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.wordpress.android.TestApplication +import org.wordpress.android.ui.gifs.provider.TenorProviderTestUtils.Companion.createGifResultList +import org.wordpress.android.ui.gifs.provider.TenorProviderTestUtils.Companion.expectedGifList +import retrofit2.Call + +@Config(application = TestApplication::class) +@RunWith(RobolectricTestRunner::class) +class TenorProviderTest { + @Mock lateinit var apiClient: IApiClient + + @Mock lateinit var gifSearchCall: Call + + @Mock lateinit var gifResponse: GifsResponse + + @Captor lateinit var callbackCaptor: ArgumentCaptor> + + private lateinit var tenorProviderUnderTest: TenorProvider + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(apiClient.search(any(), any(), any(), any(), any(), any())) + .thenReturn(gifSearchCall) + + val gifResults = createGifResultList() + whenever(gifResponse.results).thenReturn(gifResults) + + tenorProviderUnderTest = TenorProvider(ApplicationProvider.getApplicationContext(), apiClient) + } + + @Test + fun `search call should invoke onSuccess with expected Gif list for valid query`() { + var onSuccessWasCalled = false + + tenorProviderUnderTest.search("test", + onSuccess = { + onSuccessWasCalled = true + assertEquals(expectedGifList, it) + }, + onFailure = { + fail("Failure handler should not be called") + }) + + verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) + val capturedCallback = callbackCaptor.value + capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) + assert(onSuccessWasCalled) { "onSuccess should be called" } + } + + @Test + fun `search call should invoke onFailure when callback returns failure`() { + var onFailureWasCalled = false + + tenorProviderUnderTest.search("test", + onSuccess = { + fail("Success handler should not be called") + }, + onFailure = { + onFailureWasCalled = true + assertEquals("No gifs matching your search", it) + }) + + verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) + val capturedCallback = callbackCaptor.value + capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException()) + assert(onFailureWasCalled) { "onFailure should be called" } + } + + @Test + fun `search call should invoke onFailure when null GifResponse is returned`() { + var onFailureWasCalled = false + + tenorProviderUnderTest.search("test", + onSuccess = { + fail("Success handler should not be called") + }, + onFailure = { + onFailureWasCalled = true + assertEquals("Error", it) + }) + + verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) + val capturedCallback = callbackCaptor.value + capturedCallback.success(ApplicationProvider.getApplicationContext(), null) + assert(onFailureWasCalled) { "onFailure should be called" } + } +} diff --git a/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTestUtils.kt new file mode 100644 index 000000000000..2a7da095f5cc --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTestUtils.kt @@ -0,0 +1,27 @@ +package org.wordpress.android.ui.gifs.provider + +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import com.tenor.android.core.model.impl.Result +import org.wordpress.android.ui.gifs.provider.GifProvider.Gif + +class TenorProviderTestUtils { + companion object { + internal fun createGifResultList(): List = listOf( + createGifResultMock("first GIF"), + createGifResultMock("second GIF"), + createGifResultMock("third GIF"), + createGifResultMock("fourth GIF") + ) + + private fun createGifResultMock(url: String): Result = + mock().apply { whenever(this.url).thenReturn(url) } + + internal val expectedGifList = listOf( + Gif("first GIF"), + Gif("second GIF"), + Gif("third GIF"), + Gif("fourth GIF") + ) + } +} From 99751e6f53d92fe83900f29394a60b1de24f765d Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sun, 22 Mar 2020 22:52:46 -0300 Subject: [PATCH 04/58] Added GifProvider and TenorProvider documentation --- .../android/ui/gifs/provider/GifProvider.kt | 18 ++++++++++++++ .../android/ui/gifs/provider/TenorProvider.kt | 24 +++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt index fe60ca3ed0b0..c19a2f8ec708 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt @@ -2,15 +2,33 @@ package org.wordpress.android.ui.gifs.provider import org.wordpress.android.R +/** + * Interface to interact with a GIF provider API avoiding coupling with the concrete implementation + */ interface GifProvider { + /** + * Request GIF search given a query string + * + * The [query] parameter represents the desired text to be search within the provider. + * [onSuccess] will be called if the Provider had success finding GIFs + * and will deliver a List with all matching GIFs + * [onFailure] will be called if the Provider didn't succeeded with the task of bringing GIFs, + * the delivered String will describe the error to be presented to the user + */ fun search( query: String, onSuccess: (List) -> Unit, onFailure: (String) -> Unit ) + /** + * A class to represent the default data model delivered by any [GifProvider] implementation + */ data class Gif(val url: String) + /** + * String resources to describe failures when a [onFailure] is called + */ companion object { const val queryReturnedNothingStringId = R.string.gifs_list_search_nothing_found const val unknownErrorStringId = R.string.error diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt index 7edc209cabe9..5f42bc2f11b8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt @@ -11,18 +11,28 @@ import com.tenor.android.core.response.impl.GifsResponse import org.wordpress.android.BuildConfig import org.wordpress.android.ui.gifs.provider.GifProvider.Gif +/** + * Implementation of a GifProvider using the Tenor gif API as provider + * + * This Provider performs requests to the Tenor API using the [tenorClient]. + */ + internal class TenorProvider( val context: Context, - client: IApiClient? = null + tenorClient: IApiClient? = null ) : GifProvider { - private val tenorClient: IApiClient + private val apiClient: IApiClient private val searchResultLimit = 10 + /** + * Initializes the Tenor API client with the environment API key, if no tenorClient is provided via constructor, + * the init will use the default implementation provided by the Tenor library. + */ init { ApiService.Builder(context, IApiClient::class.java).apply { apiKey(BuildConfig.TENOR_API_KEY) ApiClient.init(context, this) - tenorClient = client ?: ApiClient.getInstance(context) + apiClient = tenorClient ?: ApiClient.getInstance(context) } } @@ -31,13 +41,13 @@ internal class TenorProvider( onSuccess: (List) -> Unit, onFailure: (String) -> Unit ) { - tenorClient.simpleSearch(query, + apiClient.simpleSearch(query, onSuccess = { response -> response?.run { results.map { Gif(it.url) } } ?.let { onSuccess(it) } ?: onFailure(context.getString(GifProvider.unknownErrorStringId)) }, - onFail = { + onFailure = { onFailure(context.getString(GifProvider.queryReturnedNothingStringId)) } ) @@ -46,7 +56,7 @@ internal class TenorProvider( private inline fun IApiClient.simpleSearch( query: String, crossinline onSuccess: (GifsResponse?) -> Unit, - crossinline onFail: (Throwable?) -> Unit + crossinline onFailure: (Throwable?) -> Unit ) { search( ApiClient.getServiceIds(context), @@ -62,7 +72,7 @@ internal class TenorProvider( } override fun failure(ctx: Context, throwable: Throwable?) { - onFail(throwable) + onFailure(throwable) } }) } From d393dca4a3b72d6850e1b3368fda05f18901b8af Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Mon, 23 Mar 2020 02:15:21 -0300 Subject: [PATCH 05/58] GifProvider is now available through injection with Dagger and provided to the PickerDataSourceFactory --- .../org/wordpress/android/modules/ApplicationModule.java | 7 +++++++ .../wordpress/android/ui/gifs/provider/TenorProvider.kt | 2 +- .../android/viewmodel/giphy/GiphyPickerDataSource.kt | 2 ++ .../viewmodel/giphy/GiphyPickerDataSourceFactory.kt | 5 +++-- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index 1a71f80f37ff..4a85bfe81f09 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -10,6 +10,8 @@ import org.wordpress.android.ui.accounts.signup.UsernameChangerFullScreenDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.CountryPickerDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.StatePickerDialogFragment; +import org.wordpress.android.ui.gifs.provider.GifProvider; +import org.wordpress.android.ui.gifs.provider.TenorProvider; import org.wordpress.android.ui.news.LocalNewsService; import org.wordpress.android.ui.news.NewsService; import org.wordpress.android.ui.reader.ReaderPostWebViewCachingFragment; @@ -108,4 +110,9 @@ public static WizardManager provideWizardManager( static LiveData provideConnectionStatusLiveData(Context context) { return new ConnectionStatusLiveData.Factory(context).create(); } + + @Provides + static GifProvider provideGifProvider(Context context) { + return new TenorProvider(context); + } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt index 5f42bc2f11b8..dab7a03992bb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt @@ -17,7 +17,7 @@ import org.wordpress.android.ui.gifs.provider.GifProvider.Gif * This Provider performs requests to the Tenor API using the [tenorClient]. */ -internal class TenorProvider( +internal class TenorProvider @JvmOverloads constructor( val context: Context, tenorClient: IApiClient? = null ) : GifProvider { diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt index 4fe6bcc45712..b5c1ed88232e 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt @@ -3,6 +3,7 @@ package org.wordpress.android.viewmodel.giphy import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PositionalDataSource +import org.wordpress.android.ui.gifs.provider.GifProvider /** * The PagedListDataSource that is created and managed by [GiphyPickerDataSourceFactory] @@ -11,6 +12,7 @@ import androidx.paging.PositionalDataSource * [searchQuery] is changed by the user. */ class GiphyPickerDataSource( + private val gifProvider: GifProvider, private val searchQuery: String ) : PositionalDataSource() { /** diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt index 2134355e1a9e..9d85e17b6e40 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.paging.DataSource import androidx.paging.DataSource.Factory +import org.wordpress.android.ui.gifs.provider.GifProvider import javax.inject.Inject /** @@ -16,7 +17,7 @@ import javax.inject.Inject * 2. The [LivePagedListBuilder] will create a new [GiphyPickerDataSource] by calling [create] * 3. The new [GiphyPickerDataSource] will start another paged API request */ -class GiphyPickerDataSourceFactory @Inject constructor() : Factory() { +class GiphyPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { /** * The active search query. * @@ -52,7 +53,7 @@ class GiphyPickerDataSourceFactory @Inject constructor() : Factory { - val dataSource = GiphyPickerDataSource(searchQuery) + val dataSource = GiphyPickerDataSource(gifProvider, searchQuery) this.dataSource.postValue(dataSource) return dataSource } From c401c4c081d84ae01d4e2b8847d9368f517fc4c9 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Mon, 23 Mar 2020 03:02:38 -0300 Subject: [PATCH 06/58] Replaced Giphy name to Gif from all packages and classes --- .../android/modules/ApplicationModule.java | 4 +- .../android/modules/ViewModelModule.java | 6 +-- .../android/ui/gifs/GiphyMediaViewHolder.kt | 22 ++++---- .../android/ui/gifs/GiphyPickerActivity.kt | 18 +++---- .../ui/gifs/GiphyPickerPagedListAdapter.kt | 16 +++--- .../CoroutineScopedViewModel.kt | 2 +- .../GifMediaFetcher.kt} | 18 +++---- .../GifMediaViewModel.kt} | 4 +- .../GifPickerDataSource.kt} | 22 ++++---- .../GifPickerDataSourceFactory.kt} | 28 +++++----- .../GifPickerViewModel.kt} | 52 +++++++++---------- .../MutableGifMediaViewModel.kt} | 12 ++--- .../gif}/provider/GifProvider.kt | 2 +- .../gif}/provider/TenorProvider.kt | 4 +- .../GifPickerViewModelTest.kt} | 26 +++++----- .../gif}/provider/TenorProviderTest.kt | 6 +-- .../gif}/provider/TenorProviderTestUtils.kt | 4 +- 17 files changed, 123 insertions(+), 123 deletions(-) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy => gif}/CoroutineScopedViewModel.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyMediaFetcher.kt => gif/GifMediaFetcher.kt} (83%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyMediaViewModel.kt => gif/GifMediaViewModel.kt} (95%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerDataSource.kt => gif/GifPickerDataSource.kt} (81%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerDataSourceFactory.kt => gif/GifPickerDataSourceFactory.kt} (50%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerViewModel.kt => gif/GifPickerViewModel.kt} (87%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/MutableGiphyMediaViewModel.kt => gif/MutableGifMediaViewModel.kt} (78%) rename WordPress/src/main/java/org/wordpress/android/{ui/gifs => viewmodel/gif}/provider/GifProvider.kt (95%) rename WordPress/src/main/java/org/wordpress/android/{ui/gifs => viewmodel/gif}/provider/TenorProvider.kt (95%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerViewModelTest.kt => gif/GifPickerViewModelTest.kt} (93%) rename WordPress/src/test/java/org/wordpress/android/{ui/gifs => viewmodel/gif}/provider/TenorProviderTest.kt (93%) rename WordPress/src/test/java/org/wordpress/android/{ui/gifs => viewmodel/gif}/provider/TenorProviderTestUtils.kt (86%) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index 4a85bfe81f09..aecf71400167 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -10,8 +10,8 @@ import org.wordpress.android.ui.accounts.signup.UsernameChangerFullScreenDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.CountryPickerDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.StatePickerDialogFragment; -import org.wordpress.android.ui.gifs.provider.GifProvider; -import org.wordpress.android.ui.gifs.provider.TenorProvider; +import org.wordpress.android.viewmodel.gif.provider.GifProvider; +import org.wordpress.android.viewmodel.gif.provider.TenorProvider; import org.wordpress.android.ui.news.LocalNewsService; import org.wordpress.android.ui.news.NewsService; import org.wordpress.android.ui.reader.ReaderPostWebViewCachingFragment; diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java index cec149670aa7..643d9d4cfb13 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java @@ -37,7 +37,7 @@ import org.wordpress.android.viewmodel.activitylog.ActivityLogViewModel; import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel; import org.wordpress.android.viewmodel.domains.DomainSuggestionsViewModel; -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel; +import org.wordpress.android.viewmodel.gif.GifPickerViewModel; import org.wordpress.android.viewmodel.history.HistoryViewModel; import org.wordpress.android.viewmodel.main.WPMainActivityViewModel; import org.wordpress.android.viewmodel.pages.PageListViewModel; @@ -218,8 +218,8 @@ abstract class ViewModelModule { @Binds @IntoMap - @ViewModelKey(GiphyPickerViewModel.class) - abstract ViewModel giphyPickerViewModel(GiphyPickerViewModel viewModel); + @ViewModelKey(GifPickerViewModel.class) + abstract ViewModel giphyPickerViewModel(GifPickerViewModel viewModel); @Binds @IntoMap diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt index dc0efeac17ae..f3940aa939df 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt @@ -14,14 +14,14 @@ import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.util.image.ImageType.PHOTO import org.wordpress.android.util.redirectContextClickToLongPressListener -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel +import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** * Represents a single item in the [GiphyPickerActivity]'s grid (RecyclerView). * * This is meant to show a single animated gif. * - * This ViewHolder references a readonly [GiphyMediaViewModel]. It should never update the [GiphyMediaViewModel]. That + * This ViewHolder references a readonly [GifMediaViewModel]. It should never update the [GifMediaViewModel]. That * behavior is handled by the [GiphyPickerViewModel]. This is designed this way so that [GiphyPickerViewModel] * encapsulates all the logic of managing selected items as well as keeping their selection numbers continuous. */ @@ -35,11 +35,11 @@ class GiphyMediaViewHolder( * * If there is no bound [mediaViewModel], this can mean that there was an API error or this is just a placeholder. */ - private val onClickListener: (GiphyMediaViewModel?) -> Unit, + private val onClickListener: (GifMediaViewModel?) -> Unit, /** * A function that is called when the user performs a long press on the thumbnail */ - private val onLongClickListener: (GiphyMediaViewModel) -> Unit, + private val onLongClickListener: (GifMediaViewModel) -> Unit, /** * The view used for this `ViewHolder`. */ @@ -48,13 +48,13 @@ class GiphyMediaViewHolder( * The dimensions used for the ImageView */ thumbnailViewDimensions: ThumbnailViewDimensions -) : LifecycleOwnerViewHolder(itemView) { +) : LifecycleOwnerViewHolder(itemView) { data class ThumbnailViewDimensions(val width: Int, val height: Int) private val thumbnailView: ImageView = itemView.image_thumbnail private val selectionNumberTextView: TextView = itemView.text_selection_count - private var mediaViewModel: GiphyMediaViewModel? = null + private var mediaViewModel: GifMediaViewModel? = null init { thumbnailView.apply { @@ -72,13 +72,13 @@ class GiphyMediaViewHolder( } /** - * Update the views to use the given [GiphyMediaViewModel] + * Update the views to use the given [GifMediaViewModel] * * The [mediaViewModel] is optional because we enable placeholders in the paged list created by - * [org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel]. This causes null values to be bound to + * [org.wordpress.android.viewmodel.gif.GifPickerViewModel]. This causes null values to be bound to * [GiphyMediaViewHolder] instances. */ - override fun bind(item: GiphyMediaViewModel?) { + override fun bind(item: GifMediaViewModel?) { super.bind(item) this.mediaViewModel = item @@ -141,8 +141,8 @@ class GiphyMediaViewHolder( */ fun create( imageManager: ImageManager, - onClickListener: (GiphyMediaViewModel?) -> Unit, - onLongClickListener: (GiphyMediaViewModel) -> Unit, + onClickListener: (GifMediaViewModel?) -> Unit, + onLongClickListener: (GifMediaViewModel) -> Unit, parent: ViewGroup, thumbnailViewDimensions: ThumbnailViewDimensions ): GiphyMediaViewHolder { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt index 7d7db09fa44c..5514c97aca3a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt @@ -28,10 +28,10 @@ import org.wordpress.android.util.ToastUtils import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.ViewModelFactory -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.State +import org.wordpress.android.viewmodel.gif.GifMediaViewModel +import org.wordpress.android.viewmodel.gif.GifPickerViewModel +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.State import javax.inject.Inject /** @@ -46,7 +46,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { @Inject lateinit var imageManager: ImageManager @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: GiphyPickerViewModel + private lateinit var viewModel: GifPickerViewModel private val gridColumnCount: Int by lazy { if (DisplayUtils.isLandscape(this)) 4 else 3 } @@ -64,7 +64,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { val site = intent.getSerializableExtra(WordPress.SITE) as SiteModel - viewModel = ViewModelProviders.of(this, viewModelFactory).get(GiphyPickerViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(GifPickerViewModel::class.java) viewModel.setup(site) // We are intentionally reusing this layout since the UI is very similar. @@ -150,7 +150,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { } /** - * Configure the selection bar and its labels when the [GiphyPickerViewModel] selected items change + * Configure the selection bar and its labels when the [GifPickerViewModel] selected items change */ private fun initializeSelectionBar() { viewModel.selectionBarIsVisible.observe(this, Observer { @@ -275,7 +275,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { * * @param mediaViewModels A non-empty list */ - private fun showPreview(mediaViewModels: List) { + private fun showPreview(mediaViewModels: List) { check(mediaViewModels.isNotEmpty()) val uris = mediaViewModels.map { it.previewImageUri.toString() } @@ -308,7 +308,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { } /** - * Set up enabling/disabling of controls depending on the current [GiphyPickerViewModel.State]: + * Set up enabling/disabling of controls depending on the current [GifPickerViewModel.State]: * * - [State.IDLE]: All normal functions are allowed * - [State.DOWNLOADING] or [State.FINISHED]: "Add", "Preview", searching, and selecting are disabled diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt index 3da7e8038ff1..f7dcb86bb32d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt @@ -5,7 +5,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil.ItemCallback import org.wordpress.android.ui.gifs.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.util.image.ImageManager -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel +import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** * An [RecyclerView] adapter to be used with the [PagedList] created by [GiphyPickerViewModel] @@ -13,9 +13,9 @@ import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel class GiphyPickerPagedListAdapter( private val imageManager: ImageManager, private val thumbnailViewDimensions: ThumbnailViewDimensions, - private val onMediaViewClickListener: (GiphyMediaViewModel?) -> Unit, - private val onMediaViewLongClickListener: (GiphyMediaViewModel) -> Unit -) : PagedListAdapter(DIFF_CALLBACK) { + private val onMediaViewClickListener: (GifMediaViewModel?) -> Unit, + private val onMediaViewLongClickListener: (GifMediaViewModel) -> Unit +) : PagedListAdapter(DIFF_CALLBACK) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GiphyMediaViewHolder { return GiphyMediaViewHolder.create( imageManager = imageManager, @@ -31,18 +31,18 @@ class GiphyPickerPagedListAdapter( } companion object { - private val DIFF_CALLBACK = object : ItemCallback() { - override fun areItemsTheSame(oldItem: GiphyMediaViewModel, newItem: GiphyMediaViewModel): Boolean { + private val DIFF_CALLBACK = object : ItemCallback() { + override fun areItemsTheSame(oldItem: GifMediaViewModel, newItem: GifMediaViewModel): Boolean { return oldItem.id == newItem.id } /** - * Always assume that two similar [GiphyMediaViewModel] objects always have the same content. + * Always assume that two similar [GifMediaViewModel] objects always have the same content. * * It is probably extremely unlikely that GIFs from Giphy will change while the user is performing * a search. */ - override fun areContentsTheSame(oldItem: GiphyMediaViewModel, newItem: GiphyMediaViewModel): Boolean { + override fun areContentsTheSame(oldItem: GifMediaViewModel, newItem: GifMediaViewModel): Boolean { return true } } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt index bc33fb90d74d..475e7b23229b 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.ViewModel import kotlinx.coroutines.CoroutineScope diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt similarity index 83% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt index 38c617edfe2c..1d02c055c486 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import android.content.Context import android.webkit.MimeTypeMap @@ -18,13 +18,13 @@ import org.wordpress.android.util.WPMediaUtils import javax.inject.Inject /** - * Downloads [GiphyMediaViewModel.largeImageUri] objects and saves them as [MediaModel] + * Downloads [GifMediaViewModel.largeImageUri] objects and saves them as [MediaModel] * * The download happens concurrently and primarily uses [Dispatchers.IO]. This means that we are limited by the number * of threads backed by that `CoroutineDispatcher`. In the future, we should probably add a limit to the number of * GIFs that users can select to reduce the likelihood of OOM exceptions. */ -class GiphyMediaFetcher @Inject constructor( +class GifMediaFetcher @Inject constructor( private val context: Context, private val mediaStore: MediaStore, private val dispatcher: Dispatcher @@ -38,22 +38,22 @@ class GiphyMediaFetcher @Inject constructor( */ @Throws suspend fun fetchAndSave( - giphyMediaViewModels: List, + gifMediaViewModels: List, site: SiteModel ): List = coroutineScope { // Execute [fetchAndSave] for all giphyMediaViewModels first so that they are queued and executed in the // background. We'll call `await()` once they are queued. - return@coroutineScope giphyMediaViewModels.map { - fetchAndSave(scope = this, giphyMediaViewModel = it, site = site) + return@coroutineScope gifMediaViewModels.map { + fetchAndSave(scope = this, gifMediaViewModel = it, site = site) }.map { it.await() } } private fun fetchAndSave( scope: CoroutineScope, - giphyMediaViewModel: GiphyMediaViewModel, + gifMediaViewModel: GifMediaViewModel, site: SiteModel ): Deferred = scope.async(Dispatchers.IO) { - val uri = giphyMediaViewModel.largeImageUri + val uri = gifMediaViewModel.largeImageUri // No need to log the Exception here. The underlying method that is used, [MediaUtils.downloadExternalMedia] // already logs any errors. val downloadedUri = WPMediaUtils.fetchMedia(context, uri) ?: throw Exception("Failed to download the image.") @@ -65,7 +65,7 @@ class GiphyMediaFetcher @Inject constructor( val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension) val mediaModel = FluxCUtils.mediaModelFromLocalUri(context, downloadedUri, mimeType, mediaStore, site.id) - mediaModel.title = giphyMediaViewModel.title + mediaModel.title = gifMediaViewModel.title dispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(mediaModel)) return@async mediaModel diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt index 24a756e717a1..e660e309879f 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import android.net.Uri import androidx.lifecycle.LiveData @@ -15,7 +15,7 @@ import androidx.lifecycle.LiveData * See the [Giphy API docs](https://developers.giphy.com/docs/) for more information on what a [Media] object contains. * Search for "The GIF Object" section. */ -interface GiphyMediaViewModel { +interface GifMediaViewModel { /** * The id from Giphy's [Media] */ diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt similarity index 81% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt index b5c1ed88232e..2a44ca5ecefd 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt @@ -1,33 +1,33 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PositionalDataSource -import org.wordpress.android.ui.gifs.provider.GifProvider +import org.wordpress.android.viewmodel.gif.provider.GifProvider /** - * The PagedListDataSource that is created and managed by [GiphyPickerDataSourceFactory] + * The PagedListDataSource that is created and managed by [GifPickerDataSourceFactory] * * This performs paged API requests using the [apiClient]. A new instance of this class must be created if the * [searchQuery] is changed by the user. */ -class GiphyPickerDataSource( +class GifPickerDataSource( private val gifProvider: GifProvider, private val searchQuery: String -) : PositionalDataSource() { +) : PositionalDataSource() { /** * The data structure used for storing failed [loadRange] calls so they can be retried later. */ private data class RangeLoadArguments( val params: LoadRangeParams, - val callback: LoadRangeCallback + val callback: LoadRangeCallback ) /** * The error received when [loadInitial] fails. * * Unlike [rangeLoadErrorEvent], this is not a [LiveData] because the consumer of this method - * [GiphyPickerViewModel] simply uses it to check for null values and reacts to a different event. + * [GifPickerViewModel] simply uses it to check for null values and reacts to a different event. * * This is cleared when [loadInitial] is started. */ @@ -53,15 +53,15 @@ class GiphyPickerDataSource( /** * Always the load the first page (startingPosition = 0) from the Giphy API * - * The [GiphyPickerDataSourceFactory] recreates [GiphyPickerDataSource] instances whenever a new [searchQuery] + * The [GifPickerDataSourceFactory] recreates [GifPickerDataSource] instances whenever a new [searchQuery] * is queued. The [LoadInitialParams.requestedStartPosition] may have a value that is only valid for the * previous [searchQuery]. If that value is greater than the total search results of the new [searchQuery], * a crash will happen. * - * Using `0` as the `startPosition` forces the [GiphyPickerDataSource] consumer to reset the list (UI) from the + * Using `0` as the `startPosition` forces the [GifPickerDataSource] consumer to reset the list (UI) from the * top. */ - override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { + override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { val startPosition = 0 initialLoadError = null @@ -82,7 +82,7 @@ class GiphyPickerDataSource( * Errors are dispatched to [rangeLoadErrorEvent]. If successful, previously failed calls of this method are * automatically retried using [retryAllFailedRangeLoads]. */ - override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { + override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { // Logic removed for now. } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt similarity index 50% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt index 9d85e17b6e40..07104445195f 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt @@ -1,27 +1,27 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.paging.DataSource import androidx.paging.DataSource.Factory -import org.wordpress.android.ui.gifs.provider.GifProvider +import org.wordpress.android.viewmodel.gif.provider.GifProvider import javax.inject.Inject /** - * Creates instances of [GiphyPickerDataSource] + * Creates instances of [GifPickerDataSource] * * Whenever the [searchQuery] is changed: * - * 1. The last [GiphyPickerDataSource] is invalidated - * 2. The [LivePagedListBuilder] will create a new [GiphyPickerDataSource] by calling [create] - * 3. The new [GiphyPickerDataSource] will start another paged API request + * 1. The last [GifPickerDataSource] is invalidated + * 2. The [LivePagedListBuilder] will create a new [GifPickerDataSource] by calling [create] + * 3. The new [GifPickerDataSource] will start another paged API request */ -class GiphyPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { +class GifPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { /** * The active search query. * - * When changed, the current [GiphyPickerDataSource] will be invalidated. A new API search will be performed. + * When changed, the current [GifPickerDataSource] will be invalidated. A new API search will be performed. */ var searchQuery: String = "" set(value) { @@ -34,26 +34,26 @@ class GiphyPickerDataSourceFactory @Inject constructor(private val gifProvider: * * We retain this so we can invalidate it later when [searchQuery] is changed. */ - private val dataSource = MutableLiveData() + private val dataSource = MutableLiveData() /** - * The [GiphyPickerDataSource.initialLoadError] of the current [dataSource] + * The [GifPickerDataSource.initialLoadError] of the current [dataSource] */ val initialLoadError: Throwable? get() = dataSource.value?.initialLoadError /** - * The [GiphyPickerDataSource.rangeLoadErrorEvent] of the current [dataSource] + * The [GifPickerDataSource.rangeLoadErrorEvent] of the current [dataSource] */ val rangeLoadErrorEvent: LiveData = Transformations.switchMap(dataSource) { it.rangeLoadErrorEvent } /** * Retries all previously failed page loads. * - * @see [GiphyPickerDataSource.retryAllFailedRangeLoads] + * @see [GifPickerDataSource.retryAllFailedRangeLoads] */ fun retryAllFailedRangeLoads() = dataSource.value?.retryAllFailedRangeLoads() - override fun create(): DataSource { - val dataSource = GiphyPickerDataSource(gifProvider, searchQuery) + override fun create(): DataSource { + val dataSource = GifPickerDataSource(gifProvider, searchQuery) this.dataSource.postValue(dataSource) return dataSource } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt similarity index 87% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt index a64ac84ef4e6..5b7091acc2cb 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -27,19 +27,19 @@ import javax.inject.Inject * Holds the data for [org.wordpress.android.ui.gifs.GiphyPickerActivity] * * This creates a [PagedList] which can be bound to by a [PagedListAdapter] and also manages the logic of the - * selected media. That includes but not limited to keeping the [GiphyMediaViewModel.selectionNumber] continuous. + * selected media. That includes but not limited to keeping the [GifMediaViewModel.selectionNumber] continuous. * * Calling [setup] is required before using this ViewModel. */ -class GiphyPickerViewModel @Inject constructor( +class GifPickerViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, - private val mediaFetcher: GiphyMediaFetcher, + private val mediaFetcher: GifMediaFetcher, /** - * The [GiphyPickerDataSourceFactory] to use + * The [GifPickerDataSourceFactory] to use * * This is only available in the constructor to allow mocking in tests. */ - private val dataSourceFactory: GiphyPickerDataSourceFactory + private val dataSourceFactory: GifPickerDataSourceFactory ) : CoroutineScopedViewModel() { /** * A result of [downloadSelected] observed using the [downloadResult] LiveData @@ -95,7 +95,7 @@ class GiphyPickerViewModel @Inject constructor( /** * Errors that happened during page loads. * - * @see [GiphyPickerDataSource.rangeLoadErrorEvent] + * @see [GifPickerDataSource.rangeLoadErrorEvent] */ val rangeLoadErrorEvent: LiveData = dataSourceFactory.rangeLoadErrorEvent @@ -113,13 +113,13 @@ class GiphyPickerViewModel @Inject constructor( */ val downloadResult: LiveData = _downloadResult - private val _selectedMediaViewModelList = MutableLiveData>() + private val _selectedMediaViewModelList = MutableLiveData>() /** - * A [Map] of the [GiphyMediaViewModel]s that were selected by the user + * A [Map] of the [GifMediaViewModel]s that were selected by the user * - * This map is sorted in the order that the user picked them. The [String] is the value of [GiphyMediaViewModel.id]. + * This map is sorted in the order that the user picked them. The [String] is the value of [GifMediaViewModel.id]. */ - val selectedMediaViewModelList: LiveData> = _selectedMediaViewModelList + val selectedMediaViewModelList: LiveData> = _selectedMediaViewModelList /** * Returns `true` if the selection bar (UI) should be shown @@ -140,7 +140,7 @@ class GiphyPickerViewModel @Inject constructor( /** * The [PagedList] that should be displayed in the RecyclerView */ - val mediaViewModelPagedList: LiveData> by lazy { + val mediaViewModelPagedList: LiveData> by lazy { val pagedListConfig = PagedList.Config.Builder().setEnablePlaceholders(true).setPageSize(30).build() LivePagedListBuilder(dataSourceFactory, pagedListConfig).setBoundaryCallback(pagedListBoundaryCallback).build() } @@ -148,7 +148,7 @@ class GiphyPickerViewModel @Inject constructor( /** * Update the [emptyDisplayMode] depending on the number of API search results or whether there was an error. */ - private val pagedListBoundaryCallback = object : BoundaryCallback() { + private val pagedListBoundaryCallback = object : BoundaryCallback() { override fun onZeroItemsLoaded() { _isPerformingInitialLoad.postValue(false) @@ -161,7 +161,7 @@ class GiphyPickerViewModel @Inject constructor( super.onZeroItemsLoaded() } - override fun onItemAtFrontLoaded(itemAtFront: GiphyMediaViewModel) { + override fun onItemAtFrontLoaded(itemAtFront: GifMediaViewModel) { _isPerformingInitialLoad.postValue(false) _emptyDisplayMode.postValue(EmptyDisplayMode.HIDDEN) super.onItemAtFrontLoaded(itemAtFront) @@ -199,7 +199,7 @@ class GiphyPickerViewModel @Inject constructor( * when, presumably, the user has stopped typing. * * This also clears the [selectedMediaViewModelList]. This makes sense because the user will not be seeing the - * currently selected [GiphyMediaViewModel] if the new search query results are different. + * currently selected [GifMediaViewModel] if the new search query results are different. * * Searching is disabled if downloading or the [query] is the same as the last one. * @@ -231,7 +231,7 @@ class GiphyPickerViewModel @Inject constructor( } /** - * Downloads all the selected [GiphyMediaViewModel] + * Downloads all the selected [GifMediaViewModel] * * When the process is finished, the results will be posted to [downloadResult]. * @@ -276,17 +276,17 @@ class GiphyPickerViewModel @Inject constructor( } /** - * Toggles a [GiphyMediaViewModel]'s `isSelected` property between true and false + * Toggles a [GifMediaViewModel]'s `isSelected` property between true and false * - * This also updates the [GiphyMediaViewModel.selectionNumber] of all the objects in [selectedMediaViewModelList]. + * This also updates the [GifMediaViewModel.selectionNumber] of all the objects in [selectedMediaViewModelList]. */ - fun toggleSelected(mediaViewModel: GiphyMediaViewModel) { + fun toggleSelected(mediaViewModel: GifMediaViewModel) { if (_state.value != State.IDLE) { return } - assert(mediaViewModel is MutableGiphyMediaViewModel) - mediaViewModel as MutableGiphyMediaViewModel + assert(mediaViewModel is MutableGifMediaViewModel) + mediaViewModel as MutableGifMediaViewModel val isSelected = !(mediaViewModel.isSelected.value ?: false) @@ -308,14 +308,14 @@ class GiphyPickerViewModel @Inject constructor( } /** - * Update the [GiphyMediaViewModel.selectionNumber] values so that they are continuous + * Update the [GifMediaViewModel.selectionNumber] values so that they are continuous * - * For example, if the selection numbers are [1, 2, 3, 4, 5] and the 2nd [GiphyMediaViewModel] was removed, we + * For example, if the selection numbers are [1, 2, 3, 4, 5] and the 2nd [GifMediaViewModel] was removed, we * want the selection numbers to be updated to [1, 2, 3, 4] instead of leaving it as [1, 3, 4, 5]. */ - private fun rebuildSelectionNumbers(mediaList: LinkedHashMap) { + private fun rebuildSelectionNumbers(mediaList: LinkedHashMap) { mediaList.values.forEachIndexed { index, mediaViewModel -> - (mediaViewModel as MutableGiphyMediaViewModel).postSelectionNumber(index + 1) + (mediaViewModel as MutableGifMediaViewModel).postSelectionNumber(index + 1) } } @@ -341,7 +341,7 @@ class GiphyPickerViewModel @Inject constructor( /** * Retries all previously failed page loads. * - * @see [GiphyPickerDataSource.retryAllFailedRangeLoads] + * @see [GifPickerDataSource.retryAllFailedRangeLoads] */ fun retryAllFailedRangeLoads() = dataSourceFactory.retryAllFailedRangeLoads() } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt similarity index 78% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt index 1b3ef9f9905b..0e0bc3c42e15 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import android.net.Uri import androidx.lifecycle.LiveData @@ -6,21 +6,21 @@ import androidx.lifecycle.MutableLiveData import org.wordpress.android.viewmodel.SingleLiveEvent /** - * A mutable implementation of [GiphyMediaViewModel] + * A mutable implementation of [GifMediaViewModel] * - * This is meant to be accessible by [GiphyPickerViewModel] and [GiphyPickerDataSource] only. This is designed this - * way so that [GiphyPickerViewModel] encapsulates all the logic of managing selected items as well as keeping their + * This is meant to be accessible by [GifPickerViewModel] and [GifPickerDataSource] only. This is designed this + * way so that [GifPickerViewModel] encapsulates all the logic of managing selected items as well as keeping their * selection numbers continuous. * * The [GiphyPickerViewHolder] should never have access to the mutating methods of this class. */ -class MutableGiphyMediaViewModel( +class MutableGifMediaViewModel( override val id: String, override val thumbnailUri: Uri, override val previewImageUri: Uri, override val largeImageUri: Uri, override val title: String -) : GiphyMediaViewModel { +) : GifMediaViewModel { /** * Using [SingleLiveEvent] will prevent calls like this from running immediately when a ViewHolder is bound: * diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt index c19a2f8ec708..9663becbca19 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.gifs.provider +package org.wordpress.android.viewmodel.gif.provider import org.wordpress.android.R diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index dab7a03992bb..b82a15cd1a83 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.gifs.provider +package org.wordpress.android.viewmodel.gif.provider import android.content.Context import com.tenor.android.core.constant.AspectRatioRange @@ -9,7 +9,7 @@ import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse import org.wordpress.android.BuildConfig -import org.wordpress.android.ui.gifs.provider.GifProvider.Gif +import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif /** * Implementation of a GifProvider using the Tenor gif API as provider diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt similarity index 93% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt index 4c3480cdfd52..e5ee98cb25e9 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.paging.PositionalDataSource.LoadInitialCallback @@ -19,26 +19,26 @@ import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.util.NetworkUtilsWrapper -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.State +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.State import java.util.Random import java.util.UUID @RunWith(MockitoJUnitRunner::class) -class GiphyPickerViewModelTest { +class GifPickerViewModelTest { @get:Rule val rule = InstantTaskExecutorRule() - private lateinit var viewModel: GiphyPickerViewModel + private lateinit var viewModel: GifPickerViewModel - private val dataSourceFactory = mock() - private val mediaFetcher = mock() + private val dataSourceFactory = mock() + private val mediaFetcher = mock() @Mock private lateinit var networkUtils: NetworkUtilsWrapper @Before fun setUp() { - viewModel = GiphyPickerViewModel( + viewModel = GifPickerViewModel( dataSourceFactory = dataSourceFactory, networkUtils = networkUtils, mediaFetcher = mediaFetcher @@ -147,12 +147,12 @@ class GiphyPickerViewModelTest { @Test fun `when search results are empty, the empty view should be visible and says there are no results`() { // Arrange - val dataSource = mock() + val dataSource = mock() whenever(dataSourceFactory.create()).thenReturn(dataSource) whenever(dataSourceFactory.searchQuery).thenReturn("dummy") - val callbackCaptor = argumentCaptor>() + val callbackCaptor = argumentCaptor>() doNothing().whenever(dataSource).loadInitial(any(), callbackCaptor.capture()) // Observe mediaViewModelPagedList so the DataSourceFactory will be activated and perform API requests @@ -174,12 +174,12 @@ class GiphyPickerViewModelTest { @Test fun `when the initial load fails, the empty view should show a network error`() { // Arrange - val dataSource = mock() + val dataSource = mock() whenever(dataSourceFactory.create()).thenReturn(dataSource) whenever(dataSourceFactory.initialLoadError).thenReturn(mock()) - val callbackCaptor = argumentCaptor>() + val callbackCaptor = argumentCaptor>() doNothing().whenever(dataSource).loadInitial(any(), callbackCaptor.capture()) // Observe mediaViewModelPagedList so the DataSourceFactory will be activated and perform API requests @@ -313,7 +313,7 @@ class GiphyPickerViewModelTest { id = Random().nextInt() } - private fun createGiphyMediaViewModel() = MutableGiphyMediaViewModel( + private fun createGiphyMediaViewModel() = MutableGifMediaViewModel( id = UUID.randomUUID().toString(), thumbnailUri = mock(), largeImageUri = mock(), diff --git a/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt similarity index 93% rename from WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt index 293ec3bd10d6..a82ac3779296 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.gifs.provider +package org.wordpress.android.viewmodel.gif.provider import android.content.Context import androidx.test.core.app.ApplicationProvider @@ -21,8 +21,8 @@ import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.wordpress.android.TestApplication -import org.wordpress.android.ui.gifs.provider.TenorProviderTestUtils.Companion.createGifResultList -import org.wordpress.android.ui.gifs.provider.TenorProviderTestUtils.Companion.expectedGifList +import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.createGifResultList +import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.expectedGifList import retrofit2.Call @Config(application = TestApplication::class) diff --git a/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt similarity index 86% rename from WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTestUtils.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt index 2a7da095f5cc..0649b84d8547 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/gifs/provider/TenorProviderTestUtils.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt @@ -1,9 +1,9 @@ -package org.wordpress.android.ui.gifs.provider +package org.wordpress.android.viewmodel.gif.provider import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever import com.tenor.android.core.model.impl.Result -import org.wordpress.android.ui.gifs.provider.GifProvider.Gif +import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif class TenorProviderTestUtils { companion object { From 6554d8812c2489a409d8a0bdbf59edd04534b0df Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Mon, 23 Mar 2020 05:29:44 -0300 Subject: [PATCH 07/58] Connected the TenorProvider implementation to the expected GifMediaViewModel and GifPickerDataSource --- .../viewmodel/gif/GifPickerDataSource.kt | 28 +++++++--- .../viewmodel/gif/MutableGifMediaViewModel.kt | 9 ++++ .../viewmodel/gif/provider/GifProvider.kt | 16 ++++-- .../viewmodel/gif/provider/TenorProvider.kt | 53 +++++++++++++++---- 4 files changed, 86 insertions(+), 20 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt index 2a44ca5ecefd..3181f6ede3e1 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt @@ -68,12 +68,20 @@ class GifPickerDataSource( _rangeLoadErrorEvent.postValue(null) // Do not do any API call if the [searchQuery] is empty - if (searchQuery.isBlank()) { - callback.onResult(emptyList(), startPosition, 0) - return - } + when { + searchQuery.isBlank() -> + callback.onResult(emptyList(), startPosition, 0) - callback.onResult(emptyList(), startPosition, 0) + else -> gifProvider.search( + searchQuery, + startPosition, + params.requestedLoadSize, + onSuccess = { + callback.onResult(it, startPosition, it.size) + }, + onFailure = { callback.onResult(emptyList(), startPosition, 0) } + ) + } } /** @@ -83,7 +91,15 @@ class GifPickerDataSource( * automatically retried using [retryAllFailedRangeLoads]. */ override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { - // Logic removed for now. + gifProvider.search( + searchQuery, + params.startPosition, + params.loadSize, + onSuccess = { callback.onResult(it) }, + onFailure = { + failedRangeLoadArguments.add(RangeLoadArguments(params, callback)) + if(_rangeLoadErrorEvent.value == null) _rangeLoadErrorEvent.value = it + }) } /** diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt index 0e0bc3c42e15..857365cfe145 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt @@ -4,6 +4,7 @@ import android.net.Uri import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import org.wordpress.android.viewmodel.SingleLiveEvent +import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif /** * A mutable implementation of [GifMediaViewModel] @@ -21,6 +22,14 @@ class MutableGifMediaViewModel( override val largeImageUri: Uri, override val title: String ) : GifMediaViewModel { + constructor(id: String, title: String, gif: Gif) : this( + id = id, + thumbnailUri = gif.thumbnailUri, + previewImageUri = gif.previewImageUri, + largeImageUri = gif.largeImageUri, + title = title + ) + /** * Using [SingleLiveEvent] will prevent calls like this from running immediately when a ViewHolder is bound: * diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt index 9663becbca19..0ef2ef228a50 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt @@ -1,6 +1,8 @@ package org.wordpress.android.viewmodel.gif.provider +import android.net.Uri import org.wordpress.android.R +import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** * Interface to interact with a GIF provider API avoiding coupling with the concrete implementation @@ -10,6 +12,8 @@ interface GifProvider { * Request GIF search given a query string * * The [query] parameter represents the desired text to be search within the provider. + * [position] to request results starting from a given position for that [query] + * [loadSize] to request a result list limited to a specific amount * [onSuccess] will be called if the Provider had success finding GIFs * and will deliver a List with all matching GIFs * [onFailure] will be called if the Provider didn't succeeded with the task of bringing GIFs, @@ -17,14 +21,20 @@ interface GifProvider { */ fun search( query: String, - onSuccess: (List) -> Unit, - onFailure: (String) -> Unit + position: Int, + loadSize: Int? = null, + onSuccess: (List) -> Unit, + onFailure: (Throwable) -> Unit ) /** * A class to represent the default data model delivered by any [GifProvider] implementation */ - data class Gif(val url: String) + data class Gif( + val thumbnailUri: Uri, + val previewImageUri: Uri, + val largeImageUri: Uri + ) /** * String resources to describe failures when a [onFailure] is called diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index b82a15cd1a83..0357939c2407 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -1,14 +1,20 @@ package org.wordpress.android.viewmodel.gif.provider import android.content.Context +import android.net.Uri import com.tenor.android.core.constant.AspectRatioRange +import com.tenor.android.core.constant.MediaCollectionFormat import com.tenor.android.core.constant.MediaFilter +import com.tenor.android.core.model.impl.MediaCollection +import com.tenor.android.core.model.impl.Result import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.ApiService import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse import org.wordpress.android.BuildConfig +import org.wordpress.android.viewmodel.gif.GifMediaViewModel +import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif /** @@ -22,7 +28,7 @@ internal class TenorProvider @JvmOverloads constructor( tenorClient: IApiClient? = null ) : GifProvider { private val apiClient: IApiClient - private val searchResultLimit = 10 + private val maximumAllowedLoadSize = 50 /** * Initializes the Tenor API client with the environment API key, if no tenorClient is provided via constructor, @@ -38,31 +44,36 @@ internal class TenorProvider @JvmOverloads constructor( override fun search( query: String, - onSuccess: (List) -> Unit, - onFailure: (String) -> Unit + position: Int, + loadSize: Int?, + onSuccess: (List) -> Unit, + onFailure: (Throwable) -> Unit ) { - apiClient.simpleSearch(query, + apiClient.simpleSearch( + query, + position.toString(), + loadSize, onSuccess = { response -> - response?.run { results.map { Gif(it.url) } } + response?.run { results.map { it.toMutableGifMediaViewModel() } } ?.let { onSuccess(it) } - ?: onFailure(context.getString(GifProvider.unknownErrorStringId)) + ?: onFailure(RuntimeException()) }, - onFailure = { - onFailure(context.getString(GifProvider.queryReturnedNothingStringId)) - } + onFailure = { it?.let(onFailure) } ) } private inline fun IApiClient.simpleSearch( query: String, + position: String, + loadSize: Int?, crossinline onSuccess: (GifsResponse?) -> Unit, crossinline onFailure: (Throwable?) -> Unit ) { search( ApiClient.getServiceIds(context), query, - searchResultLimit, - "", + loadSize.fittedToMaximumAllowed, + position, MediaFilter.BASIC, AspectRatioRange.ALL @@ -76,4 +87,24 @@ internal class TenorProvider @JvmOverloads constructor( } }) } + + private fun Result.toMutableGifMediaViewModel() = MutableGifMediaViewModel( + id, + title, + medias.first().toGif() + ) + + private fun MediaCollection.toGif() = Gif( + thumbnailUri = Uri.parse(this[MediaCollectionFormat.GIF_NANO].url), + previewImageUri = Uri.parse(this[MediaCollectionFormat.GIF_TINY].url), + largeImageUri = Uri.parse(this[MediaCollectionFormat.GIF].url) + ) + + private val Int?.fittedToMaximumAllowed + get() = this?.let { + when { + this > maximumAllowedLoadSize -> maximumAllowedLoadSize + else -> this + } + } ?: maximumAllowedLoadSize } From e376715a05f823223bc85c38b9d19805b0d11159 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Mon, 23 Mar 2020 14:33:11 -0300 Subject: [PATCH 08/58] Improved test suite for TenorProvider with code refactor and more test cases --- .../viewmodel/gif/MutableGifMediaViewModel.kt | 2 +- .../viewmodel/gif/provider/GifProvider.kt | 7 +- .../viewmodel/gif/provider/TenorProvider.kt | 22 +++- .../gif/provider/TenorProviderTest.kt | 104 +++++++++++++++++- .../gif/provider/TenorProviderTestUtils.kt | 60 ++++++++-- 5 files changed, 172 insertions(+), 23 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt index 857365cfe145..f4c9a0b20082 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt @@ -15,7 +15,7 @@ import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif * * The [GiphyPickerViewHolder] should never have access to the mutating methods of this class. */ -class MutableGifMediaViewModel( +data class MutableGifMediaViewModel( override val id: String, override val thumbnailUri: Uri, override val previewImageUri: Uri, diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt index 0ef2ef228a50..8ac7649a9e4e 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt @@ -37,10 +37,7 @@ interface GifProvider { ) /** - * String resources to describe failures when a [onFailure] is called + * Exception to describe errors within the Provider when a [onFailure] is called */ - companion object { - const val queryReturnedNothingStringId = R.string.gifs_list_search_nothing_found - const val unknownErrorStringId = R.string.error - } + class GifRequestFailedException(message: String) : Exception(message) } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index 0357939c2407..0473df683fb0 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -13,9 +13,11 @@ import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse import org.wordpress.android.BuildConfig +import org.wordpress.android.R.string import org.wordpress.android.viewmodel.gif.GifMediaViewModel import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif +import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException /** * Implementation of a GifProvider using the Tenor gif API as provider @@ -53,15 +55,25 @@ internal class TenorProvider @JvmOverloads constructor( query, position.toString(), loadSize, - onSuccess = { response -> - response?.run { results.map { it.toMutableGifMediaViewModel() } } - ?.let { onSuccess(it) } - ?: onFailure(RuntimeException()) - }, + onSuccess = { handleResponse(it, onSuccess, onFailure) }, onFailure = { it?.let(onFailure) } ) } + private fun handleResponse( + response: GifsResponse?, + onSuccess: (List) -> Unit, + onFailure: (Throwable) -> Unit + ) { + response?.run { results.map { it.toMutableGifMediaViewModel() } } + ?.let { onSuccess(it) } + ?: onFailure( + GifRequestFailedException( + context.getString(string.gifs_list_search_nothing_found) + ) + ) + } + private inline fun IApiClient.simpleSearch( query: String, position: String, diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt index a82ac3779296..255e1db5a47b 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt @@ -6,6 +6,7 @@ import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever +import com.tenor.android.core.constant.MediaFilter import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse @@ -22,7 +23,7 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.wordpress.android.TestApplication import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.createGifResultList -import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.expectedGifList +import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.expectedMediaViewModelCollection import retrofit2.Call @Config(application = TestApplication::class) @@ -55,9 +56,10 @@ class TenorProviderTest { var onSuccessWasCalled = false tenorProviderUnderTest.search("test", + 0, onSuccess = { onSuccessWasCalled = true - assertEquals(expectedGifList, it) + assertEquals(expectedMediaViewModelCollection, it) }, onFailure = { fail("Failure handler should not be called") @@ -74,17 +76,18 @@ class TenorProviderTest { var onFailureWasCalled = false tenorProviderUnderTest.search("test", + 0, onSuccess = { fail("Success handler should not be called") }, onFailure = { onFailureWasCalled = true - assertEquals("No gifs matching your search", it) + assertEquals("Expected message", it.message) }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value - capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException()) + capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException("Expected message")) assert(onFailureWasCalled) { "onFailure should be called" } } @@ -93,12 +96,13 @@ class TenorProviderTest { var onFailureWasCalled = false tenorProviderUnderTest.search("test", + 0, onSuccess = { fail("Success handler should not be called") }, onFailure = { onFailureWasCalled = true - assertEquals("Error", it) + assertEquals("No gifs matching your search", it.message) }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) @@ -106,4 +110,94 @@ class TenorProviderTest { capturedCallback.success(ApplicationProvider.getApplicationContext(), null) assert(onFailureWasCalled) { "onFailure should be called" } } + + @Test + fun `search call must use BASIC as MediaFilter`() { + val argument = ArgumentCaptor.forClass(String::class.java) + + tenorProviderUnderTest.search( + "test", + 0, + onSuccess = {}, + onFailure = {}) + + verify(apiClient).search( + any(), + any(), + any(), + any(), + argument.capture(), + any() + ) + + assertEquals(MediaFilter.BASIC, argument.value) + } + + @Test + fun `search call without loadSize should use default maximum value`() { + val argument = ArgumentCaptor.forClass(Int::class.java) + + tenorProviderUnderTest.search( + "test", + 0, + onSuccess = {}, + onFailure = {}) + + verify(apiClient).search( + any(), + any(), + argument.capture(), + any(), + any(), + any() + ) + + assertEquals(50, argument.value) + } + + @Test + fun `search call with loadSize lower than 50 should be used`() { + val argument = ArgumentCaptor.forClass(Int::class.java) + + tenorProviderUnderTest.search( + "test", + 0, + 20, + onSuccess = {}, + onFailure = {}) + + verify(apiClient).search( + any(), + any(), + argument.capture(), + any(), + any(), + any() + ) + + assertEquals(20, argument.value) + } + + @Test + fun `search call with loadSize higher than 50 should be reduced back to default maximum value`() { + val argument = ArgumentCaptor.forClass(Int::class.java) + + tenorProviderUnderTest.search( + "test", + 0, + 1500, + onSuccess = {}, + onFailure = {}) + + verify(apiClient).search( + any(), + any(), + argument.capture(), + any(), + any(), + any() + ) + + assertEquals(50, argument.value) + } } diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt index 0649b84d8547..daf5b6616386 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt @@ -1,8 +1,13 @@ package org.wordpress.android.viewmodel.gif.provider +import android.net.Uri import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever +import com.tenor.android.core.constant.MediaCollectionFormat +import com.tenor.android.core.model.impl.Media +import com.tenor.android.core.model.impl.MediaCollection import com.tenor.android.core.model.impl.Result +import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif class TenorProviderTestUtils { @@ -14,14 +19,55 @@ class TenorProviderTestUtils { createGifResultMock("fourth GIF") ) - private fun createGifResultMock(url: String): Result = - mock().apply { whenever(this.url).thenReturn(url) } + private fun createGifResultMock(mockFilling: String) = + mock().apply { + whenever(this.id).thenReturn(mockFilling) + whenever(this.title).thenReturn(mockFilling) + val mediaCollection = createMediaCollectionMock(mockFilling) + whenever(this.medias).thenReturn(listOf(mediaCollection)) + } - internal val expectedGifList = listOf( - Gif("first GIF"), - Gif("second GIF"), - Gif("third GIF"), - Gif("fourth GIF") + private fun createMediaCollectionMock(mockContent: String) = + mock().apply { + val nanoGifMedia = createMediaMock("$mockContent gif_nano") + val tinyGifMedia = createMediaMock("$mockContent gif_tiny") + val gifMedia = createMediaMock("$mockContent gif") + + whenever(this[MediaCollectionFormat.GIF_NANO]).thenReturn(nanoGifMedia) + whenever(this[MediaCollectionFormat.GIF_TINY]).thenReturn(tinyGifMedia) + whenever(this[MediaCollectionFormat.GIF]).thenReturn(gifMedia) + } + + private fun createMediaMock(mockContent: String) = + mock().apply { whenever(this.url).thenReturn(mockContent) } + + internal val expectedMediaViewModelCollection = listOf( + MutableGifMediaViewModel( + "first GIF", + "first GIF", + createExpectedGif("first GIF") + ), + MutableGifMediaViewModel( + "second GIF", + "second GIF", + createExpectedGif("second GIF") + ), + MutableGifMediaViewModel( + "third GIF", + "third GIF", + createExpectedGif("third GIF") + ), + MutableGifMediaViewModel( + "fourth GIF", + "fourth GIF", + createExpectedGif("fourth GIF") + ) + ) + + private fun createExpectedGif(expectedContent: String) = Gif( + Uri.parse("$expectedContent gif_nano"), + Uri.parse("$expectedContent gif_tiny"), + Uri.parse("$expectedContent gif") ) } } From b2d093fc03697613fd1948c44c8ba65d6b420e51 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Mon, 23 Mar 2020 14:46:30 -0300 Subject: [PATCH 09/58] Improved code reuse, naming and deprecated assertion methods --- .../gif/provider/TenorProviderTest.kt | 19 +++++---- .../gif/provider/TenorProviderTestUtils.kt | 42 ++++++++----------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt index 255e1db5a47b..e7018f4592a2 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt @@ -10,8 +10,9 @@ import com.tenor.android.core.constant.MediaFilter import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse -import junit.framework.Assert.assertEquals -import junit.framework.Assert.fail +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.fail import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -22,8 +23,8 @@ import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.wordpress.android.TestApplication -import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.createGifResultList -import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.expectedMediaViewModelCollection +import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.mockedTenorResult import retrofit2.Call @Config(application = TestApplication::class) @@ -45,7 +46,7 @@ class TenorProviderTest { whenever(apiClient.search(any(), any(), any(), any(), any(), any())) .thenReturn(gifSearchCall) - val gifResults = createGifResultList() + val gifResults = mockedTenorResult whenever(gifResponse.results).thenReturn(gifResults) tenorProviderUnderTest = TenorProvider(ApplicationProvider.getApplicationContext(), apiClient) @@ -59,7 +60,7 @@ class TenorProviderTest { 0, onSuccess = { onSuccessWasCalled = true - assertEquals(expectedMediaViewModelCollection, it) + assertEquals(expectedGifMediaViewModelCollection, it) }, onFailure = { fail("Failure handler should not be called") @@ -68,7 +69,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) - assert(onSuccessWasCalled) { "onSuccess should be called" } + assertTrue("onSuccess should be called", onSuccessWasCalled) } @Test @@ -88,7 +89,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException("Expected message")) - assert(onFailureWasCalled) { "onFailure should be called" } + assertTrue("onFailure should be called", onFailureWasCalled) } @Test @@ -108,7 +109,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value capturedCallback.success(ApplicationProvider.getApplicationContext(), null) - assert(onFailureWasCalled) { "onFailure should be called" } + assertTrue("onFailure should be called", onFailureWasCalled) } @Test diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt index daf5b6616386..5ea8fb957f42 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt @@ -12,11 +12,19 @@ import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif class TenorProviderTestUtils { companion object { - internal fun createGifResultList(): List = listOf( - createGifResultMock("first GIF"), - createGifResultMock("second GIF"), - createGifResultMock("third GIF"), - createGifResultMock("fourth GIF") + internal val mockedTenorResult + get() = listOf( + createGifResultMock("first GIF"), + createGifResultMock("second GIF"), + createGifResultMock("third GIF"), + createGifResultMock("fourth GIF") + ) + + internal val expectedGifMediaViewModelCollection = listOf( + createExpectedGifMediaViewModel("first GIF"), + createExpectedGifMediaViewModel("second GIF"), + createExpectedGifMediaViewModel("third GIF"), + createExpectedGifMediaViewModel("fourth GIF") ) private fun createGifResultMock(mockFilling: String) = @@ -41,28 +49,12 @@ class TenorProviderTestUtils { private fun createMediaMock(mockContent: String) = mock().apply { whenever(this.url).thenReturn(mockContent) } - internal val expectedMediaViewModelCollection = listOf( - MutableGifMediaViewModel( - "first GIF", - "first GIF", - createExpectedGif("first GIF") - ), - MutableGifMediaViewModel( - "second GIF", - "second GIF", - createExpectedGif("second GIF") - ), + private fun createExpectedGifMediaViewModel(mockContent: String) = MutableGifMediaViewModel( - "third GIF", - "third GIF", - createExpectedGif("third GIF") - ), - MutableGifMediaViewModel( - "fourth GIF", - "fourth GIF", - createExpectedGif("fourth GIF") + mockContent, + mockContent, + createExpectedGif(mockContent) ) - ) private fun createExpectedGif(expectedContent: String) = Gif( Uri.parse("$expectedContent gif_nano"), From 2e06912b564bd6df670c73408e7145e1b4e298da Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 01:21:54 -0300 Subject: [PATCH 10/58] Gif data class removed, using the MutableGifMediaViewModel instead. Added more documentation --- .../android/modules/ApplicationModule.java | 4 +- .../android/modules/ViewModelModule.java | 2 +- .../android/ui/gifs/GiphyMediaViewHolder.kt | 4 +- .../android/ui/gifs/GiphyPickerActivity.kt | 8 +- .../ui/gifs/GiphyPickerPagedListAdapter.kt | 2 +- .../viewmodel/gif/provider/TenorProvider.kt | 122 ------------ .../{gif => gifs}/CoroutineScopedViewModel.kt | 2 +- .../{gif => gifs}/GifMediaFetcher.kt | 2 +- .../{gif => gifs}/GifMediaViewModel.kt | 2 +- .../{gif => gifs}/GifPickerDataSource.kt | 6 +- .../GifPickerDataSourceFactory.kt | 4 +- .../{gif => gifs}/GifPickerViewModel.kt | 2 +- .../{gif => gifs}/MutableGifMediaViewModel.kt | 11 +- .../{gif => gifs}/provider/GifProvider.kt | 23 +-- .../viewmodel/gifs/provider/TenorProvider.kt | 181 ++++++++++++++++++ WordPress/src/main/res/values/strings.xml | 10 +- .../{gif => gifs}/GifPickerViewModelTest.kt | 6 +- .../provider/TenorProviderTest.kt | 13 +- .../provider/TenorProviderTestUtils.kt | 21 +- 19 files changed, 230 insertions(+), 195 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/CoroutineScopedViewModel.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/GifMediaFetcher.kt (98%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/GifMediaViewModel.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/GifPickerDataSource.kt (96%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/GifPickerDataSourceFactory.kt (94%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/GifPickerViewModel.kt (99%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/MutableGifMediaViewModel.kt (82%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gif => gifs}/provider/GifProvider.kt (56%) create mode 100644 WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt rename WordPress/src/test/java/org/wordpress/android/viewmodel/{gif => gifs}/GifPickerViewModelTest.kt (98%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{gif => gifs}/provider/TenorProviderTest.kt (90%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{gif => gifs}/provider/TenorProviderTestUtils.kt (78%) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index aecf71400167..2151df578f5b 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -10,8 +10,8 @@ import org.wordpress.android.ui.accounts.signup.UsernameChangerFullScreenDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.CountryPickerDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.StatePickerDialogFragment; -import org.wordpress.android.viewmodel.gif.provider.GifProvider; -import org.wordpress.android.viewmodel.gif.provider.TenorProvider; +import org.wordpress.android.viewmodel.gifs.provider.GifProvider; +import org.wordpress.android.viewmodel.gifs.provider.TenorProvider; import org.wordpress.android.ui.news.LocalNewsService; import org.wordpress.android.ui.news.NewsService; import org.wordpress.android.ui.reader.ReaderPostWebViewCachingFragment; diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java index 643d9d4cfb13..31c9f5657cb6 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java @@ -37,7 +37,7 @@ import org.wordpress.android.viewmodel.activitylog.ActivityLogViewModel; import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel; import org.wordpress.android.viewmodel.domains.DomainSuggestionsViewModel; -import org.wordpress.android.viewmodel.gif.GifPickerViewModel; +import org.wordpress.android.viewmodel.gifs.GifPickerViewModel; import org.wordpress.android.viewmodel.history.HistoryViewModel; import org.wordpress.android.viewmodel.main.WPMainActivityViewModel; import org.wordpress.android.viewmodel.pages.PageListViewModel; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt index f3940aa939df..846c79001fee 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt @@ -14,7 +14,7 @@ import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.util.image.ImageType.PHOTO import org.wordpress.android.util.redirectContextClickToLongPressListener -import org.wordpress.android.viewmodel.gif.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GifMediaViewModel /** * Represents a single item in the [GiphyPickerActivity]'s grid (RecyclerView). @@ -75,7 +75,7 @@ class GiphyMediaViewHolder( * Update the views to use the given [GifMediaViewModel] * * The [mediaViewModel] is optional because we enable placeholders in the paged list created by - * [org.wordpress.android.viewmodel.gif.GifPickerViewModel]. This causes null values to be bound to + * [org.wordpress.android.viewmodel.gifs.GifPickerViewModel]. This causes null values to be bound to * [GiphyMediaViewHolder] instances. */ override fun bind(item: GifMediaViewModel?) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt index 5514c97aca3a..00a95ffd3b08 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt @@ -28,10 +28,10 @@ import org.wordpress.android.util.ToastUtils import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.ViewModelFactory -import org.wordpress.android.viewmodel.gif.GifMediaViewModel -import org.wordpress.android.viewmodel.gif.GifPickerViewModel -import org.wordpress.android.viewmodel.gif.GifPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.gif.GifPickerViewModel.State +import org.wordpress.android.viewmodel.gifs.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GifPickerViewModel +import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.State import javax.inject.Inject /** diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt index f7dcb86bb32d..904080b760c3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt @@ -5,7 +5,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil.ItemCallback import org.wordpress.android.ui.gifs.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.util.image.ImageManager -import org.wordpress.android.viewmodel.gif.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GifMediaViewModel /** * An [RecyclerView] adapter to be used with the [PagedList] created by [GiphyPickerViewModel] diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt deleted file mode 100644 index 0473df683fb0..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt +++ /dev/null @@ -1,122 +0,0 @@ -package org.wordpress.android.viewmodel.gif.provider - -import android.content.Context -import android.net.Uri -import com.tenor.android.core.constant.AspectRatioRange -import com.tenor.android.core.constant.MediaCollectionFormat -import com.tenor.android.core.constant.MediaFilter -import com.tenor.android.core.model.impl.MediaCollection -import com.tenor.android.core.model.impl.Result -import com.tenor.android.core.network.ApiClient -import com.tenor.android.core.network.ApiService -import com.tenor.android.core.network.IApiClient -import com.tenor.android.core.response.WeakRefCallback -import com.tenor.android.core.response.impl.GifsResponse -import org.wordpress.android.BuildConfig -import org.wordpress.android.R.string -import org.wordpress.android.viewmodel.gif.GifMediaViewModel -import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel -import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif -import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException - -/** - * Implementation of a GifProvider using the Tenor gif API as provider - * - * This Provider performs requests to the Tenor API using the [tenorClient]. - */ - -internal class TenorProvider @JvmOverloads constructor( - val context: Context, - tenorClient: IApiClient? = null -) : GifProvider { - private val apiClient: IApiClient - private val maximumAllowedLoadSize = 50 - - /** - * Initializes the Tenor API client with the environment API key, if no tenorClient is provided via constructor, - * the init will use the default implementation provided by the Tenor library. - */ - init { - ApiService.Builder(context, IApiClient::class.java).apply { - apiKey(BuildConfig.TENOR_API_KEY) - ApiClient.init(context, this) - apiClient = tenorClient ?: ApiClient.getInstance(context) - } - } - - override fun search( - query: String, - position: Int, - loadSize: Int?, - onSuccess: (List) -> Unit, - onFailure: (Throwable) -> Unit - ) { - apiClient.simpleSearch( - query, - position.toString(), - loadSize, - onSuccess = { handleResponse(it, onSuccess, onFailure) }, - onFailure = { it?.let(onFailure) } - ) - } - - private fun handleResponse( - response: GifsResponse?, - onSuccess: (List) -> Unit, - onFailure: (Throwable) -> Unit - ) { - response?.run { results.map { it.toMutableGifMediaViewModel() } } - ?.let { onSuccess(it) } - ?: onFailure( - GifRequestFailedException( - context.getString(string.gifs_list_search_nothing_found) - ) - ) - } - - private inline fun IApiClient.simpleSearch( - query: String, - position: String, - loadSize: Int?, - crossinline onSuccess: (GifsResponse?) -> Unit, - crossinline onFailure: (Throwable?) -> Unit - ) { - search( - ApiClient.getServiceIds(context), - query, - loadSize.fittedToMaximumAllowed, - position, - MediaFilter.BASIC, - AspectRatioRange.ALL - - ).enqueue(object : WeakRefCallback(context) { - override fun success(ctx: Context, response: GifsResponse?) { - onSuccess(response) - } - - override fun failure(ctx: Context, throwable: Throwable?) { - onFailure(throwable) - } - }) - } - - private fun Result.toMutableGifMediaViewModel() = MutableGifMediaViewModel( - id, - title, - medias.first().toGif() - ) - - private fun MediaCollection.toGif() = Gif( - thumbnailUri = Uri.parse(this[MediaCollectionFormat.GIF_NANO].url), - previewImageUri = Uri.parse(this[MediaCollectionFormat.GIF_TINY].url), - largeImageUri = Uri.parse(this[MediaCollectionFormat.GIF].url) - ) - - private val Int?.fittedToMaximumAllowed - get() = this?.let { - when { - this > maximumAllowedLoadSize -> maximumAllowedLoadSize - else -> this - } - } ?: maximumAllowedLoadSize -} diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/CoroutineScopedViewModel.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/CoroutineScopedViewModel.kt index 475e7b23229b..251bb6dd3453 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/CoroutineScopedViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import androidx.lifecycle.ViewModel import kotlinx.coroutines.CoroutineScope diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaFetcher.kt similarity index 98% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaFetcher.kt index 1d02c055c486..0f3e1b293d73 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaFetcher.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import android.content.Context import android.webkit.MimeTypeMap diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaViewModel.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaViewModel.kt index e660e309879f..37268c46479f 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import android.net.Uri import androidx.lifecycle.LiveData diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt similarity index 96% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt index 3181f6ede3e1..3abafab4e550 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt @@ -1,9 +1,9 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PositionalDataSource -import org.wordpress.android.viewmodel.gif.provider.GifProvider +import org.wordpress.android.viewmodel.gifs.provider.GifProvider /** * The PagedListDataSource that is created and managed by [GifPickerDataSourceFactory] @@ -67,8 +67,8 @@ class GifPickerDataSource( initialLoadError = null _rangeLoadErrorEvent.postValue(null) - // Do not do any API call if the [searchQuery] is empty when { + // Do not do any API call if the [searchQuery] is empty searchQuery.isBlank() -> callback.onResult(emptyList(), startPosition, 0) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSourceFactory.kt similarity index 94% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSourceFactory.kt index 07104445195f..32811e471255 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSourceFactory.kt @@ -1,11 +1,11 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.paging.DataSource import androidx.paging.DataSource.Factory -import org.wordpress.android.viewmodel.gif.provider.GifProvider +import org.wordpress.android.viewmodel.gifs.provider.GifProvider import javax.inject.Inject /** diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt similarity index 99% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt index 5b7091acc2cb..127e970cc234 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGifMediaViewModel.kt similarity index 82% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGifMediaViewModel.kt index f4c9a0b20082..ec632eba74cd 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGifMediaViewModel.kt @@ -1,10 +1,9 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import android.net.Uri import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import org.wordpress.android.viewmodel.SingleLiveEvent -import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif /** * A mutable implementation of [GifMediaViewModel] @@ -22,14 +21,6 @@ data class MutableGifMediaViewModel( override val largeImageUri: Uri, override val title: String ) : GifMediaViewModel { - constructor(id: String, title: String, gif: Gif) : this( - id = id, - thumbnailUri = gif.thumbnailUri, - previewImageUri = gif.previewImageUri, - largeImageUri = gif.largeImageUri, - title = title - ) - /** * Using [SingleLiveEvent] will prevent calls like this from running immediately when a ViewHolder is bound: * diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt similarity index 56% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt index 8ac7649a9e4e..e18d3fcda560 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt @@ -1,22 +1,20 @@ -package org.wordpress.android.viewmodel.gif.provider +package org.wordpress.android.viewmodel.gifs.provider -import android.net.Uri -import org.wordpress.android.R -import org.wordpress.android.viewmodel.gif.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GifMediaViewModel /** * Interface to interact with a GIF provider API avoiding coupling with the concrete implementation */ interface GifProvider { /** - * Request GIF search given a query string + * Request GIF search from a query string * - * The [query] parameter represents the desired text to be search within the provider. + * The [query] parameter represents the desired text to search within the provider. * [position] to request results starting from a given position for that [query] * [loadSize] to request a result list limited to a specific amount * [onSuccess] will be called if the Provider had success finding GIFs * and will deliver a List with all matching GIFs - * [onFailure] will be called if the Provider didn't succeeded with the task of bringing GIFs, + * [onFailure] will be called if the Provider didn't succeed with the task of bringing GIFs, * the delivered String will describe the error to be presented to the user */ fun search( @@ -28,16 +26,7 @@ interface GifProvider { ) /** - * A class to represent the default data model delivered by any [GifProvider] implementation - */ - data class Gif( - val thumbnailUri: Uri, - val previewImageUri: Uri, - val largeImageUri: Uri - ) - - /** - * Exception to describe errors within the Provider when a [onFailure] is called + * An Exception to describe errors within the Provider when a [onFailure] is called */ class GifRequestFailedException(message: String) : Exception(message) } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt new file mode 100644 index 000000000000..a2cc2c369ea4 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt @@ -0,0 +1,181 @@ +package org.wordpress.android.viewmodel.gifs.provider + +import android.content.Context +import android.net.Uri +import com.tenor.android.core.constant.AspectRatioRange +import com.tenor.android.core.constant.MediaCollectionFormat +import com.tenor.android.core.constant.MediaFilter +import com.tenor.android.core.model.impl.Result +import com.tenor.android.core.network.ApiClient +import com.tenor.android.core.network.ApiService +import com.tenor.android.core.network.IApiClient +import com.tenor.android.core.response.WeakRefCallback +import com.tenor.android.core.response.impl.GifsResponse +import org.wordpress.android.BuildConfig +import org.wordpress.android.R.string +import org.wordpress.android.viewmodel.gifs.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.MutableGifMediaViewModel +import org.wordpress.android.viewmodel.gifs.provider.GifProvider.GifRequestFailedException + +/** + * Implementation of a GifProvider using the Tenor GIF API as provider + * + * This Provider performs requests to the Tenor API using the [tenorClient]. + */ + +internal class TenorProvider @JvmOverloads constructor( + val context: Context, + tenorClient: IApiClient? = null +) : GifProvider { + private val apiClient: IApiClient + /** + * To better refers to the Tenor API maximum GIF limit per request + */ + private val maximumAllowedLoadSize = 50 + + /** + * Initializes the Tenor API client with the environment API key, if no tenorClient is provided via constructor, + * the init will use the default implementation provided by the Tenor library. + */ + init { + ApiService.Builder(context, IApiClient::class.java).apply { + apiKey(BuildConfig.TENOR_API_KEY) + ApiClient.init(context, this) + /** + * If we call [ApiClient.getInstance] before the [ApiClient.init] the Tenor API + * will throw an exception for an illegal operation, but to still make possible for the + * constructor to have the [tenorClient] as a optional parameter, the actual [apiClient] + * will be decided after everything is initialized + */ + apiClient = tenorClient ?: ApiClient.getInstance(context) + } + } + + /** + * Implementation of the [GifProvider] search method, it will call the Tenor client search + * right away with the provided parameters. + */ + override fun search( + query: String, + position: Int, + loadSize: Int?, + onSuccess: (List) -> Unit, + onFailure: (Throwable) -> Unit + ) { + apiClient.simpleSearch( + query, + position.toString(), + loadSize, + onSuccess = { + handleResponse(it, onSuccess, onFailure) + }, + onFailure = { + it?.let { throwable -> + handleFailure(throwable, onFailure) + } + } + ) + } + + /** + * This method act as a simplification to call a search within the Tenor API and the callback + * creation + * [MediaFilter] must be BASIC or the returned Media will not have a displayable thumbnail + * All other provided parameters are set following the Tenor API Documentation + * + * Method is inlined for better high-order functions performance + */ + private inline fun IApiClient.simpleSearch( + query: String, + position: String, + loadSize: Int?, + crossinline onSuccess: (GifsResponse?) -> Unit, + crossinline onFailure: (Throwable?) -> Unit + ) { + search( + ApiClient.getServiceIds(context), + query, + loadSize.fittedToMaximumAllowed, + position, + MediaFilter.BASIC, + AspectRatioRange.ALL + + ).enqueue(object : WeakRefCallback(context) { + override fun success(ctx: Context, response: GifsResponse?) { + onSuccess(response) + } + + override fun failure(ctx: Context, throwable: Throwable?) { + onFailure(throwable) + } + }) + } + + /** + * When the Tenor API returns the [GifsResponse] this method will try to parse it + * to a [List] of [GifMediaViewModel], if the parse fails, the [onFailure] will be called + * with a [GifRequestFailedException] assuming that no valid GIF was found + * + * Method is inlined for better high-order functions performance + */ + private inline fun handleResponse( + response: GifsResponse?, + onSuccess: (List) -> Unit, + onFailure: (Throwable) -> Unit + ) { + response?.run { results.map { it.toMutableGifMediaViewModel() } } + ?.let { onSuccess(it) } + ?: onFailure( + GifRequestFailedException( + context.getString(string.giphy_picker_empty_search_list) + ) + ) + } + + /** + * If the search request fails an [GifRequestFailedException] will be passed with the API + * message. If there's no message provided, a generic message will be applied. + */ + private inline fun handleFailure( + throwable: Throwable, + onFailure: (Throwable) -> Unit + ) { + throwable.message?.let { message -> + onFailure(GifRequestFailedException(message)) + } ?: onFailure( + GifRequestFailedException( + context.getString(string.gifs_list_search_returned_unknown_error) + ) + ) + } + + /** + * Every GIF returned by the Tenor will be available as [Result], to better interface + * with our app, it will be converted to [MutableGifMediaViewModel] to avoid any external + * coupling with the Tenor API + */ + private fun Result.toMutableGifMediaViewModel() = MutableGifMediaViewModel( + id, + Uri.parse(urlFromCollectionFormat(MediaCollectionFormat.GIF_NANO)), + Uri.parse(urlFromCollectionFormat(MediaCollectionFormat.GIF_TINY)), + Uri.parse(urlFromCollectionFormat(MediaCollectionFormat.GIF)), + title + ) + + private fun Result.urlFromCollectionFormat(format: String) = + medias.firstOrNull()?.get(format)?.url + + /** + * Since the Tenor only allows a maximum of 50 GIFs per request, the API will throw + * an exception if this rule is disrespected, in order to still be resilient in + * provide the desired search, the loadSize will be reduced to the maximum allowed + * if needed + */ + private val Int?.fittedToMaximumAllowed + get() = this?.let { + when { + this > maximumAllowedLoadSize -> maximumAllowedLoadSize + else -> this + } + } ?: maximumAllowedLoadSize +} diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 911baee17772..202f6fb5351c 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2253,11 +2253,13 @@ Search to find free photos to add to your Media Library Photos provided by %s - Search Giphy + + Search Tenor Search to find GIFs to add to your Media Library! No media matching your search Some media failed to load due to a network error. - Powered by GIPHY + Sorry, there was a problem + Powered by Tenor Saving post as draft @@ -2658,10 +2660,6 @@ Search posts No posts matching your search - - No gifs matching your search - - Default Desktop diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModelTest.kt similarity index 98% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModelTest.kt index e5ee98cb25e9..3632a8fa421f 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModelTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gif +package org.wordpress.android.viewmodel.gifs import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.paging.PositionalDataSource.LoadInitialCallback @@ -19,8 +19,8 @@ import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.util.NetworkUtilsWrapper -import org.wordpress.android.viewmodel.gif.GifPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.gif.GifPickerViewModel.State +import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.State import java.util.Random import java.util.UUID diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt similarity index 90% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt index e7018f4592a2..9d77d160d3c8 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gif.provider +package org.wordpress.android.viewmodel.gifs.provider import android.content.Context import androidx.test.core.app.ApplicationProvider @@ -23,8 +23,9 @@ import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.wordpress.android.TestApplication -import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.expectedGifMediaViewModelCollection -import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestUtils.Companion.mockedTenorResult +import org.wordpress.android.viewmodel.gifs.provider.GifProvider.GifRequestFailedException +import org.wordpress.android.viewmodel.gifs.provider.TenorProviderTestUtils.Companion.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.gifs.provider.TenorProviderTestUtils.Companion.mockedTenorResult import retrofit2.Call @Config(application = TestApplication::class) @@ -53,7 +54,7 @@ class TenorProviderTest { } @Test - fun `search call should invoke onSuccess with expected Gif list for valid query`() { + fun `search call should invoke onSuccess with expected GIF list for valid query`() { var onSuccessWasCalled = false tenorProviderUnderTest.search("test", @@ -83,6 +84,7 @@ class TenorProviderTest { }, onFailure = { onFailureWasCalled = true + assertTrue(it is GifRequestFailedException) assertEquals("Expected message", it.message) }) @@ -103,7 +105,8 @@ class TenorProviderTest { }, onFailure = { onFailureWasCalled = true - assertEquals("No gifs matching your search", it.message) + assertTrue(it is GifRequestFailedException) + assertEquals("No GIFs matching your search", it.message) }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt similarity index 78% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt index 5ea8fb957f42..b9e0e58b6c5c 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestUtils.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gif.provider +package org.wordpress.android.viewmodel.gifs.provider import android.net.Uri import com.nhaarman.mockitokotlin2.mock @@ -7,8 +7,7 @@ import com.tenor.android.core.constant.MediaCollectionFormat import com.tenor.android.core.model.impl.Media import com.tenor.android.core.model.impl.MediaCollection import com.tenor.android.core.model.impl.Result -import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel -import org.wordpress.android.viewmodel.gif.provider.GifProvider.Gif +import org.wordpress.android.viewmodel.gifs.MutableGifMediaViewModel class TenorProviderTestUtils { companion object { @@ -49,17 +48,13 @@ class TenorProviderTestUtils { private fun createMediaMock(mockContent: String) = mock().apply { whenever(this.url).thenReturn(mockContent) } - private fun createExpectedGifMediaViewModel(mockContent: String) = + private fun createExpectedGifMediaViewModel(expectedContent: String) = MutableGifMediaViewModel( - mockContent, - mockContent, - createExpectedGif(mockContent) + expectedContent, + Uri.parse("$expectedContent gif_nano"), + Uri.parse("$expectedContent gif_tiny"), + Uri.parse("$expectedContent gif"), + expectedContent ) - - private fun createExpectedGif(expectedContent: String) = Gif( - Uri.parse("$expectedContent gif_nano"), - Uri.parse("$expectedContent gif_tiny"), - Uri.parse("$expectedContent gif") - ) } } From bddff064c5dfaf10fafb111dfcc6b8fbcecd50c5 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 02:13:55 -0300 Subject: [PATCH 11/58] Fixed GiphyPickerActivity reference on AndroidManifest --- WordPress/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 3855fffeea59..8d2437d74253 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -529,7 +529,7 @@ android:label="" android:theme="@style/WordPress.NoActionBar" /> From a75cd473ea2d921a3ffef0a3d647a38637825ab5 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 07:07:30 -0300 Subject: [PATCH 12/58] Integrated pagination into the Tenor requests --- .../viewmodel/gifs/GifPickerDataSource.kt | 14 +++--- .../viewmodel/gifs/GifPickerViewModel.kt | 12 +++++- .../viewmodel/gifs/provider/GifProvider.kt | 5 ++- .../viewmodel/gifs/provider/TenorProvider.kt | 43 ++++++++----------- .../gifs/provider/TenorProviderTest.kt | 23 +++++----- 5 files changed, 49 insertions(+), 48 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt index 3abafab4e550..f266cb0523af 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt @@ -72,12 +72,10 @@ class GifPickerDataSource( searchQuery.isBlank() -> callback.onResult(emptyList(), startPosition, 0) - else -> gifProvider.search( - searchQuery, - startPosition, - params.requestedLoadSize, - onSuccess = { - callback.onResult(it, startPosition, it.size) + else -> gifProvider.search(searchQuery, startPosition, params.requestedLoadSize, + onSuccess = { gifs, nextPosition -> + val totalCount = nextPosition ?: gifs.size + callback.onResult(gifs, startPosition, totalCount) }, onFailure = { callback.onResult(emptyList(), startPosition, 0) } ) @@ -95,10 +93,10 @@ class GifPickerDataSource( searchQuery, params.startPosition, params.loadSize, - onSuccess = { callback.onResult(it) }, + onSuccess = { gifs, _ -> callback.onResult(gifs) }, onFailure = { failedRangeLoadArguments.add(RangeLoadArguments(params, callback)) - if(_rangeLoadErrorEvent.value == null) _rangeLoadErrorEvent.value = it + if (_rangeLoadErrorEvent.value == null) _rangeLoadErrorEvent.value = it }) } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt index 127e970cc234..f4cf241091fd 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt @@ -141,8 +141,16 @@ class GifPickerViewModel @Inject constructor( * The [PagedList] that should be displayed in the RecyclerView */ val mediaViewModelPagedList: LiveData> by lazy { - val pagedListConfig = PagedList.Config.Builder().setEnablePlaceholders(true).setPageSize(30).build() - LivePagedListBuilder(dataSourceFactory, pagedListConfig).setBoundaryCallback(pagedListBoundaryCallback).build() + val pagedListConfig = PagedList.Config.Builder() + .setEnablePlaceholders(false) + .setPrefetchDistance(15) + .setInitialLoadSizeHint(50) + .setPageSize(21) + .build() + + LivePagedListBuilder(dataSourceFactory, pagedListConfig) + .setBoundaryCallback(pagedListBoundaryCallback) + .build() } /** diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt index e18d3fcda560..ba10ade5fc45 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt @@ -13,7 +13,8 @@ interface GifProvider { * [position] to request results starting from a given position for that [query] * [loadSize] to request a result list limited to a specific amount * [onSuccess] will be called if the Provider had success finding GIFs - * and will deliver a List with all matching GIFs + * and will deliver a [List] of [GifMediaViewModel] with all matching GIFs + * and a [Int] describing the next position for pagination * [onFailure] will be called if the Provider didn't succeed with the task of bringing GIFs, * the delivered String will describe the error to be presented to the user */ @@ -21,7 +22,7 @@ interface GifProvider { query: String, position: Int, loadSize: Int? = null, - onSuccess: (List) -> Unit, + onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt index a2cc2c369ea4..b305712d0751 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt @@ -59,15 +59,19 @@ internal class TenorProvider @JvmOverloads constructor( query: String, position: Int, loadSize: Int?, - onSuccess: (List) -> Unit, + onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) { apiClient.simpleSearch( query, position.toString(), loadSize, - onSuccess = { - handleResponse(it, onSuccess, onFailure) + onSuccess = { response -> + response.results.map { it.toMutableGifMediaViewModel() } + .let { gifs -> + val nextPosition = response.next.toIntOrNull()?.let { it + 1 } + onSuccess(gifs, nextPosition) + } }, onFailure = { it?.let { throwable -> @@ -83,13 +87,16 @@ internal class TenorProvider @JvmOverloads constructor( * [MediaFilter] must be BASIC or the returned Media will not have a displayable thumbnail * All other provided parameters are set following the Tenor API Documentation * + * The [onFailure] will be called assuming that no valid GIF was found + * or that a direct failure was found by Tenor API + * * Method is inlined for better high-order functions performance */ private inline fun IApiClient.simpleSearch( query: String, position: String, loadSize: Int?, - crossinline onSuccess: (GifsResponse?) -> Unit, + crossinline onSuccess: (GifsResponse) -> Unit, crossinline onFailure: (Throwable?) -> Unit ) { search( @@ -102,7 +109,12 @@ internal class TenorProvider @JvmOverloads constructor( ).enqueue(object : WeakRefCallback(context) { override fun success(ctx: Context, response: GifsResponse?) { - onSuccess(response) + response?.let(onSuccess) + ?: onFailure( + GifRequestFailedException( + context.getString(string.giphy_picker_empty_search_list) + ) + ) } override fun failure(ctx: Context, throwable: Throwable?) { @@ -111,27 +123,6 @@ internal class TenorProvider @JvmOverloads constructor( }) } - /** - * When the Tenor API returns the [GifsResponse] this method will try to parse it - * to a [List] of [GifMediaViewModel], if the parse fails, the [onFailure] will be called - * with a [GifRequestFailedException] assuming that no valid GIF was found - * - * Method is inlined for better high-order functions performance - */ - private inline fun handleResponse( - response: GifsResponse?, - onSuccess: (List) -> Unit, - onFailure: (Throwable) -> Unit - ) { - response?.run { results.map { it.toMutableGifMediaViewModel() } } - ?.let { onSuccess(it) } - ?: onFailure( - GifRequestFailedException( - context.getString(string.giphy_picker_empty_search_list) - ) - ) - } - /** * If the search request fails an [GifRequestFailedException] will be passed with the API * message. If there's no message provided, a generic message will be applied. diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt index 9d77d160d3c8..1fb29884e0f8 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt @@ -54,14 +54,17 @@ class TenorProviderTest { } @Test - fun `search call should invoke onSuccess with expected GIF list for valid query`() { + fun `search call should invoke onSuccess with expected GIF list and nextPosition for valid query`() { var onSuccessWasCalled = false + whenever(gifResponse.next).thenReturn("0") + val expectedNextPosition = 0 tenorProviderUnderTest.search("test", 0, - onSuccess = { + onSuccess = { actualViewModelCollection, actualNextPosition -> onSuccessWasCalled = true - assertEquals(expectedGifMediaViewModelCollection, it) + assertEquals(expectedGifMediaViewModelCollection, actualViewModelCollection) + assertEquals(expectedNextPosition, actualNextPosition) }, onFailure = { fail("Failure handler should not be called") @@ -79,7 +82,7 @@ class TenorProviderTest { tenorProviderUnderTest.search("test", 0, - onSuccess = { + onSuccess = { _, _ -> fail("Success handler should not be called") }, onFailure = { @@ -100,13 +103,13 @@ class TenorProviderTest { tenorProviderUnderTest.search("test", 0, - onSuccess = { + onSuccess = { _, _ -> fail("Success handler should not be called") }, onFailure = { onFailureWasCalled = true assertTrue(it is GifRequestFailedException) - assertEquals("No GIFs matching your search", it.message) + assertEquals("No media matching your search", it.message) }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) @@ -122,7 +125,7 @@ class TenorProviderTest { tenorProviderUnderTest.search( "test", 0, - onSuccess = {}, + onSuccess = { _,_ -> }, onFailure = {}) verify(apiClient).search( @@ -144,7 +147,7 @@ class TenorProviderTest { tenorProviderUnderTest.search( "test", 0, - onSuccess = {}, + onSuccess = { _,_ -> }, onFailure = {}) verify(apiClient).search( @@ -167,7 +170,7 @@ class TenorProviderTest { "test", 0, 20, - onSuccess = {}, + onSuccess = { _,_ -> }, onFailure = {}) verify(apiClient).search( @@ -190,7 +193,7 @@ class TenorProviderTest { "test", 0, 1500, - onSuccess = {}, + onSuccess = { _,_ -> }, onFailure = {}) verify(apiClient).search( From 91a00b276d9cdebb2a6646eaddce73212f238a59 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 17:28:17 -0300 Subject: [PATCH 13/58] Reverted Giphy renaming --- WordPress/src/main/AndroidManifest.xml | 2 +- .../android/modules/AppComponent.java | 2 +- .../android/modules/ViewModelModule.java | 6 +-- .../{gifs => giphy}/GiphyMediaViewHolder.kt | 24 ++++----- .../ui/{gifs => giphy}/GiphyPickerActivity.kt | 22 ++++---- .../GiphyPickerPagedListAdapter.kt | 20 +++---- .../LifecycleOwnerViewHolder.kt | 2 +- ...ifMediaFetcher.kt => GiphyMediaFetcher.kt} | 16 +++--- ...diaViewModel.kt => GiphyMediaViewModel.kt} | 2 +- ...DataSource.kt => GiphyPickerDataSource.kt} | 18 +++---- ...ory.kt => GiphyPickerDataSourceFactory.kt} | 24 ++++----- ...erViewModel.kt => GiphyPickerViewModel.kt} | 52 +++++++++---------- ...Model.kt => MutableGiphyMediaViewModel.kt} | 10 ++-- .../viewmodel/gifs/provider/GifProvider.kt | 6 +-- .../viewmodel/gifs/provider/TenorProvider.kt | 10 ++-- ...delTest.kt => GiphyPickerViewModelTest.kt} | 24 ++++----- .../gifs/provider/TenorProviderTestUtils.kt | 4 +- 17 files changed, 122 insertions(+), 122 deletions(-) rename WordPress/src/main/java/org/wordpress/android/ui/{gifs => giphy}/GiphyMediaViewHolder.kt (87%) rename WordPress/src/main/java/org/wordpress/android/ui/{gifs => giphy}/GiphyPickerActivity.kt (95%) rename WordPress/src/main/java/org/wordpress/android/ui/{gifs => giphy}/GiphyPickerPagedListAdapter.kt (61%) rename WordPress/src/main/java/org/wordpress/android/ui/{gifs => giphy}/LifecycleOwnerViewHolder.kt (99%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/{GifMediaFetcher.kt => GiphyMediaFetcher.kt} (85%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/{GifMediaViewModel.kt => GiphyMediaViewModel.kt} (98%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/{GifPickerDataSource.kt => GiphyPickerDataSource.kt} (86%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/{GifPickerDataSourceFactory.kt => GiphyPickerDataSourceFactory.kt} (55%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/{GifPickerViewModel.kt => GiphyPickerViewModel.kt} (87%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/{MutableGifMediaViewModel.kt => MutableGiphyMediaViewModel.kt} (80%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/{GifPickerViewModelTest.kt => GiphyPickerViewModelTest.kt} (94%) diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 8d2437d74253..3855fffeea59 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -529,7 +529,7 @@ android:label="" android:theme="@style/WordPress.NoActionBar" /> diff --git a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java index 801bb6f2185c..a9edf87b9af5 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java @@ -40,7 +40,7 @@ import org.wordpress.android.ui.domains.DomainRegistrationActivity; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment; import org.wordpress.android.ui.domains.DomainSuggestionsFragment; -import org.wordpress.android.ui.gifs.GiphyPickerActivity; +import org.wordpress.android.ui.giphy.GiphyPickerActivity; import org.wordpress.android.ui.history.HistoryAdapter; import org.wordpress.android.ui.history.HistoryDetailContainerFragment; import org.wordpress.android.ui.main.AddContentAdapter; diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java index 31c9f5657cb6..be9031cdc666 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java @@ -37,7 +37,7 @@ import org.wordpress.android.viewmodel.activitylog.ActivityLogViewModel; import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel; import org.wordpress.android.viewmodel.domains.DomainSuggestionsViewModel; -import org.wordpress.android.viewmodel.gifs.GifPickerViewModel; +import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel; import org.wordpress.android.viewmodel.history.HistoryViewModel; import org.wordpress.android.viewmodel.main.WPMainActivityViewModel; import org.wordpress.android.viewmodel.pages.PageListViewModel; @@ -218,8 +218,8 @@ abstract class ViewModelModule { @Binds @IntoMap - @ViewModelKey(GifPickerViewModel.class) - abstract ViewModel giphyPickerViewModel(GifPickerViewModel viewModel); + @ViewModelKey(GiphyPickerViewModel.class) + abstract ViewModel giphyPickerViewModel(GiphyPickerViewModel viewModel); @Binds @IntoMap diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt similarity index 87% rename from WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt rename to WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt index 846c79001fee..4f9b68f78f09 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.gifs +package org.wordpress.android.ui.giphy import android.view.LayoutInflater import android.view.View @@ -14,14 +14,14 @@ import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.util.image.ImageType.PHOTO import org.wordpress.android.util.redirectContextClickToLongPressListener -import org.wordpress.android.viewmodel.gifs.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel /** * Represents a single item in the [GiphyPickerActivity]'s grid (RecyclerView). * * This is meant to show a single animated gif. * - * This ViewHolder references a readonly [GifMediaViewModel]. It should never update the [GifMediaViewModel]. That + * This ViewHolder references a readonly [GiphyMediaViewModel]. It should never update the [GiphyMediaViewModel]. That * behavior is handled by the [GiphyPickerViewModel]. This is designed this way so that [GiphyPickerViewModel] * encapsulates all the logic of managing selected items as well as keeping their selection numbers continuous. */ @@ -35,11 +35,11 @@ class GiphyMediaViewHolder( * * If there is no bound [mediaViewModel], this can mean that there was an API error or this is just a placeholder. */ - private val onClickListener: (GifMediaViewModel?) -> Unit, + private val onClickListener: (GiphyMediaViewModel?) -> Unit, /** * A function that is called when the user performs a long press on the thumbnail */ - private val onLongClickListener: (GifMediaViewModel) -> Unit, + private val onLongClickListener: (GiphyMediaViewModel) -> Unit, /** * The view used for this `ViewHolder`. */ @@ -48,13 +48,13 @@ class GiphyMediaViewHolder( * The dimensions used for the ImageView */ thumbnailViewDimensions: ThumbnailViewDimensions -) : LifecycleOwnerViewHolder(itemView) { +) : LifecycleOwnerViewHolder(itemView) { data class ThumbnailViewDimensions(val width: Int, val height: Int) private val thumbnailView: ImageView = itemView.image_thumbnail private val selectionNumberTextView: TextView = itemView.text_selection_count - private var mediaViewModel: GifMediaViewModel? = null + private var mediaViewModel: GiphyMediaViewModel? = null init { thumbnailView.apply { @@ -72,13 +72,13 @@ class GiphyMediaViewHolder( } /** - * Update the views to use the given [GifMediaViewModel] + * Update the views to use the given [GiphyMediaViewModel] * * The [mediaViewModel] is optional because we enable placeholders in the paged list created by - * [org.wordpress.android.viewmodel.gifs.GifPickerViewModel]. This causes null values to be bound to + * [org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel]. This causes null values to be bound to * [GiphyMediaViewHolder] instances. */ - override fun bind(item: GifMediaViewModel?) { + override fun bind(item: GiphyMediaViewModel?) { super.bind(item) this.mediaViewModel = item @@ -141,8 +141,8 @@ class GiphyMediaViewHolder( */ fun create( imageManager: ImageManager, - onClickListener: (GifMediaViewModel?) -> Unit, - onLongClickListener: (GifMediaViewModel) -> Unit, + onClickListener: (GiphyMediaViewModel?) -> Unit, + onLongClickListener: (GiphyMediaViewModel) -> Unit, parent: ViewGroup, thumbnailViewDimensions: ThumbnailViewDimensions ): GiphyMediaViewHolder { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt rename to WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt index 00a95ffd3b08..efb4dcc05852 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.gifs +package org.wordpress.android.ui.giphy import android.app.Activity import android.content.Intent @@ -19,8 +19,8 @@ import org.wordpress.android.WordPress import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.ui.ActionableEmptyView +import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.ui.LocaleAwareActivity -import org.wordpress.android.ui.gifs.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.ui.media.MediaPreviewActivity import org.wordpress.android.util.AniUtils import org.wordpress.android.util.DisplayUtils @@ -28,10 +28,10 @@ import org.wordpress.android.util.ToastUtils import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.ViewModelFactory -import org.wordpress.android.viewmodel.gifs.GifMediaViewModel -import org.wordpress.android.viewmodel.gifs.GifPickerViewModel -import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.State +import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel +import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel +import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.State import javax.inject.Inject /** @@ -46,7 +46,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { @Inject lateinit var imageManager: ImageManager @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: GifPickerViewModel + private lateinit var viewModel: GiphyPickerViewModel private val gridColumnCount: Int by lazy { if (DisplayUtils.isLandscape(this)) 4 else 3 } @@ -64,7 +64,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { val site = intent.getSerializableExtra(WordPress.SITE) as SiteModel - viewModel = ViewModelProviders.of(this, viewModelFactory).get(GifPickerViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(GiphyPickerViewModel::class.java) viewModel.setup(site) // We are intentionally reusing this layout since the UI is very similar. @@ -150,7 +150,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { } /** - * Configure the selection bar and its labels when the [GifPickerViewModel] selected items change + * Configure the selection bar and its labels when the [GiphyPickerViewModel] selected items change */ private fun initializeSelectionBar() { viewModel.selectionBarIsVisible.observe(this, Observer { @@ -275,7 +275,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { * * @param mediaViewModels A non-empty list */ - private fun showPreview(mediaViewModels: List) { + private fun showPreview(mediaViewModels: List) { check(mediaViewModels.isNotEmpty()) val uris = mediaViewModels.map { it.previewImageUri.toString() } @@ -308,7 +308,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { } /** - * Set up enabling/disabling of controls depending on the current [GifPickerViewModel.State]: + * Set up enabling/disabling of controls depending on the current [GiphyPickerViewModel.State]: * * - [State.IDLE]: All normal functions are allowed * - [State.DOWNLOADING] or [State.FINISHED]: "Add", "Preview", searching, and selecting are disabled diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt similarity index 61% rename from WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt rename to WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt index 904080b760c3..0fca83878b35 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/GiphyPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt @@ -1,11 +1,11 @@ -package org.wordpress.android.ui.gifs +package org.wordpress.android.ui.giphy import android.view.ViewGroup import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil.ItemCallback -import org.wordpress.android.ui.gifs.GiphyMediaViewHolder.ThumbnailViewDimensions +import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.util.image.ImageManager -import org.wordpress.android.viewmodel.gifs.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel /** * An [RecyclerView] adapter to be used with the [PagedList] created by [GiphyPickerViewModel] @@ -13,9 +13,9 @@ import org.wordpress.android.viewmodel.gifs.GifMediaViewModel class GiphyPickerPagedListAdapter( private val imageManager: ImageManager, private val thumbnailViewDimensions: ThumbnailViewDimensions, - private val onMediaViewClickListener: (GifMediaViewModel?) -> Unit, - private val onMediaViewLongClickListener: (GifMediaViewModel) -> Unit -) : PagedListAdapter(DIFF_CALLBACK) { + private val onMediaViewClickListener: (GiphyMediaViewModel?) -> Unit, + private val onMediaViewLongClickListener: (GiphyMediaViewModel) -> Unit +) : PagedListAdapter(DIFF_CALLBACK) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GiphyMediaViewHolder { return GiphyMediaViewHolder.create( imageManager = imageManager, @@ -31,18 +31,18 @@ class GiphyPickerPagedListAdapter( } companion object { - private val DIFF_CALLBACK = object : ItemCallback() { - override fun areItemsTheSame(oldItem: GifMediaViewModel, newItem: GifMediaViewModel): Boolean { + private val DIFF_CALLBACK = object : ItemCallback() { + override fun areItemsTheSame(oldItem: GiphyMediaViewModel, newItem: GiphyMediaViewModel): Boolean { return oldItem.id == newItem.id } /** - * Always assume that two similar [GifMediaViewModel] objects always have the same content. + * Always assume that two similar [GiphyMediaViewModel] objects always have the same content. * * It is probably extremely unlikely that GIFs from Giphy will change while the user is performing * a search. */ - override fun areContentsTheSame(oldItem: GifMediaViewModel, newItem: GifMediaViewModel): Boolean { + override fun areContentsTheSame(oldItem: GiphyMediaViewModel, newItem: GiphyMediaViewModel): Boolean { return true } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gifs/LifecycleOwnerViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt similarity index 99% rename from WordPress/src/main/java/org/wordpress/android/ui/gifs/LifecycleOwnerViewHolder.kt rename to WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt index fd6f0ba464bf..7c207dc25c48 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gifs/LifecycleOwnerViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.gifs +package org.wordpress.android.ui.giphy import android.view.View import android.view.View.OnAttachStateChangeListener diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaFetcher.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaFetcher.kt similarity index 85% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaFetcher.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaFetcher.kt index 0f3e1b293d73..ce044ddb9c15 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaFetcher.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaFetcher.kt @@ -18,13 +18,13 @@ import org.wordpress.android.util.WPMediaUtils import javax.inject.Inject /** - * Downloads [GifMediaViewModel.largeImageUri] objects and saves them as [MediaModel] + * Downloads [GiphyMediaViewModel.largeImageUri] objects and saves them as [MediaModel] * * The download happens concurrently and primarily uses [Dispatchers.IO]. This means that we are limited by the number * of threads backed by that `CoroutineDispatcher`. In the future, we should probably add a limit to the number of * GIFs that users can select to reduce the likelihood of OOM exceptions. */ -class GifMediaFetcher @Inject constructor( +class GiphyMediaFetcher @Inject constructor( private val context: Context, private val mediaStore: MediaStore, private val dispatcher: Dispatcher @@ -38,22 +38,22 @@ class GifMediaFetcher @Inject constructor( */ @Throws suspend fun fetchAndSave( - gifMediaViewModels: List, + giphyMediaViewModels: List, site: SiteModel ): List = coroutineScope { // Execute [fetchAndSave] for all giphyMediaViewModels first so that they are queued and executed in the // background. We'll call `await()` once they are queued. - return@coroutineScope gifMediaViewModels.map { - fetchAndSave(scope = this, gifMediaViewModel = it, site = site) + return@coroutineScope giphyMediaViewModels.map { + fetchAndSave(scope = this, giphyMediaViewModel = it, site = site) }.map { it.await() } } private fun fetchAndSave( scope: CoroutineScope, - gifMediaViewModel: GifMediaViewModel, + giphyMediaViewModel: GiphyMediaViewModel, site: SiteModel ): Deferred = scope.async(Dispatchers.IO) { - val uri = gifMediaViewModel.largeImageUri + val uri = giphyMediaViewModel.largeImageUri // No need to log the Exception here. The underlying method that is used, [MediaUtils.downloadExternalMedia] // already logs any errors. val downloadedUri = WPMediaUtils.fetchMedia(context, uri) ?: throw Exception("Failed to download the image.") @@ -65,7 +65,7 @@ class GifMediaFetcher @Inject constructor( val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension) val mediaModel = FluxCUtils.mediaModelFromLocalUri(context, downloadedUri, mimeType, mediaStore, site.id) - mediaModel.title = gifMediaViewModel.title + mediaModel.title = giphyMediaViewModel.title dispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(mediaModel)) return@async mediaModel diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaViewModel.kt similarity index 98% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaViewModel.kt index 37268c46479f..1a72e815125d 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaViewModel.kt @@ -15,7 +15,7 @@ import androidx.lifecycle.LiveData * See the [Giphy API docs](https://developers.giphy.com/docs/) for more information on what a [Media] object contains. * Search for "The GIF Object" section. */ -interface GifMediaViewModel { +interface GiphyMediaViewModel { /** * The id from Giphy's [Media] */ diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSource.kt similarity index 86% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSource.kt index f266cb0523af..c71438181be9 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSource.kt @@ -6,28 +6,28 @@ import androidx.paging.PositionalDataSource import org.wordpress.android.viewmodel.gifs.provider.GifProvider /** - * The PagedListDataSource that is created and managed by [GifPickerDataSourceFactory] + * The PagedListDataSource that is created and managed by [GiphyPickerDataSourceFactory] * * This performs paged API requests using the [apiClient]. A new instance of this class must be created if the * [searchQuery] is changed by the user. */ -class GifPickerDataSource( +class GiphyPickerDataSource( private val gifProvider: GifProvider, private val searchQuery: String -) : PositionalDataSource() { +) : PositionalDataSource() { /** * The data structure used for storing failed [loadRange] calls so they can be retried later. */ private data class RangeLoadArguments( val params: LoadRangeParams, - val callback: LoadRangeCallback + val callback: LoadRangeCallback ) /** * The error received when [loadInitial] fails. * * Unlike [rangeLoadErrorEvent], this is not a [LiveData] because the consumer of this method - * [GifPickerViewModel] simply uses it to check for null values and reacts to a different event. + * [GiphyPickerViewModel] simply uses it to check for null values and reacts to a different event. * * This is cleared when [loadInitial] is started. */ @@ -53,15 +53,15 @@ class GifPickerDataSource( /** * Always the load the first page (startingPosition = 0) from the Giphy API * - * The [GifPickerDataSourceFactory] recreates [GifPickerDataSource] instances whenever a new [searchQuery] + * The [GiphyPickerDataSourceFactory] recreates [GiphyPickerDataSource] instances whenever a new [searchQuery] * is queued. The [LoadInitialParams.requestedStartPosition] may have a value that is only valid for the * previous [searchQuery]. If that value is greater than the total search results of the new [searchQuery], * a crash will happen. * - * Using `0` as the `startPosition` forces the [GifPickerDataSource] consumer to reset the list (UI) from the + * Using `0` as the `startPosition` forces the [GiphyPickerDataSource] consumer to reset the list (UI) from the * top. */ - override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { + override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { val startPosition = 0 initialLoadError = null @@ -88,7 +88,7 @@ class GifPickerDataSource( * Errors are dispatched to [rangeLoadErrorEvent]. If successful, previously failed calls of this method are * automatically retried using [retryAllFailedRangeLoads]. */ - override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { + override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { gifProvider.search( searchQuery, params.startPosition, diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSourceFactory.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSourceFactory.kt similarity index 55% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSourceFactory.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSourceFactory.kt index 32811e471255..087309c77498 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerDataSourceFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSourceFactory.kt @@ -9,19 +9,19 @@ import org.wordpress.android.viewmodel.gifs.provider.GifProvider import javax.inject.Inject /** - * Creates instances of [GifPickerDataSource] + * Creates instances of [GiphyPickerDataSource] * * Whenever the [searchQuery] is changed: * - * 1. The last [GifPickerDataSource] is invalidated - * 2. The [LivePagedListBuilder] will create a new [GifPickerDataSource] by calling [create] - * 3. The new [GifPickerDataSource] will start another paged API request + * 1. The last [GiphyPickerDataSource] is invalidated + * 2. The [LivePagedListBuilder] will create a new [GiphyPickerDataSource] by calling [create] + * 3. The new [GiphyPickerDataSource] will start another paged API request */ -class GifPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { +class GiphyPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { /** * The active search query. * - * When changed, the current [GifPickerDataSource] will be invalidated. A new API search will be performed. + * When changed, the current [GiphyPickerDataSource] will be invalidated. A new API search will be performed. */ var searchQuery: String = "" set(value) { @@ -34,26 +34,26 @@ class GifPickerDataSourceFactory @Inject constructor(private val gifProvider: Gi * * We retain this so we can invalidate it later when [searchQuery] is changed. */ - private val dataSource = MutableLiveData() + private val dataSource = MutableLiveData() /** - * The [GifPickerDataSource.initialLoadError] of the current [dataSource] + * The [GiphyPickerDataSource.initialLoadError] of the current [dataSource] */ val initialLoadError: Throwable? get() = dataSource.value?.initialLoadError /** - * The [GifPickerDataSource.rangeLoadErrorEvent] of the current [dataSource] + * The [GiphyPickerDataSource.rangeLoadErrorEvent] of the current [dataSource] */ val rangeLoadErrorEvent: LiveData = Transformations.switchMap(dataSource) { it.rangeLoadErrorEvent } /** * Retries all previously failed page loads. * - * @see [GifPickerDataSource.retryAllFailedRangeLoads] + * @see [GiphyPickerDataSource.retryAllFailedRangeLoads] */ fun retryAllFailedRangeLoads() = dataSource.value?.retryAllFailedRangeLoads() - override fun create(): DataSource { - val dataSource = GifPickerDataSource(gifProvider, searchQuery) + override fun create(): DataSource { + val dataSource = GiphyPickerDataSource(gifProvider, searchQuery) this.dataSource.postValue(dataSource) return dataSource } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModel.kt similarity index 87% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModel.kt index f4cf241091fd..cbdee4152d2f 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModel.kt @@ -24,22 +24,22 @@ import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject /** - * Holds the data for [org.wordpress.android.ui.gifs.GiphyPickerActivity] + * Holds the data for [org.wordpress.android.ui.giphy.GiphyPickerActivity] * * This creates a [PagedList] which can be bound to by a [PagedListAdapter] and also manages the logic of the - * selected media. That includes but not limited to keeping the [GifMediaViewModel.selectionNumber] continuous. + * selected media. That includes but not limited to keeping the [GiphyMediaViewModel.selectionNumber] continuous. * * Calling [setup] is required before using this ViewModel. */ -class GifPickerViewModel @Inject constructor( +class GiphyPickerViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, - private val mediaFetcher: GifMediaFetcher, + private val mediaFetcher: GiphyMediaFetcher, /** - * The [GifPickerDataSourceFactory] to use + * The [GiphyPickerDataSourceFactory] to use * * This is only available in the constructor to allow mocking in tests. */ - private val dataSourceFactory: GifPickerDataSourceFactory + private val dataSourceFactory: GiphyPickerDataSourceFactory ) : CoroutineScopedViewModel() { /** * A result of [downloadSelected] observed using the [downloadResult] LiveData @@ -95,7 +95,7 @@ class GifPickerViewModel @Inject constructor( /** * Errors that happened during page loads. * - * @see [GifPickerDataSource.rangeLoadErrorEvent] + * @see [GiphyPickerDataSource.rangeLoadErrorEvent] */ val rangeLoadErrorEvent: LiveData = dataSourceFactory.rangeLoadErrorEvent @@ -113,13 +113,13 @@ class GifPickerViewModel @Inject constructor( */ val downloadResult: LiveData = _downloadResult - private val _selectedMediaViewModelList = MutableLiveData>() + private val _selectedMediaViewModelList = MutableLiveData>() /** - * A [Map] of the [GifMediaViewModel]s that were selected by the user + * A [Map] of the [GiphyMediaViewModel]s that were selected by the user * - * This map is sorted in the order that the user picked them. The [String] is the value of [GifMediaViewModel.id]. + * This map is sorted in the order that the user picked them. The [String] is the value of [GiphyMediaViewModel.id]. */ - val selectedMediaViewModelList: LiveData> = _selectedMediaViewModelList + val selectedMediaViewModelList: LiveData> = _selectedMediaViewModelList /** * Returns `true` if the selection bar (UI) should be shown @@ -140,7 +140,7 @@ class GifPickerViewModel @Inject constructor( /** * The [PagedList] that should be displayed in the RecyclerView */ - val mediaViewModelPagedList: LiveData> by lazy { + val mediaViewModelPagedList: LiveData> by lazy { val pagedListConfig = PagedList.Config.Builder() .setEnablePlaceholders(false) .setPrefetchDistance(15) @@ -156,7 +156,7 @@ class GifPickerViewModel @Inject constructor( /** * Update the [emptyDisplayMode] depending on the number of API search results or whether there was an error. */ - private val pagedListBoundaryCallback = object : BoundaryCallback() { + private val pagedListBoundaryCallback = object : BoundaryCallback() { override fun onZeroItemsLoaded() { _isPerformingInitialLoad.postValue(false) @@ -169,7 +169,7 @@ class GifPickerViewModel @Inject constructor( super.onZeroItemsLoaded() } - override fun onItemAtFrontLoaded(itemAtFront: GifMediaViewModel) { + override fun onItemAtFrontLoaded(itemAtFront: GiphyMediaViewModel) { _isPerformingInitialLoad.postValue(false) _emptyDisplayMode.postValue(EmptyDisplayMode.HIDDEN) super.onItemAtFrontLoaded(itemAtFront) @@ -207,7 +207,7 @@ class GifPickerViewModel @Inject constructor( * when, presumably, the user has stopped typing. * * This also clears the [selectedMediaViewModelList]. This makes sense because the user will not be seeing the - * currently selected [GifMediaViewModel] if the new search query results are different. + * currently selected [GiphyMediaViewModel] if the new search query results are different. * * Searching is disabled if downloading or the [query] is the same as the last one. * @@ -239,7 +239,7 @@ class GifPickerViewModel @Inject constructor( } /** - * Downloads all the selected [GifMediaViewModel] + * Downloads all the selected [GiphyMediaViewModel] * * When the process is finished, the results will be posted to [downloadResult]. * @@ -284,17 +284,17 @@ class GifPickerViewModel @Inject constructor( } /** - * Toggles a [GifMediaViewModel]'s `isSelected` property between true and false + * Toggles a [GiphyMediaViewModel]'s `isSelected` property between true and false * - * This also updates the [GifMediaViewModel.selectionNumber] of all the objects in [selectedMediaViewModelList]. + * This also updates the [GiphyMediaViewModel.selectionNumber] of all the objects in [selectedMediaViewModelList]. */ - fun toggleSelected(mediaViewModel: GifMediaViewModel) { + fun toggleSelected(mediaViewModel: GiphyMediaViewModel) { if (_state.value != State.IDLE) { return } - assert(mediaViewModel is MutableGifMediaViewModel) - mediaViewModel as MutableGifMediaViewModel + assert(mediaViewModel is MutableGiphyMediaViewModel) + mediaViewModel as MutableGiphyMediaViewModel val isSelected = !(mediaViewModel.isSelected.value ?: false) @@ -316,14 +316,14 @@ class GifPickerViewModel @Inject constructor( } /** - * Update the [GifMediaViewModel.selectionNumber] values so that they are continuous + * Update the [GiphyMediaViewModel.selectionNumber] values so that they are continuous * - * For example, if the selection numbers are [1, 2, 3, 4, 5] and the 2nd [GifMediaViewModel] was removed, we + * For example, if the selection numbers are [1, 2, 3, 4, 5] and the 2nd [GiphyMediaViewModel] was removed, we * want the selection numbers to be updated to [1, 2, 3, 4] instead of leaving it as [1, 3, 4, 5]. */ - private fun rebuildSelectionNumbers(mediaList: LinkedHashMap) { + private fun rebuildSelectionNumbers(mediaList: LinkedHashMap) { mediaList.values.forEachIndexed { index, mediaViewModel -> - (mediaViewModel as MutableGifMediaViewModel).postSelectionNumber(index + 1) + (mediaViewModel as MutableGiphyMediaViewModel).postSelectionNumber(index + 1) } } @@ -349,7 +349,7 @@ class GifPickerViewModel @Inject constructor( /** * Retries all previously failed page loads. * - * @see [GifPickerDataSource.retryAllFailedRangeLoads] + * @see [GiphyPickerDataSource.retryAllFailedRangeLoads] */ fun retryAllFailedRangeLoads() = dataSourceFactory.retryAllFailedRangeLoads() } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGiphyMediaViewModel.kt similarity index 80% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGifMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGiphyMediaViewModel.kt index ec632eba74cd..df8428e6ddcc 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGiphyMediaViewModel.kt @@ -6,21 +6,21 @@ import androidx.lifecycle.MutableLiveData import org.wordpress.android.viewmodel.SingleLiveEvent /** - * A mutable implementation of [GifMediaViewModel] + * A mutable implementation of [GiphyMediaViewModel] * - * This is meant to be accessible by [GifPickerViewModel] and [GifPickerDataSource] only. This is designed this - * way so that [GifPickerViewModel] encapsulates all the logic of managing selected items as well as keeping their + * This is meant to be accessible by [GiphyPickerViewModel] and [GiphyPickerDataSource] only. This is designed this + * way so that [GiphyPickerViewModel] encapsulates all the logic of managing selected items as well as keeping their * selection numbers continuous. * * The [GiphyPickerViewHolder] should never have access to the mutating methods of this class. */ -data class MutableGifMediaViewModel( +data class MutableGiphyMediaViewModel( override val id: String, override val thumbnailUri: Uri, override val previewImageUri: Uri, override val largeImageUri: Uri, override val title: String -) : GifMediaViewModel { +) : GiphyMediaViewModel { /** * Using [SingleLiveEvent] will prevent calls like this from running immediately when a ViewHolder is bound: * diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt index ba10ade5fc45..895f8ee37c7a 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt @@ -1,6 +1,6 @@ package org.wordpress.android.viewmodel.gifs.provider -import org.wordpress.android.viewmodel.gifs.GifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel /** * Interface to interact with a GIF provider API avoiding coupling with the concrete implementation @@ -13,7 +13,7 @@ interface GifProvider { * [position] to request results starting from a given position for that [query] * [loadSize] to request a result list limited to a specific amount * [onSuccess] will be called if the Provider had success finding GIFs - * and will deliver a [List] of [GifMediaViewModel] with all matching GIFs + * and will deliver a [List] of [GiphyMediaViewModel] with all matching GIFs * and a [Int] describing the next position for pagination * [onFailure] will be called if the Provider didn't succeed with the task of bringing GIFs, * the delivered String will describe the error to be presented to the user @@ -22,7 +22,7 @@ interface GifProvider { query: String, position: Int, loadSize: Int? = null, - onSuccess: (List, Int?) -> Unit, + onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt index b305712d0751..184189610341 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt @@ -13,8 +13,8 @@ import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse import org.wordpress.android.BuildConfig import org.wordpress.android.R.string -import org.wordpress.android.viewmodel.gifs.GifMediaViewModel -import org.wordpress.android.viewmodel.gifs.MutableGifMediaViewModel +import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel +import org.wordpress.android.viewmodel.gifs.MutableGiphyMediaViewModel import org.wordpress.android.viewmodel.gifs.provider.GifProvider.GifRequestFailedException /** @@ -59,7 +59,7 @@ internal class TenorProvider @JvmOverloads constructor( query: String, position: Int, loadSize: Int?, - onSuccess: (List, Int?) -> Unit, + onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) { apiClient.simpleSearch( @@ -142,10 +142,10 @@ internal class TenorProvider @JvmOverloads constructor( /** * Every GIF returned by the Tenor will be available as [Result], to better interface - * with our app, it will be converted to [MutableGifMediaViewModel] to avoid any external + * with our app, it will be converted to [MutableGiphyMediaViewModel] to avoid any external * coupling with the Tenor API */ - private fun Result.toMutableGifMediaViewModel() = MutableGifMediaViewModel( + private fun Result.toMutableGifMediaViewModel() = MutableGiphyMediaViewModel( id, Uri.parse(urlFromCollectionFormat(MediaCollectionFormat.GIF_NANO)), Uri.parse(urlFromCollectionFormat(MediaCollectionFormat.GIF_TINY)), diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModelTest.kt similarity index 94% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModelTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModelTest.kt index 3632a8fa421f..73ede5ea4431 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GifPickerViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModelTest.kt @@ -19,26 +19,26 @@ import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.util.NetworkUtilsWrapper -import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.gifs.GifPickerViewModel.State +import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.State import java.util.Random import java.util.UUID @RunWith(MockitoJUnitRunner::class) -class GifPickerViewModelTest { +class GiphyPickerViewModelTest { @get:Rule val rule = InstantTaskExecutorRule() - private lateinit var viewModel: GifPickerViewModel + private lateinit var viewModel: GiphyPickerViewModel - private val dataSourceFactory = mock() - private val mediaFetcher = mock() + private val dataSourceFactory = mock() + private val mediaFetcher = mock() @Mock private lateinit var networkUtils: NetworkUtilsWrapper @Before fun setUp() { - viewModel = GifPickerViewModel( + viewModel = GiphyPickerViewModel( dataSourceFactory = dataSourceFactory, networkUtils = networkUtils, mediaFetcher = mediaFetcher @@ -147,12 +147,12 @@ class GifPickerViewModelTest { @Test fun `when search results are empty, the empty view should be visible and says there are no results`() { // Arrange - val dataSource = mock() + val dataSource = mock() whenever(dataSourceFactory.create()).thenReturn(dataSource) whenever(dataSourceFactory.searchQuery).thenReturn("dummy") - val callbackCaptor = argumentCaptor>() + val callbackCaptor = argumentCaptor>() doNothing().whenever(dataSource).loadInitial(any(), callbackCaptor.capture()) // Observe mediaViewModelPagedList so the DataSourceFactory will be activated and perform API requests @@ -174,12 +174,12 @@ class GifPickerViewModelTest { @Test fun `when the initial load fails, the empty view should show a network error`() { // Arrange - val dataSource = mock() + val dataSource = mock() whenever(dataSourceFactory.create()).thenReturn(dataSource) whenever(dataSourceFactory.initialLoadError).thenReturn(mock()) - val callbackCaptor = argumentCaptor>() + val callbackCaptor = argumentCaptor>() doNothing().whenever(dataSource).loadInitial(any(), callbackCaptor.capture()) // Observe mediaViewModelPagedList so the DataSourceFactory will be activated and perform API requests @@ -313,7 +313,7 @@ class GifPickerViewModelTest { id = Random().nextInt() } - private fun createGiphyMediaViewModel() = MutableGifMediaViewModel( + private fun createGiphyMediaViewModel() = MutableGiphyMediaViewModel( id = UUID.randomUUID().toString(), thumbnailUri = mock(), largeImageUri = mock(), diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt index b9e0e58b6c5c..a7e89af62495 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt @@ -7,7 +7,7 @@ import com.tenor.android.core.constant.MediaCollectionFormat import com.tenor.android.core.model.impl.Media import com.tenor.android.core.model.impl.MediaCollection import com.tenor.android.core.model.impl.Result -import org.wordpress.android.viewmodel.gifs.MutableGifMediaViewModel +import org.wordpress.android.viewmodel.gifs.MutableGiphyMediaViewModel class TenorProviderTestUtils { companion object { @@ -49,7 +49,7 @@ class TenorProviderTestUtils { mock().apply { whenever(this.url).thenReturn(mockContent) } private fun createExpectedGifMediaViewModel(expectedContent: String) = - MutableGifMediaViewModel( + MutableGiphyMediaViewModel( expectedContent, Uri.parse("$expectedContent gif_nano"), Uri.parse("$expectedContent gif_tiny"), From 7e384e376b882adbbce4b40e2fc764e54e8681a3 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 17:56:12 -0300 Subject: [PATCH 14/58] Reverted Giphy renaming for packages --- .../org/wordpress/android/modules/ApplicationModule.java | 4 ++-- .../org/wordpress/android/modules/ViewModelModule.java | 2 +- .../wordpress/android/ui/giphy/GiphyMediaViewHolder.kt | 4 ++-- .../org/wordpress/android/ui/giphy/GiphyPickerActivity.kt | 8 ++++---- .../android/ui/giphy/GiphyPickerPagedListAdapter.kt | 2 +- .../viewmodel/{gifs => giphy}/CoroutineScopedViewModel.kt | 2 +- .../viewmodel/{gifs => giphy}/GiphyMediaFetcher.kt | 2 +- .../viewmodel/{gifs => giphy}/GiphyMediaViewModel.kt | 2 +- .../viewmodel/{gifs => giphy}/GiphyPickerDataSource.kt | 4 ++-- .../{gifs => giphy}/GiphyPickerDataSourceFactory.kt | 4 ++-- .../viewmodel/{gifs => giphy}/GiphyPickerViewModel.kt | 2 +- .../{gifs => giphy}/MutableGiphyMediaViewModel.kt | 2 +- .../viewmodel/{gifs => giphy}/provider/GifProvider.kt | 4 ++-- .../viewmodel/{gifs => giphy}/provider/TenorProvider.kt | 8 ++++---- .../viewmodel/{gifs => giphy}/GiphyPickerViewModelTest.kt | 6 +++--- .../{gifs => giphy}/provider/TenorProviderTest.kt | 8 ++++---- .../{gifs => giphy}/provider/TenorProviderTestUtils.kt | 4 ++-- 17 files changed, 34 insertions(+), 34 deletions(-) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/CoroutineScopedViewModel.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/GiphyMediaFetcher.kt (98%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/GiphyMediaViewModel.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/GiphyPickerDataSource.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/GiphyPickerDataSourceFactory.kt (94%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/GiphyPickerViewModel.kt (99%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/MutableGiphyMediaViewModel.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/provider/GifProvider.kt (91%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{gifs => giphy}/provider/TenorProvider.kt (95%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{gifs => giphy}/GiphyPickerViewModelTest.kt (98%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{gifs => giphy}/provider/TenorProviderTest.kt (94%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{gifs => giphy}/provider/TenorProviderTestUtils.kt (95%) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index 2151df578f5b..78779162ed9a 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -10,8 +10,8 @@ import org.wordpress.android.ui.accounts.signup.UsernameChangerFullScreenDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.CountryPickerDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.StatePickerDialogFragment; -import org.wordpress.android.viewmodel.gifs.provider.GifProvider; -import org.wordpress.android.viewmodel.gifs.provider.TenorProvider; +import org.wordpress.android.viewmodel.giphy.provider.GifProvider; +import org.wordpress.android.viewmodel.giphy.provider.TenorProvider; import org.wordpress.android.ui.news.LocalNewsService; import org.wordpress.android.ui.news.NewsService; import org.wordpress.android.ui.reader.ReaderPostWebViewCachingFragment; diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java index be9031cdc666..cec149670aa7 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java @@ -37,7 +37,7 @@ import org.wordpress.android.viewmodel.activitylog.ActivityLogViewModel; import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel; import org.wordpress.android.viewmodel.domains.DomainSuggestionsViewModel; -import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel; +import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel; import org.wordpress.android.viewmodel.history.HistoryViewModel; import org.wordpress.android.viewmodel.main.WPMainActivityViewModel; import org.wordpress.android.viewmodel.pages.PageListViewModel; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt index 4f9b68f78f09..09b47f52aceb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt @@ -14,7 +14,7 @@ import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.util.image.ImageType.PHOTO import org.wordpress.android.util.redirectContextClickToLongPressListener -import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel +import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel /** * Represents a single item in the [GiphyPickerActivity]'s grid (RecyclerView). @@ -75,7 +75,7 @@ class GiphyMediaViewHolder( * Update the views to use the given [GiphyMediaViewModel] * * The [mediaViewModel] is optional because we enable placeholders in the paged list created by - * [org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel]. This causes null values to be bound to + * [org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel]. This causes null values to be bound to * [GiphyMediaViewHolder] instances. */ override fun bind(item: GiphyMediaViewModel?) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt index efb4dcc05852..12a4656d8acd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt @@ -28,10 +28,10 @@ import org.wordpress.android.util.ToastUtils import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.ViewModelFactory -import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel -import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel -import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.State +import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel +import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel +import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.State import javax.inject.Inject /** diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt index 0fca83878b35..0087e18a2731 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt @@ -5,7 +5,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil.ItemCallback import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.util.image.ImageManager -import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel +import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel /** * An [RecyclerView] adapter to be used with the [PagedList] created by [GiphyPickerViewModel] diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/CoroutineScopedViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/CoroutineScopedViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt index 251bb6dd3453..bc33fb90d74d 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/CoroutineScopedViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import androidx.lifecycle.ViewModel import kotlinx.coroutines.CoroutineScope diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaFetcher.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt similarity index 98% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaFetcher.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt index ce044ddb9c15..38c617edfe2c 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaFetcher.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import android.content.Context import android.webkit.MimeTypeMap diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt index 1a72e815125d..24a756e717a1 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import android.net.Uri import androidx.lifecycle.LiveData diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSource.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt index c71438181be9..b288d186c026 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt @@ -1,9 +1,9 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PositionalDataSource -import org.wordpress.android.viewmodel.gifs.provider.GifProvider +import org.wordpress.android.viewmodel.giphy.provider.GifProvider /** * The PagedListDataSource that is created and managed by [GiphyPickerDataSourceFactory] diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSourceFactory.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt similarity index 94% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSourceFactory.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt index 087309c77498..11cd422259cc 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerDataSourceFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt @@ -1,11 +1,11 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.paging.DataSource import androidx.paging.DataSource.Factory -import org.wordpress.android.viewmodel.gifs.provider.GifProvider +import org.wordpress.android.viewmodel.giphy.provider.GifProvider import javax.inject.Inject /** diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt similarity index 99% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt index cbdee4152d2f..6d35fdd0f6a7 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGiphyMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGiphyMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt index df8428e6ddcc..ec683efd6f8d 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/MutableGiphyMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import android.net.Uri import androidx.lifecycle.LiveData diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt similarity index 91% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt index 895f8ee37c7a..20edf97f27bf 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt @@ -1,6 +1,6 @@ -package org.wordpress.android.viewmodel.gifs.provider +package org.wordpress.android.viewmodel.giphy.provider -import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel +import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel /** * Interface to interact with a GIF provider API avoiding coupling with the concrete implementation diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index 184189610341..8362b2caa3e3 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gifs/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs.provider +package org.wordpress.android.viewmodel.giphy.provider import android.content.Context import android.net.Uri @@ -13,9 +13,9 @@ import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse import org.wordpress.android.BuildConfig import org.wordpress.android.R.string -import org.wordpress.android.viewmodel.gifs.GiphyMediaViewModel -import org.wordpress.android.viewmodel.gifs.MutableGiphyMediaViewModel -import org.wordpress.android.viewmodel.gifs.provider.GifProvider.GifRequestFailedException +import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel +import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel +import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException /** * Implementation of a GifProvider using the Tenor GIF API as provider diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt similarity index 98% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModelTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt index 73ede5ea4431..4c3480cdfd52 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/GiphyPickerViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs +package org.wordpress.android.viewmodel.giphy import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.paging.PositionalDataSource.LoadInitialCallback @@ -19,8 +19,8 @@ import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.util.NetworkUtilsWrapper -import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.gifs.GiphyPickerViewModel.State +import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.State import java.util.Random import java.util.UUID diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt similarity index 94% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 1fb29884e0f8..3f4707e84b2d 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs.provider +package org.wordpress.android.viewmodel.giphy.provider import android.content.Context import androidx.test.core.app.ApplicationProvider @@ -23,9 +23,9 @@ import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.wordpress.android.TestApplication -import org.wordpress.android.viewmodel.gifs.provider.GifProvider.GifRequestFailedException -import org.wordpress.android.viewmodel.gifs.provider.TenorProviderTestUtils.Companion.expectedGifMediaViewModelCollection -import org.wordpress.android.viewmodel.gifs.provider.TenorProviderTestUtils.Companion.mockedTenorResult +import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException +import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestUtils.Companion.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestUtils.Companion.mockedTenorResult import retrofit2.Call @Config(application = TestApplication::class) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestUtils.kt similarity index 95% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestUtils.kt index a7e89af62495..7f262ff8f0b6 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gifs/provider/TenorProviderTestUtils.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestUtils.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.gifs.provider +package org.wordpress.android.viewmodel.giphy.provider import android.net.Uri import com.nhaarman.mockitokotlin2.mock @@ -7,7 +7,7 @@ import com.tenor.android.core.constant.MediaCollectionFormat import com.tenor.android.core.model.impl.Media import com.tenor.android.core.model.impl.MediaCollection import com.tenor.android.core.model.impl.Result -import org.wordpress.android.viewmodel.gifs.MutableGiphyMediaViewModel +import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel class TenorProviderTestUtils { companion object { From 5b1f83550d8d9aeba7bc3b0e105cb0b3cf9dc6c7 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 19:49:52 -0300 Subject: [PATCH 15/58] Additional code refactoring and new test for TenorProvider --- .../viewmodel/giphy/GiphyPickerDataSource.kt | 38 +++++++++++++------ .../viewmodel/giphy/provider/TenorProvider.kt | 26 +++++++++---- .../giphy/provider/TenorProviderTest.kt | 24 +++++++++++- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt index b288d186c026..e3b4d9929690 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt @@ -69,19 +69,32 @@ class GiphyPickerDataSource( when { // Do not do any API call if the [searchQuery] is empty - searchQuery.isBlank() -> - callback.onResult(emptyList(), startPosition, 0) - - else -> gifProvider.search(searchQuery, startPosition, params.requestedLoadSize, - onSuccess = { gifs, nextPosition -> - val totalCount = nextPosition ?: gifs.size - callback.onResult(gifs, startPosition, totalCount) - }, - onFailure = { callback.onResult(emptyList(), startPosition, 0) } - ) + searchQuery.isBlank() -> callback.onResult(emptyList(), startPosition, 0) + else -> requestInitialSearch(params, callback) } } + /** + * Basic search request handling to initialize the list for the loadInitial function + */ + private fun requestInitialSearch( + params: LoadInitialParams, + callback: LoadInitialCallback + ) { + val startPosition = 0 + gifProvider.search(searchQuery, startPosition, params.requestedLoadSize, + onSuccess = { gifs, nextPosition -> + // nextPosition is increased by 1 to represents the total amount instead of a positional index + val totalCount = nextPosition?.let { it + 1 } ?: gifs.size + callback.onResult(gifs, startPosition, totalCount) + }, + onFailure = { + initialLoadError = it + callback.onResult(emptyList(), startPosition, 0) + } + ) + } + /** * Load a given range of items ([params]) from the Giphy API. * @@ -93,7 +106,10 @@ class GiphyPickerDataSource( searchQuery, params.startPosition, params.loadSize, - onSuccess = { gifs, _ -> callback.onResult(gifs) }, + onSuccess = { + gifs, _ -> callback.onResult(gifs) + retryAllFailedRangeLoads() + }, onFailure = { failedRangeLoadArguments.add(RangeLoadArguments(params, callback)) if (_rangeLoadErrorEvent.value == null) _rangeLoadErrorEvent.value = it diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index 8362b2caa3e3..82f74d44d560 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -67,16 +67,10 @@ internal class TenorProvider @JvmOverloads constructor( position.toString(), loadSize, onSuccess = { response -> - response.results.map { it.toMutableGifMediaViewModel() } - .let { gifs -> - val nextPosition = response.next.toIntOrNull()?.let { it + 1 } - onSuccess(gifs, nextPosition) - } + handleResponse(response, onSuccess) }, onFailure = { - it?.let { throwable -> - handleFailure(throwable, onFailure) - } + it?.let { throwable -> handleFailure(throwable, onFailure) } } ) } @@ -123,9 +117,25 @@ internal class TenorProvider @JvmOverloads constructor( }) } + /** + * If the search request succeeds an [List] of [MutableGiphyMediaViewModel] will be passed with the next position + * for pagination. If there's no next position provided, it will be passed as null. + */ + private fun handleResponse( + response: GifsResponse, + onSuccess: (List, Int?) -> Unit + ) { + response.results.map { it.toMutableGifMediaViewModel() } + .let { gifs -> + val nextPosition = response.next.toIntOrNull() + onSuccess(gifs, nextPosition) + } + } + /** * If the search request fails an [GifRequestFailedException] will be passed with the API * message. If there's no message provided, a generic message will be applied. + * */ private inline fun handleFailure( throwable: Throwable, diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 3f4707e84b2d..8d661c8b2a3c 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -57,13 +57,33 @@ class TenorProviderTest { fun `search call should invoke onSuccess with expected GIF list and nextPosition for valid query`() { var onSuccessWasCalled = false whenever(gifResponse.next).thenReturn("0") - val expectedNextPosition = 0 tenorProviderUnderTest.search("test", 0, - onSuccess = { actualViewModelCollection, actualNextPosition -> + onSuccess = { actualViewModelCollection, _ -> onSuccessWasCalled = true assertEquals(expectedGifMediaViewModelCollection, actualViewModelCollection) + }, + onFailure = { + fail("Failure handler should not be called") + }) + + verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) + val capturedCallback = callbackCaptor.value + capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) + assertTrue("onSuccess should be called", onSuccessWasCalled) + } + + @Test + fun `search call should invoke onSuccess with expected nextPosition for a valid query`() { + var onSuccessWasCalled = false + whenever(gifResponse.next).thenReturn("0") + val expectedNextPosition = 0 + + tenorProviderUnderTest.search("test", + 0, + onSuccess = { _, actualNextPosition -> + onSuccessWasCalled = true assertEquals(expectedNextPosition, actualNextPosition) }, onFailure = { From 0d23a81df34ff2a4c87f86e6455411d7676a1768 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 20:53:33 -0300 Subject: [PATCH 16/58] Reconnected GIF search with MediaBrowserActivity --- .../android/ui/ActivityLauncher.java | 8 ++++++ .../wordpress/android/ui/RequestCodes.java | 2 ++ .../ui/media/MediaBrowserActivity.java | 28 ++++++++++++++++++- WordPress/src/main/res/values/strings.xml | 1 + 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java index f58aac37f04a..c779e0c51030 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java @@ -38,6 +38,7 @@ import org.wordpress.android.ui.comments.CommentsActivity; import org.wordpress.android.ui.domains.DomainRegistrationActivity; import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose; +import org.wordpress.android.ui.giphy.GiphyPickerActivity; import org.wordpress.android.ui.history.HistoryDetailActivity; import org.wordpress.android.ui.history.HistoryDetailContainerFragment; import org.wordpress.android.ui.history.HistoryListItem.Revision; @@ -173,6 +174,13 @@ public static void showStockMediaPickerForResult(Activity activity, activity.startActivityForResult(intent, requestCode); } + public static void showGifPickerForResult(Activity activity, @NonNull SiteModel site, int requestCode) { + Intent intent = new Intent(activity, GiphyPickerActivity.class); + intent.putExtra(WordPress.SITE, site); + + activity.startActivityForResult(intent, requestCode); + } + public static void startJetpackInstall(Context context, JetpackConnectionSource source, SiteModel site) { Intent intent = new Intent(context, JetpackRemoteInstallActivity.class); intent.putExtra(WordPress.SITE, site); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java b/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java index 9914877774d7..0784fadcb4df 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/RequestCodes.java @@ -46,6 +46,8 @@ public class RequestCodes { // QuickStart public static final int QUICK_START_REMINDER_RECEIVER = 4000; + public static final int GIF_PICKER = 3200; + // Domain Registration public static final int DOMAIN_REGISTRATION = 5000; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java index 112d828464df..b69d4808f660 100755 --- a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java @@ -63,6 +63,7 @@ import org.wordpress.android.ui.ActivityLauncher; import org.wordpress.android.ui.LocaleAwareActivity; import org.wordpress.android.ui.RequestCodes; +import org.wordpress.android.ui.giphy.GiphyPickerActivity; import org.wordpress.android.ui.media.MediaGridFragment.MediaFilter; import org.wordpress.android.ui.media.MediaGridFragment.MediaGridListener; import org.wordpress.android.ui.media.services.MediaDeleteService; @@ -134,7 +135,8 @@ private enum AddMenuItem { ITEM_CAPTURE_VIDEO, ITEM_CHOOSE_PHOTO, ITEM_CHOOSE_VIDEO, - ITEM_CHOOSE_STOCK_MEDIA + ITEM_CHOOSE_STOCK_MEDIA, + ITEM_CHOOSE_GIF } @Override @@ -466,6 +468,19 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { reloadMediaGrid(); } break; + case RequestCodes.GIF_PICKER: + if (resultCode == RESULT_OK + && data.hasExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS)) { + int[] mediaLocalIds = data.getIntArrayExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS); + + ArrayList mediaModels = new ArrayList<>(); + for (int localId : mediaLocalIds) { + mediaModels.add(mMediaStore.getMediaWithLocalId(localId)); + } + + addMediaToUploadService(mediaModels); + } + break; } } @@ -872,6 +887,14 @@ public void showAddMediaPopup() { }); } + if (mBrowserType.isBrowser()) { + popup.getMenu().add(R.string.photo_picker_gif).setOnMenuItemClickListener( + item -> { + doAddMediaItemClicked(AddMenuItem.ITEM_CHOOSE_GIF); + return true; + }); + } + popup.show(); } @@ -909,6 +932,9 @@ private void doAddMediaItemClicked(@NonNull AddMenuItem item) { ActivityLauncher.showStockMediaPickerForResult(this, mSite, RequestCodes.STOCK_MEDIA_PICKER_MULTI_SELECT); break; + case ITEM_CHOOSE_GIF: + ActivityLauncher.showGifPickerForResult(this, mSite, RequestCodes.GIF_PICKER); + break; } } diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 202f6fb5351c..417f7f8af489 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2240,6 +2240,7 @@ Take photo Take video Choose from Free Photo Library + Choose from Tenor %s needs permissions to access your photos Allow %1$s was denied access to your photos. To fix this, edit your permissions and turn on %2$s. From aca0ca2c03f913b0c3eb8b026f1ce03770f9ea2e Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 20:59:31 -0300 Subject: [PATCH 17/58] Initial load changed to 42 --- .../wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt index 6d35fdd0f6a7..5cd763b674a2 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt @@ -144,7 +144,7 @@ class GiphyPickerViewModel @Inject constructor( val pagedListConfig = PagedList.Config.Builder() .setEnablePlaceholders(false) .setPrefetchDistance(15) - .setInitialLoadSizeHint(50) + .setInitialLoadSizeHint(42) .setPageSize(21) .build() From 2e46c33e65a7132945a5cc701c96b340a30880d7 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 21:00:04 -0300 Subject: [PATCH 18/58] Improved documentation for GifProvider --- .../android/viewmodel/giphy/provider/GifProvider.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt index 20edf97f27bf..1fcb7fba3253 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt @@ -9,13 +9,13 @@ interface GifProvider { /** * Request GIF search from a query string * - * The [query] parameter represents the desired text to search within the provider. - * [position] to request results starting from a given position for that [query] - * [loadSize] to request a result list limited to a specific amount - * [onSuccess] will be called if the Provider had success finding GIFs + * @param query represents the desired text to search within the provider. + * @param position to request results starting from a given position for that query + * @param loadSize to request a result list limited to a specific amount + * @param onSuccess will be called if the Provider had success finding GIFs * and will deliver a [List] of [GiphyMediaViewModel] with all matching GIFs * and a [Int] describing the next position for pagination - * [onFailure] will be called if the Provider didn't succeed with the task of bringing GIFs, + * @param onFailure will be called if the Provider didn't succeed with the task of bringing GIFs, * the delivered String will describe the error to be presented to the user */ fun search( From 14da4b2829b5f20ee0be209e2d19a973c7892960 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 24 Mar 2020 21:00:42 -0300 Subject: [PATCH 19/58] Added code refactoring for parameter organization --- .../android/viewmodel/giphy/GiphyPickerDataSource.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt index e3b4d9929690..2a195e8dd02f 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt @@ -76,6 +76,8 @@ class GiphyPickerDataSource( /** * Basic search request handling to initialize the list for the loadInitial function + * + * If no next position is informed by Tenor, the total count will be set with the size of the GIF list */ private fun requestInitialSearch( params: LoadInitialParams, @@ -102,10 +104,7 @@ class GiphyPickerDataSource( * automatically retried using [retryAllFailedRangeLoads]. */ override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { - gifProvider.search( - searchQuery, - params.startPosition, - params.loadSize, + gifProvider.search(searchQuery, params.startPosition, params.loadSize, onSuccess = { gifs, _ -> callback.onResult(gifs) retryAllFailedRangeLoads() From d338de226e235070bb4dcf047b6a43613b575885 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 00:09:16 -0300 Subject: [PATCH 20/58] Removed unwanted Tenor text reference --- .../wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt index 2a195e8dd02f..2cc9ddf8d174 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt @@ -77,7 +77,7 @@ class GiphyPickerDataSource( /** * Basic search request handling to initialize the list for the loadInitial function * - * If no next position is informed by Tenor, the total count will be set with the size of the GIF list + * If no next position is informed by the GIF provider, the total count will be set with the size of the GIF list */ private fun requestInitialSearch( params: LoadInitialParams, From f664593b52892a5ea50b7af1ac7b5e8645b9bed8 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 00:54:44 -0300 Subject: [PATCH 21/58] Added code refactoring for TenorProvider --- .../android/viewmodel/giphy/provider/TenorProvider.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index 82f74d44d560..c4956e1166d0 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -102,7 +102,7 @@ internal class TenorProvider @JvmOverloads constructor( AspectRatioRange.ALL ).enqueue(object : WeakRefCallback(context) { - override fun success(ctx: Context, response: GifsResponse?) { + override fun success(context: Context, response: GifsResponse?) { response?.let(onSuccess) ?: onFailure( GifRequestFailedException( @@ -111,7 +111,7 @@ internal class TenorProvider @JvmOverloads constructor( ) } - override fun failure(ctx: Context, throwable: Throwable?) { + override fun failure(context: Context, throwable: Throwable?) { onFailure(throwable) } }) @@ -121,7 +121,7 @@ internal class TenorProvider @JvmOverloads constructor( * If the search request succeeds an [List] of [MutableGiphyMediaViewModel] will be passed with the next position * for pagination. If there's no next position provided, it will be passed as null. */ - private fun handleResponse( + private inline fun handleResponse( response: GifsResponse, onSuccess: (List, Int?) -> Unit ) { From 3289614c8ae9c732c6fb0648a1761cf2aa0146e1 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 00:58:49 -0300 Subject: [PATCH 22/58] Improved documentation over TenorProvider methods --- .../android/viewmodel/giphy/provider/TenorProvider.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index c4956e1166d0..a6e0460bc2c1 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -120,6 +120,8 @@ internal class TenorProvider @JvmOverloads constructor( /** * If the search request succeeds an [List] of [MutableGiphyMediaViewModel] will be passed with the next position * for pagination. If there's no next position provided, it will be passed as null. + * + * Method is inlined for better high-order functions performance */ private inline fun handleResponse( response: GifsResponse, @@ -136,6 +138,7 @@ internal class TenorProvider @JvmOverloads constructor( * If the search request fails an [GifRequestFailedException] will be passed with the API * message. If there's no message provided, a generic message will be applied. * + * Method is inlined for better high-order functions performance */ private inline fun handleFailure( throwable: Throwable, From f267c9ab79c39da65f8a8aae923fe48859642f2c Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 16:47:52 -0300 Subject: [PATCH 23/58] Added resilience to the initial load fetching --- .../android/viewmodel/giphy/GiphyPickerDataSource.kt | 12 ++++++++---- .../android/viewmodel/giphy/GiphyPickerViewModel.kt | 1 - 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt index 2cc9ddf8d174..d07195dab666 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt @@ -86,8 +86,12 @@ class GiphyPickerDataSource( val startPosition = 0 gifProvider.search(searchQuery, startPosition, params.requestedLoadSize, onSuccess = { gifs, nextPosition -> - // nextPosition is increased by 1 to represents the total amount instead of a positional index - val totalCount = nextPosition?.let { it + 1 } ?: gifs.size + val totalCount = when { + // nextPosition should never be smaller than the number of GIFs returned + nextPosition == null || nextPosition < gifs.size -> gifs.size + else -> nextPosition + } + callback.onResult(gifs, startPosition, totalCount) }, onFailure = { @@ -105,8 +109,8 @@ class GiphyPickerDataSource( */ override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { gifProvider.search(searchQuery, params.startPosition, params.loadSize, - onSuccess = { - gifs, _ -> callback.onResult(gifs) + onSuccess = { gifs, _ -> + callback.onResult(gifs) retryAllFailedRangeLoads() }, onFailure = { diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt index 5cd763b674a2..58573a2cd9fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt @@ -143,7 +143,6 @@ class GiphyPickerViewModel @Inject constructor( val mediaViewModelPagedList: LiveData> by lazy { val pagedListConfig = PagedList.Config.Builder() .setEnablePlaceholders(false) - .setPrefetchDistance(15) .setInitialLoadSizeHint(42) .setPageSize(21) .build() From 40f781c544b6d71def9c03938130a7c1e8a14c68 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 16:49:58 -0300 Subject: [PATCH 24/58] Changed constant to better fit code convention --- .../viewmodel/giphy/provider/TenorProvider.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index a6e0460bc2c1..e384b43450b0 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -28,10 +28,6 @@ internal class TenorProvider @JvmOverloads constructor( tenorClient: IApiClient? = null ) : GifProvider { private val apiClient: IApiClient - /** - * To better refers to the Tenor API maximum GIF limit per request - */ - private val maximumAllowedLoadSize = 50 /** * Initializes the Tenor API client with the environment API key, if no tenorClient is provided via constructor, @@ -178,8 +174,15 @@ internal class TenorProvider @JvmOverloads constructor( private val Int?.fittedToMaximumAllowed get() = this?.let { when { - this > maximumAllowedLoadSize -> maximumAllowedLoadSize + this > MAXIMUM_ALLOWED_LOAD_SIZE -> MAXIMUM_ALLOWED_LOAD_SIZE else -> this } - } ?: maximumAllowedLoadSize + } ?: MAXIMUM_ALLOWED_LOAD_SIZE + + companion object { + /** + * To better refers to the Tenor API maximum GIF limit per request + */ + private const val MAXIMUM_ALLOWED_LOAD_SIZE = 50 + } } From 64733fc1adc91ec9ac0422872b841bf430169ef7 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 17:13:01 -0300 Subject: [PATCH 25/58] Changed TenorProviderTestUtils to TenorProviderTestFixtures, also refactored the class to become a object --- .../giphy/provider/TenorProviderTest.kt | 12 ++-- .../provider/TenorProviderTestFixtures.kt | 58 ++++++++++++++++++ .../giphy/provider/TenorProviderTestUtils.kt | 60 ------------------- 3 files changed, 64 insertions(+), 66 deletions(-) create mode 100644 WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestFixtures.kt delete mode 100644 WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestUtils.kt diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 8d661c8b2a3c..8833e1ec29d0 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -24,8 +24,8 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.wordpress.android.TestApplication import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException -import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestUtils.Companion.expectedGifMediaViewModelCollection -import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestUtils.Companion.mockedTenorResult +import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.mockedTenorResult import retrofit2.Call @Config(application = TestApplication::class) @@ -145,7 +145,7 @@ class TenorProviderTest { tenorProviderUnderTest.search( "test", 0, - onSuccess = { _,_ -> }, + onSuccess = { _, _ -> }, onFailure = {}) verify(apiClient).search( @@ -167,7 +167,7 @@ class TenorProviderTest { tenorProviderUnderTest.search( "test", 0, - onSuccess = { _,_ -> }, + onSuccess = { _, _ -> }, onFailure = {}) verify(apiClient).search( @@ -190,7 +190,7 @@ class TenorProviderTest { "test", 0, 20, - onSuccess = { _,_ -> }, + onSuccess = { _, _ -> }, onFailure = {}) verify(apiClient).search( @@ -213,7 +213,7 @@ class TenorProviderTest { "test", 0, 1500, - onSuccess = { _,_ -> }, + onSuccess = { _, _ -> }, onFailure = {}) verify(apiClient).search( diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestFixtures.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestFixtures.kt new file mode 100644 index 000000000000..855cf6ae85fb --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestFixtures.kt @@ -0,0 +1,58 @@ +package org.wordpress.android.viewmodel.giphy.provider + +import android.net.Uri +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import com.tenor.android.core.constant.MediaCollectionFormat +import com.tenor.android.core.model.impl.Media +import com.tenor.android.core.model.impl.MediaCollection +import com.tenor.android.core.model.impl.Result +import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel + +object TenorProviderTestFixtures { + internal val mockedTenorResult + get() = listOf( + createGifResultMock("first GIF"), + createGifResultMock("second GIF"), + createGifResultMock("third GIF"), + createGifResultMock("fourth GIF") + ) + + internal val expectedGifMediaViewModelCollection = listOf( + createExpectedGifMediaViewModel("first GIF"), + createExpectedGifMediaViewModel("second GIF"), + createExpectedGifMediaViewModel("third GIF"), + createExpectedGifMediaViewModel("fourth GIF") + ) + + private fun createGifResultMock(mockFilling: String) = + mock().apply { + whenever(this.id).thenReturn(mockFilling) + whenever(this.title).thenReturn(mockFilling) + val mediaCollection = createMediaCollectionMock(mockFilling) + whenever(this.medias).thenReturn(listOf(mediaCollection)) + } + + private fun createMediaCollectionMock(mockContent: String) = + mock().apply { + val nanoGifMedia = createMediaMock("$mockContent gif_nano") + val tinyGifMedia = createMediaMock("$mockContent gif_tiny") + val gifMedia = createMediaMock("$mockContent gif") + + whenever(this[MediaCollectionFormat.GIF_NANO]).thenReturn(nanoGifMedia) + whenever(this[MediaCollectionFormat.GIF_TINY]).thenReturn(tinyGifMedia) + whenever(this[MediaCollectionFormat.GIF]).thenReturn(gifMedia) + } + + private fun createMediaMock(mockContent: String) = + mock().apply { whenever(this.url).thenReturn(mockContent) } + + private fun createExpectedGifMediaViewModel(expectedContent: String) = + MutableGiphyMediaViewModel( + expectedContent, + Uri.parse("$expectedContent gif_nano"), + Uri.parse("$expectedContent gif_tiny"), + Uri.parse("$expectedContent gif"), + expectedContent + ) +} diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestUtils.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestUtils.kt deleted file mode 100644 index 7f262ff8f0b6..000000000000 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestUtils.kt +++ /dev/null @@ -1,60 +0,0 @@ -package org.wordpress.android.viewmodel.giphy.provider - -import android.net.Uri -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.whenever -import com.tenor.android.core.constant.MediaCollectionFormat -import com.tenor.android.core.model.impl.Media -import com.tenor.android.core.model.impl.MediaCollection -import com.tenor.android.core.model.impl.Result -import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel - -class TenorProviderTestUtils { - companion object { - internal val mockedTenorResult - get() = listOf( - createGifResultMock("first GIF"), - createGifResultMock("second GIF"), - createGifResultMock("third GIF"), - createGifResultMock("fourth GIF") - ) - - internal val expectedGifMediaViewModelCollection = listOf( - createExpectedGifMediaViewModel("first GIF"), - createExpectedGifMediaViewModel("second GIF"), - createExpectedGifMediaViewModel("third GIF"), - createExpectedGifMediaViewModel("fourth GIF") - ) - - private fun createGifResultMock(mockFilling: String) = - mock().apply { - whenever(this.id).thenReturn(mockFilling) - whenever(this.title).thenReturn(mockFilling) - val mediaCollection = createMediaCollectionMock(mockFilling) - whenever(this.medias).thenReturn(listOf(mediaCollection)) - } - - private fun createMediaCollectionMock(mockContent: String) = - mock().apply { - val nanoGifMedia = createMediaMock("$mockContent gif_nano") - val tinyGifMedia = createMediaMock("$mockContent gif_tiny") - val gifMedia = createMediaMock("$mockContent gif") - - whenever(this[MediaCollectionFormat.GIF_NANO]).thenReturn(nanoGifMedia) - whenever(this[MediaCollectionFormat.GIF_TINY]).thenReturn(tinyGifMedia) - whenever(this[MediaCollectionFormat.GIF]).thenReturn(gifMedia) - } - - private fun createMediaMock(mockContent: String) = - mock().apply { whenever(this.url).thenReturn(mockContent) } - - private fun createExpectedGifMediaViewModel(expectedContent: String) = - MutableGiphyMediaViewModel( - expectedContent, - Uri.parse("$expectedContent gif_nano"), - Uri.parse("$expectedContent gif_tiny"), - Uri.parse("$expectedContent gif"), - expectedContent - ) - } -} From 656172035a4866b55588ec76e166e8dd3935fd66 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 17:36:18 -0300 Subject: [PATCH 26/58] Changed test assertion to use assertThat pattern and improve test readability --- .../giphy/provider/TenorProviderTest.kt | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 8833e1ec29d0..a2f910a3106f 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -10,8 +10,7 @@ import com.tenor.android.core.constant.MediaFilter import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse -import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue +import org.assertj.core.api.Assertions.assertThat import org.junit.Assert.fail import org.junit.Before import org.junit.Test @@ -62,7 +61,7 @@ class TenorProviderTest { 0, onSuccess = { actualViewModelCollection, _ -> onSuccessWasCalled = true - assertEquals(expectedGifMediaViewModelCollection, actualViewModelCollection) + assertThat(actualViewModelCollection).isEqualTo(expectedGifMediaViewModelCollection) }, onFailure = { fail("Failure handler should not be called") @@ -71,7 +70,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) - assertTrue("onSuccess should be called", onSuccessWasCalled) + assertThat(onSuccessWasCalled).isTrue() } @Test @@ -84,7 +83,7 @@ class TenorProviderTest { 0, onSuccess = { _, actualNextPosition -> onSuccessWasCalled = true - assertEquals(expectedNextPosition, actualNextPosition) + assertThat(actualNextPosition).isEqualTo(expectedNextPosition) }, onFailure = { fail("Failure handler should not be called") @@ -93,7 +92,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) - assertTrue("onSuccess should be called", onSuccessWasCalled) + assertThat(onSuccessWasCalled).isTrue() } @Test @@ -105,16 +104,16 @@ class TenorProviderTest { onSuccess = { _, _ -> fail("Success handler should not be called") }, - onFailure = { + onFailure = { throwable -> onFailureWasCalled = true - assertTrue(it is GifRequestFailedException) - assertEquals("Expected message", it.message) + assertThat(throwable).isInstanceOf(GifRequestFailedException::class.java) + assertThat(throwable.message).isEqualTo("Expected message") }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException("Expected message")) - assertTrue("onFailure should be called", onFailureWasCalled) + assertThat(onFailureWasCalled).isTrue() } @Test @@ -126,16 +125,16 @@ class TenorProviderTest { onSuccess = { _, _ -> fail("Success handler should not be called") }, - onFailure = { + onFailure = { throwable -> onFailureWasCalled = true - assertTrue(it is GifRequestFailedException) - assertEquals("No media matching your search", it.message) + assertThat(throwable).isInstanceOf(GifRequestFailedException::class.java) + assertThat(throwable.message).isEqualTo("No media matching your search") }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value capturedCallback.success(ApplicationProvider.getApplicationContext(), null) - assertTrue("onFailure should be called", onFailureWasCalled) + assertThat(onFailureWasCalled).isTrue() } @Test @@ -157,7 +156,8 @@ class TenorProviderTest { any() ) - assertEquals(MediaFilter.BASIC, argument.value) + val requestedMediaFilter = argument.value + assertThat(requestedMediaFilter).isEqualTo(MediaFilter.BASIC) } @Test @@ -179,7 +179,8 @@ class TenorProviderTest { any() ) - assertEquals(50, argument.value) + val requestedLoadSize = argument.value + assertThat(requestedLoadSize).isEqualTo(50) } @Test @@ -202,7 +203,8 @@ class TenorProviderTest { any() ) - assertEquals(20, argument.value) + val requestedLoadSize = argument.value + assertThat(requestedLoadSize).isEqualTo(20) } @Test @@ -225,6 +227,7 @@ class TenorProviderTest { any() ) - assertEquals(50, argument.value) + val requestedLoadSize = argument.value + assertThat(requestedLoadSize).isEqualTo(50) } } From a69afcc36842c5b788f9869e704290f55c12e8be Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 18:14:30 -0300 Subject: [PATCH 27/58] Moved Tenor API initialization to the outside of TenorProvider --- .../android/modules/ApplicationModule.java | 14 +++++++--- .../viewmodel/giphy/provider/TenorProvider.kt | 26 ++----------------- .../giphy/provider/TenorProviderTest.kt | 12 ++++++++- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index 78779162ed9a..6e0474a2d005 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -5,13 +5,16 @@ import androidx.lifecycle.LiveData; +import com.tenor.android.core.network.ApiClient; +import com.tenor.android.core.network.ApiService; +import com.tenor.android.core.network.IApiClient; + +import org.wordpress.android.BuildConfig; import org.wordpress.android.ui.CommentFullScreenDialogFragment; import org.wordpress.android.ui.accounts.signup.SettingsUsernameChangerFragment; import org.wordpress.android.ui.accounts.signup.UsernameChangerFullScreenDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.CountryPickerDialogFragment; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment.StatePickerDialogFragment; -import org.wordpress.android.viewmodel.giphy.provider.GifProvider; -import org.wordpress.android.viewmodel.giphy.provider.TenorProvider; import org.wordpress.android.ui.news.LocalNewsService; import org.wordpress.android.ui.news.NewsService; import org.wordpress.android.ui.reader.ReaderPostWebViewCachingFragment; @@ -30,6 +33,8 @@ import org.wordpress.android.ui.stats.refresh.lists.widget.minified.StatsMinifiedWidgetConfigureFragment; import org.wordpress.android.util.wizard.WizardManager; import org.wordpress.android.viewmodel.ContextProvider; +import org.wordpress.android.viewmodel.giphy.provider.GifProvider; +import org.wordpress.android.viewmodel.giphy.provider.TenorProvider; import org.wordpress.android.viewmodel.helpers.ConnectionStatus; import org.wordpress.android.viewmodel.helpers.ConnectionStatusLiveData; @@ -113,6 +118,9 @@ static LiveData provideConnectionStatusLiveData(Context contex @Provides static GifProvider provideGifProvider(Context context) { - return new TenorProvider(context); + ApiService.IBuilder builder = new ApiService.Builder<>(context, IApiClient.class); + builder.apiKey(BuildConfig.TENOR_API_KEY); + ApiClient.init(context, builder); + return new TenorProvider(context, ApiClient.getInstance(context)); } } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index e384b43450b0..b6c06055fcd5 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -7,11 +7,9 @@ import com.tenor.android.core.constant.MediaCollectionFormat import com.tenor.android.core.constant.MediaFilter import com.tenor.android.core.model.impl.Result import com.tenor.android.core.network.ApiClient -import com.tenor.android.core.network.ApiService import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse -import org.wordpress.android.BuildConfig import org.wordpress.android.R.string import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel @@ -25,28 +23,8 @@ import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFail internal class TenorProvider @JvmOverloads constructor( val context: Context, - tenorClient: IApiClient? = null + private val tenorClient: IApiClient ) : GifProvider { - private val apiClient: IApiClient - - /** - * Initializes the Tenor API client with the environment API key, if no tenorClient is provided via constructor, - * the init will use the default implementation provided by the Tenor library. - */ - init { - ApiService.Builder(context, IApiClient::class.java).apply { - apiKey(BuildConfig.TENOR_API_KEY) - ApiClient.init(context, this) - /** - * If we call [ApiClient.getInstance] before the [ApiClient.init] the Tenor API - * will throw an exception for an illegal operation, but to still make possible for the - * constructor to have the [tenorClient] as a optional parameter, the actual [apiClient] - * will be decided after everything is initialized - */ - apiClient = tenorClient ?: ApiClient.getInstance(context) - } - } - /** * Implementation of the [GifProvider] search method, it will call the Tenor client search * right away with the provided parameters. @@ -58,7 +36,7 @@ internal class TenorProvider @JvmOverloads constructor( onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) { - apiClient.simpleSearch( + tenorClient.simpleSearch( query, position.toString(), loadSize, diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index a2f910a3106f..40d35b0d5bfa 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -7,6 +7,8 @@ import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever import com.tenor.android.core.constant.MediaFilter +import com.tenor.android.core.network.ApiClient +import com.tenor.android.core.network.ApiService.Builder import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse @@ -21,6 +23,7 @@ import org.mockito.Mock import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config +import org.wordpress.android.BuildConfig import org.wordpress.android.TestApplication import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.expectedGifMediaViewModelCollection @@ -43,13 +46,20 @@ class TenorProviderTest { @Before fun setUp() { MockitoAnnotations.initMocks(this) + val context = ApplicationProvider.getApplicationContext() + + Builder(context, IApiClient::class.java).apply { + apiKey(BuildConfig.TENOR_API_KEY) + ApiClient.init(context, this) + } + whenever(apiClient.search(any(), any(), any(), any(), any(), any())) .thenReturn(gifSearchCall) val gifResults = mockedTenorResult whenever(gifResponse.results).thenReturn(gifResults) - tenorProviderUnderTest = TenorProvider(ApplicationProvider.getApplicationContext(), apiClient) + tenorProviderUnderTest = TenorProvider(context, apiClient) } @Test From 45e70dd3fd1d20ec3be6e2321cf1a9c33359ab2a Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 25 Mar 2020 18:18:47 -0300 Subject: [PATCH 28/58] Extracted magic numbers to constants --- .../android/viewmodel/giphy/GiphyPickerViewModel.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt index 58573a2cd9fe..f72fda0ce117 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt @@ -143,8 +143,8 @@ class GiphyPickerViewModel @Inject constructor( val mediaViewModelPagedList: LiveData> by lazy { val pagedListConfig = PagedList.Config.Builder() .setEnablePlaceholders(false) - .setInitialLoadSizeHint(42) - .setPageSize(21) + .setInitialLoadSizeHint(DEFAULT_INITIAL_LOAD_SIZE_HINT) + .setPageSize(DEFAULT_PAGE_SIZE) .build() LivePagedListBuilder(dataSourceFactory, pagedListConfig) @@ -351,4 +351,9 @@ class GiphyPickerViewModel @Inject constructor( * @see [GiphyPickerDataSource.retryAllFailedRangeLoads] */ fun retryAllFailedRangeLoads() = dataSourceFactory.retryAllFailedRangeLoads() + + companion object { + private const val DEFAULT_INITIAL_LOAD_SIZE_HINT = 42 + private const val DEFAULT_PAGE_SIZE = 21 + } } From ec760a1374b3c3d71194a34701ac785d09c5d5fe Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Thu, 26 Mar 2020 00:52:13 -0300 Subject: [PATCH 29/58] Reconnected EditPostActivity with GIF Picker --- .../android/ui/photopicker/PhotoPickerFragment.java | 10 +++++++++- .../wordpress/android/ui/posts/EditPostActivity.java | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java index 82ff18776f17..cb0283615c2c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java @@ -60,7 +60,8 @@ public enum PhotoPickerIcon { ANDROID_CAPTURE_VIDEO(true), ANDROID_CHOOSE_PHOTO_OR_VIDEO(true), WP_MEDIA(false), - STOCK_MEDIA(true); + STOCK_MEDIA(true), + GIF(true); private boolean mRequiresUploadPermission; @@ -257,6 +258,7 @@ public void doIconClicked(@NonNull PhotoPickerIcon icon) { AnalyticsTracker.track(AnalyticsTracker.Stat.MEDIA_PICKER_OPEN_WP_MEDIA); break; case STOCK_MEDIA: + case GIF: break; } @@ -297,6 +299,12 @@ public boolean onMenuItemClick(MenuItem item) { return true; } }); + + MenuItem itemGif = popup.getMenu().add(R.string.photo_picker_gif); + itemGif.setOnMenuItemClickListener(item -> { + doIconClicked(PhotoPickerIcon.GIF); + return true; + }); } popup.show(); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index 27bc02042eb4..182fff62d662 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -101,6 +101,7 @@ import org.wordpress.android.ui.PagePostCreationSourcesDetail; import org.wordpress.android.ui.RequestCodes; import org.wordpress.android.ui.Shortcut; +import org.wordpress.android.ui.giphy.GiphyPickerActivity; import org.wordpress.android.ui.history.HistoryListItem.Revision; import org.wordpress.android.ui.media.MediaBrowserActivity; import org.wordpress.android.ui.media.MediaBrowserType; @@ -920,6 +921,9 @@ public void onPhotoPickerIconClicked(@NonNull PhotoPickerIcon icon, boolean allo ActivityLauncher.showStockMediaPickerForResult( this, mSite, RequestCodes.STOCK_MEDIA_PICKER_MULTI_SELECT); break; + case GIF: + ActivityLauncher.showGifPickerForResult(this, mSite, RequestCodes.GIF_PICKER); + break; } } else { WPSnackbar.make(findViewById(R.id.editor_activity), R.string.media_error_no_permission_upload, @@ -2259,6 +2263,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { .addExistingMediaToEditorAsync(AddExistingMediaSource.STOCK_PHOTO_LIBRARY, mediaIds); } break; + case RequestCodes.GIF_PICKER: + if (data.hasExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS)) { + int[] localIds = data.getIntArrayExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS); + mEditorMedia.addMediaFromGiphyToPostAsync(localIds); + } + break; case RequestCodes.HISTORY_DETAIL: if (data.hasExtra(KEY_REVISION)) { mViewPager.setCurrentItem(PAGE_CONTENT); From 18f0c2eeebd11c60147b97471039187e82d92150 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Thu, 26 Mar 2020 04:41:50 -0300 Subject: [PATCH 30/58] Added tests for GIF Picker DataSource --- .../giphy/GiphyPickerDataSourceFixtures.kt | 12 + .../giphy/GiphyPickerDataSourceTest.kt | 228 ++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFixtures.kt create mode 100644 WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceTest.kt diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFixtures.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFixtures.kt new file mode 100644 index 000000000000..c9e894e839e0 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFixtures.kt @@ -0,0 +1,12 @@ +package org.wordpress.android.viewmodel.giphy + +import com.nhaarman.mockitokotlin2.mock + +object GiphyPickerDataSourceFixtures { + internal val expectedGifMediaViewModelCollection: List = listOf( + mock(), + mock(), + mock(), + mock() + ) +} diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceTest.kt new file mode 100644 index 000000000000..476cf13732d1 --- /dev/null +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceTest.kt @@ -0,0 +1,228 @@ +package org.wordpress.android.viewmodel.giphy + +import androidx.paging.PositionalDataSource.LoadInitialCallback +import androidx.paging.PositionalDataSource.LoadInitialParams +import androidx.paging.PositionalDataSource.LoadRangeCallback +import androidx.paging.PositionalDataSource.LoadRangeParams +import com.nhaarman.mockitokotlin2.KArgumentCaptor +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.argumentCaptor +import com.nhaarman.mockitokotlin2.spy +import com.nhaarman.mockitokotlin2.times +import com.nhaarman.mockitokotlin2.verify +import org.assertj.core.api.Assertions.assertThat +import org.junit.Assert.fail +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.wordpress.android.viewmodel.giphy.GiphyPickerDataSourceFixtures.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.giphy.provider.GifProvider +import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException + +class GiphyPickerDataSourceTest { + @Mock lateinit var gifProvider: GifProvider + + lateinit var onSuccessCaptor: KArgumentCaptor<(List, Int?) -> Unit> + + lateinit var onFailureCaptor: KArgumentCaptor<(Throwable) -> Unit> + + private lateinit var pickerDataSourceUnderTest: GiphyPickerDataSource + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + pickerDataSourceUnderTest = GiphyPickerDataSource(gifProvider, "test") + onSuccessCaptor = argumentCaptor() + onFailureCaptor = argumentCaptor() + } + + @Test + fun `loadInitial should call onResult when search is successful`() { + var onResultWasCalled = false + + val params = LoadInitialParams(0, 20, 5, false) + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { + onResultWasCalled = true + assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) + assertThat(position).isEqualTo(0) + assertThat(totalCount).isEqualTo(4) + } + + override fun onResult(data: MutableList, position: Int) { + fail("Wrong onResult called") + } + } + pickerDataSourceUnderTest.loadInitial(params, dataSourceCallback) + + verify(gifProvider, times(1)).search(any(), any(), any(), onSuccessCaptor.capture(), any()) + val capturedProviderOnSuccess = onSuccessCaptor.firstValue + capturedProviderOnSuccess(expectedGifMediaViewModelCollection, 4) + assertThat(onResultWasCalled).isTrue() + } + + @Test + fun `loadInitial should call onResult with correct position when search is successful but next position is null`() { + var onResultWasCalled = false + + val params = LoadInitialParams(0, 20, 5, false) + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { + onResultWasCalled = true + assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) + assertThat(position).isEqualTo(0) + assertThat(totalCount).isEqualTo(4) + } + + override fun onResult(data: MutableList, position: Int) { + fail("Wrong onResult called") + } + } + pickerDataSourceUnderTest.loadInitial(params, dataSourceCallback) + + verify(gifProvider, times(1)).search(any(), any(), any(), onSuccessCaptor.capture(), any()) + val capturedProviderOnSuccess = onSuccessCaptor.firstValue + capturedProviderOnSuccess(expectedGifMediaViewModelCollection, null) + assertThat(onResultWasCalled).isTrue() + } + + @Test + fun `loadInitial should call onResult with correct position when search is successful but next position is incorrect`() { + var onResultWasCalled = false + + val params = LoadInitialParams(0, 20, 5, false) + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { + onResultWasCalled = true + assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) + assertThat(position).isEqualTo(0) + assertThat(totalCount).isEqualTo(4) + } + + override fun onResult(data: MutableList, position: Int) { + fail("Wrong onResult called") + } + } + pickerDataSourceUnderTest.loadInitial(params, dataSourceCallback) + + verify(gifProvider, times(1)).search(any(), any(), any(), onSuccessCaptor.capture(), any()) + val capturedProviderOnSuccess = onSuccessCaptor.firstValue + capturedProviderOnSuccess(expectedGifMediaViewModelCollection, 2) + assertThat(onResultWasCalled).isTrue() + } + + @Test + fun `loadInitial should call onResult with emptyList when search query is blank`() { + var onResultWasCalled = false + pickerDataSourceUnderTest = GiphyPickerDataSource(gifProvider, "") + + val params = LoadInitialParams(0, 20, 5, false) + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { + onResultWasCalled = true + assertThat(data).isEmpty() + assertThat(position).isEqualTo(0) + assertThat(totalCount).isEqualTo(0) + } + + override fun onResult(data: MutableList, position: Int) { + fail("Wrong onResult called") + } + } + pickerDataSourceUnderTest.loadInitial(params, dataSourceCallback) + + verify(gifProvider, times(0)).search(any(), any(), any(), any(), any()) + assertThat(onResultWasCalled).isTrue() + } + + @Test + fun `loadInitial should call onResult when search fails with emptyList`() { + var onResultWasCalled = false + val expectedThrowable = GifRequestFailedException("Test throwable") + + val params = LoadInitialParams(0, 20, 5, false) + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { + onResultWasCalled = true + assertThat(data).isEmpty() + assertThat(position).isEqualTo(0) + assertThat(totalCount).isEqualTo(0) + } + + override fun onResult(data: MutableList, position: Int) { + fail("Wrong onResult called") + } + } + pickerDataSourceUnderTest.loadInitial(params, dataSourceCallback) + + verify(gifProvider, times(1)).search(any(), any(), any(), any(), onFailureCaptor.capture()) + val capturedProviderOnFailure = onFailureCaptor.firstValue + capturedProviderOnFailure(expectedThrowable) + + assertThat(onResultWasCalled).isTrue() + } + + @Test + fun `loadInitial should set initialLoadError when search fails`() { + var onResultWasCalled = false + val expectedThrowable = GifRequestFailedException("Test throwable") + + val params = LoadInitialParams(0, 20, 5, false) + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { + onResultWasCalled = true + } + + override fun onResult(data: MutableList, position: Int) { + fail("Wrong onResult called") + } + } + pickerDataSourceUnderTest.loadInitial(params, dataSourceCallback) + + verify(gifProvider, times(1)).search(any(), any(), any(), any(), onFailureCaptor.capture()) + val capturedProviderOnFailure = onFailureCaptor.firstValue + capturedProviderOnFailure(expectedThrowable) + + assertThat(onResultWasCalled).isTrue() + assertThat(pickerDataSourceUnderTest.initialLoadError).isNotNull() + assertThat(pickerDataSourceUnderTest.initialLoadError).isInstanceOf(GifRequestFailedException::class.java) + assertThat(pickerDataSourceUnderTest.initialLoadError?.message).isEqualTo("Test throwable") + } + + @Test + fun `loadRange should call onResult when search is successful`() { + var onResultWasCalled = false + + val params = LoadRangeParams(0, 20) + val dataSourceCallback = object: LoadRangeCallback() { + override fun onResult(data: MutableList) { + onResultWasCalled = true + assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) + } + } + pickerDataSourceUnderTest.loadRange(params, dataSourceCallback) + + verify(gifProvider, times(1)).search(any(), any(), any(), onSuccessCaptor.capture(), any()) + val capturedProviderOnSuccess = onSuccessCaptor.firstValue + capturedProviderOnSuccess(expectedGifMediaViewModelCollection, 4) + assertThat(onResultWasCalled).isTrue() + } + + @Test + fun `loadRange should call retryAllFailedRangeLoads when search is successful`() { + val spiedDataSource = spy(pickerDataSourceUnderTest) + + val params = LoadRangeParams(0, 20) + val dataSourceCallback = object: LoadRangeCallback() { + override fun onResult(data: MutableList) {} + } + spiedDataSource.loadRange(params, dataSourceCallback) + + verify(gifProvider, times(1)).search(any(), any(), any(), onSuccessCaptor.capture(), any()) + val capturedProviderOnSuccess = onSuccessCaptor.firstValue + capturedProviderOnSuccess(expectedGifMediaViewModelCollection, 2) + + verify(spiedDataSource, times(1)).retryAllFailedRangeLoads() + } +} From f0f20064056058555ca6199f7db018bc649b896d Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Thu, 26 Mar 2020 21:08:23 -0300 Subject: [PATCH 31/58] Added thread safety and timeout handling to TenorProvider --- .../viewmodel/giphy/provider/TenorProvider.kt | 107 +++++++++++++----- .../giphy/provider/TenorProviderTest.kt | 98 ++++++++++++++++ 2 files changed, 174 insertions(+), 31 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index b6c06055fcd5..f76b5678cc20 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -10,10 +10,16 @@ import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.wordpress.android.R.string import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException +import retrofit2.Call /** * Implementation of a GifProvider using the Tenor GIF API as provider @@ -23,7 +29,8 @@ import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFail internal class TenorProvider @JvmOverloads constructor( val context: Context, - private val tenorClient: IApiClient + private val tenorClient: IApiClient, + private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default) ) : GifProvider { /** * Implementation of the [GifProvider] search method, it will call the Tenor client search @@ -36,7 +43,7 @@ internal class TenorProvider @JvmOverloads constructor( onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) { - tenorClient.simpleSearch( + tenorClient.enqueueSearchRequest( query, position.toString(), loadSize, @@ -50,45 +57,78 @@ internal class TenorProvider @JvmOverloads constructor( } /** - * This method act as a simplification to call a search within the Tenor API and the callback - * creation - * [MediaFilter] must be BASIC or the returned Media will not have a displayable thumbnail - * All other provided parameters are set following the Tenor API Documentation + * The [onSuccess] will be called if the response is not null * * The [onFailure] will be called assuming that no valid GIF was found * or that a direct failure was found by Tenor API * * Method is inlined for better high-order functions performance */ - private inline fun IApiClient.simpleSearch( + private inline fun IApiClient.enqueueSearchRequest( query: String, position: String, loadSize: Int?, crossinline onSuccess: (GifsResponse) -> Unit, crossinline onFailure: (Throwable?) -> Unit - ) { - search( - ApiClient.getServiceIds(context), - query, - loadSize.fittedToMaximumAllowed, - position, - MediaFilter.BASIC, - AspectRatioRange.ALL - - ).enqueue(object : WeakRefCallback(context) { + ) = buildSearchCall(query, loadSize, position).apply { + enqueue(object : WeakRefCallback(context) { override fun success(context: Context, response: GifsResponse?) { + this@apply.cancel() response?.let(onSuccess) - ?: onFailure( - GifRequestFailedException( - context.getString(string.giphy_picker_empty_search_list) - ) - ) + ?: onFailure(buildGifRequestFailure(string.giphy_picker_empty_search_list)) } override fun failure(context: Context, throwable: Throwable?) { + this@apply.cancel() onFailure(throwable) } }) + + dispatchTimeoutClock(onFailure) + } + + /** + * This method act as a simplification to call a search within the Tenor API and the callback + * creation + * + * [MediaFilter] must be BASIC or the returned Media will not have a displayable thumbnail + * All other provided parameters are set following the Tenor API Documentation + */ + private fun IApiClient.buildSearchCall( + query: String, + loadSize: Int?, + position: String + ) = search( + ApiClient.getServiceIds(context), + query, + loadSize.fittedToMaximumAllowed, + position, + MediaFilter.BASIC, + AspectRatioRange.ALL + ) + + /** + * This method counts from 0 to [DEFAULT_SECONDS_TO_TIMEOUT] to make sure that + * every request responds within the expected amount of time. + * + * If the call isn't canceled until the timer reaches the limit, + * the [onFailure] will be called passing an [GifRequestTimeoutException] + * + * But if the call is canceled before the timer reaches the limit, + * the coroutine job will right away be canceled and the [onFailure] call + * won't be reached + * + * Method is inlined for better high-order functions performance + */ + private inline fun Call.dispatchTimeoutClock( + crossinline onFailure: (Throwable?) -> Unit + ) = scope.launch { + for (timeTick in 0 until DEFAULT_SECONDS_TO_TIMEOUT) { + if (this@dispatchTimeoutClock.isCanceled) this@launch.cancel() + delay(ONE_SECOND_IN_MILLIS) + } + + CoroutineScope(Dispatchers.Main).launch { onFailure(GifRequestTimeoutException()) } } /** @@ -99,8 +139,8 @@ internal class TenorProvider @JvmOverloads constructor( */ private inline fun handleResponse( response: GifsResponse, - onSuccess: (List, Int?) -> Unit - ) { + crossinline onSuccess: (List, Int?) -> Unit + ) = CoroutineScope(Dispatchers.Main).launch { response.results.map { it.toMutableGifMediaViewModel() } .let { gifs -> val nextPosition = response.next.toIntOrNull() @@ -116,15 +156,11 @@ internal class TenorProvider @JvmOverloads constructor( */ private inline fun handleFailure( throwable: Throwable, - onFailure: (Throwable) -> Unit - ) { + crossinline onFailure: (Throwable) -> Unit + ) = CoroutineScope(Dispatchers.Main).launch { throwable.message?.let { message -> onFailure(GifRequestFailedException(message)) - } ?: onFailure( - GifRequestFailedException( - context.getString(string.gifs_list_search_returned_unknown_error) - ) - ) + } ?: onFailure(buildGifRequestFailure(string.gifs_list_search_returned_unknown_error)) } /** @@ -157,10 +193,19 @@ internal class TenorProvider @JvmOverloads constructor( } } ?: MAXIMUM_ALLOWED_LOAD_SIZE + private fun buildGifRequestFailure(resourceId: Int) = GifRequestFailedException(context.getString(resourceId)) + + /** + * An Exception to describe timeouts within the TenorProvider when a [onFailure] is called + */ + class GifRequestTimeoutException : Exception("The Tenor request took too long to respond") + companion object { /** * To better refers to the Tenor API maximum GIF limit per request */ private const val MAXIMUM_ALLOWED_LOAD_SIZE = 50 + private const val DEFAULT_SECONDS_TO_TIMEOUT = 10 + private const val ONE_SECOND_IN_MILLIS = 1000L } } diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 40d35b0d5bfa..875f581517d2 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -12,6 +12,8 @@ import com.tenor.android.core.network.ApiService.Builder import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runBlockingTest import org.assertj.core.api.Assertions.assertThat import org.junit.Assert.fail import org.junit.Before @@ -26,10 +28,12 @@ import org.robolectric.annotation.Config import org.wordpress.android.BuildConfig import org.wordpress.android.TestApplication import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException +import org.wordpress.android.viewmodel.giphy.provider.TenorProvider.GifRequestTimeoutException import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.expectedGifMediaViewModelCollection import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.mockedTenorResult import retrofit2.Call +@ExperimentalCoroutinesApi @Config(application = TestApplication::class) @RunWith(RobolectricTestRunner::class) class TenorProviderTest { @@ -240,4 +244,98 @@ class TenorProviderTest { val requestedLoadSize = argument.value assertThat(requestedLoadSize).isEqualTo(50) } + + @Test + fun `timeout job should trigger onFailure when nothing is invoked from search`() { + var onFailureWasCalled = false + whenever(gifResponse.next).thenReturn("0") + whenever(gifSearchCall.cancel()).then { + whenever(gifSearchCall.isCanceled).thenReturn(true) + } + + runBlockingTest { + val context = ApplicationProvider.getApplicationContext() + tenorProviderUnderTest = TenorProvider(context, apiClient, this) + + tenorProviderUnderTest.search("test", + 0, + onSuccess = { actualViewModelCollection, _ -> + fail("Failure handler should not be called") + }, + onFailure = { + onFailureWasCalled = true + }) + } + assertThat(onFailureWasCalled).isTrue() + assertThat(gifSearchCall.isCanceled).isFalse() + } + + @Test + fun `timeout job should not trigger onFailure when onSuccess is called`() { + var onFailureWasCalled = false + var onSuccessWasCalled = false + + whenever(gifResponse.next).thenReturn("0") + whenever(gifSearchCall.cancel()).then { + whenever(gifSearchCall.isCanceled).thenReturn(true) + } + + runBlockingTest { + val context = ApplicationProvider.getApplicationContext() + tenorProviderUnderTest = TenorProvider(context, apiClient, this) + + tenorProviderUnderTest.search("test", + 0, + onSuccess = { actualViewModelCollection, _ -> + onSuccessWasCalled = true + }, + onFailure = { + onFailureWasCalled = true + }) + + verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) + val capturedCallback = callbackCaptor.value + capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) + } + + assertThat(onSuccessWasCalled).isTrue() + assertThat(onFailureWasCalled).isFalse() + assertThat(gifSearchCall.isCanceled).isTrue() + } + + @Test + fun `timeout job should not trigger when onFailure is called from the search`() { + var onFailureWasCalled = false + var onSuccessWasCalled = false + var expectedException: Throwable? = null + + whenever(gifResponse.next).thenReturn("0") + whenever(gifSearchCall.cancel()).then { + whenever(gifSearchCall.isCanceled).thenReturn(true) + } + + runBlockingTest { + val context = ApplicationProvider.getApplicationContext() + tenorProviderUnderTest = TenorProvider(context, apiClient, this) + + tenorProviderUnderTest.search("test", + 0, + onSuccess = { actualViewModelCollection, _ -> + onSuccessWasCalled = true + }, + onFailure = { + onFailureWasCalled = true + expectedException = it + }) + + verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) + val capturedCallback = callbackCaptor.value + capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException("Expected message")) + } + + assertThat(onSuccessWasCalled).isFalse() + assertThat(onFailureWasCalled).isTrue() + assertThat(expectedException).isNotInstanceOf(GifRequestTimeoutException::class.java) + assertThat(gifSearchCall.isCanceled).isTrue() + } } From 6dbeea08a73fb21820075709afd1c0f093d985cc Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Thu, 26 Mar 2020 23:19:22 -0300 Subject: [PATCH 32/58] Restored Analytics tracking --- .../org/wordpress/android/ui/ActivityLauncher.java | 5 ++++- .../android/ui/giphy/GiphyPickerActivity.kt | 4 +++- .../android/viewmodel/giphy/GiphyPickerViewModel.kt | 4 +++- .../android/analytics/AnalyticsTracker.java | 6 +++--- .../android/analytics/AnalyticsTrackerNosara.java | 12 ++++++------ 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java index c779e0c51030..c3c887b2e174 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java @@ -175,9 +175,12 @@ public static void showStockMediaPickerForResult(Activity activity, } public static void showGifPickerForResult(Activity activity, @NonNull SiteModel site, int requestCode) { + Map properties = new HashMap<>(); + properties.put("from", activity.getClass().getSimpleName()); + AnalyticsTracker.track(Stat.GIF_PICKER_ACCESSED, properties); + Intent intent = new Intent(activity, GiphyPickerActivity.class); intent.putExtra(WordPress.SITE, site); - activity.startActivityForResult(intent, requestCode); } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt index 12a4656d8acd..b0d94b6ea758 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt @@ -25,6 +25,7 @@ import org.wordpress.android.ui.media.MediaPreviewActivity import org.wordpress.android.util.AniUtils import org.wordpress.android.util.DisplayUtils import org.wordpress.android.util.ToastUtils +import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.ViewModelFactory @@ -45,6 +46,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { */ @Inject lateinit var imageManager: ImageManager @Inject lateinit var viewModelFactory: ViewModelFactory + @Inject lateinit var analyticsTrackerWrapper: AnalyticsTrackerWrapper private lateinit var viewModel: GiphyPickerViewModel @@ -346,7 +348,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { } val properties = mapOf("number_of_media_selected" to mediaLocalIds.size) - AnalyticsTracker.track(AnalyticsTracker.Stat.GIPHY_PICKER_DOWNLOADED, properties) + analyticsTrackerWrapper.track(AnalyticsTracker.Stat.GIF_PICKER_DOWNLOADED, properties) } /** diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt index f72fda0ce117..7083d5afee68 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt @@ -19,6 +19,7 @@ import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.util.NetworkUtilsWrapper +import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import org.wordpress.android.util.getDistinct import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject @@ -33,6 +34,7 @@ import javax.inject.Inject */ class GiphyPickerViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, + private val analyticsTrackerWrapper: AnalyticsTrackerWrapper, private val mediaFetcher: GiphyMediaFetcher, /** * The [GiphyPickerDataSourceFactory] to use @@ -231,7 +233,7 @@ class GiphyPickerViewModel @Inject constructor( dataSourceFactory.searchQuery = query - AnalyticsTracker.track(AnalyticsTracker.Stat.GIPHY_PICKER_SEARCHED) + analyticsTrackerWrapper.track(AnalyticsTracker.Stat.GIF_PICKER_SEARCHED) } else { searchQueryChannel.send(query) } diff --git a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java index 4bad16dca558..7415d78f5316 100644 --- a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java +++ b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java @@ -483,9 +483,9 @@ public enum Stat { STOCK_MEDIA_ACCESSED, STOCK_MEDIA_SEARCHED, STOCK_MEDIA_UPLOADED, - GIPHY_PICKER_SEARCHED, - GIPHY_PICKER_ACCESSED, - GIPHY_PICKER_DOWNLOADED, + GIF_PICKER_SEARCHED, + GIF_PICKER_ACCESSED, + GIF_PICKER_DOWNLOADED, SHORTCUT_STATS_CLICKED, SHORTCUT_NOTIFICATIONS_CLICKED, SHORTCUT_NEW_POST_CLICKED, diff --git a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java index ea2d36fcee0a..60a58e7fbc51 100644 --- a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java +++ b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java @@ -1502,12 +1502,12 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "stock_media_searched"; case STOCK_MEDIA_UPLOADED: return "stock_media_uploaded"; - case GIPHY_PICKER_SEARCHED: - return "giphy_picker_searched"; - case GIPHY_PICKER_ACCESSED: - return "giphy_picker_accessed"; - case GIPHY_PICKER_DOWNLOADED: - return "giphy_picker_downloaded"; + case GIF_PICKER_SEARCHED: + return "gif_picker_searched"; + case GIF_PICKER_ACCESSED: + return "gif_picker_accessed"; + case GIF_PICKER_DOWNLOADED: + return "gif_picker_downloaded"; case SHORTCUT_STATS_CLICKED: return "shortcut_stats_clicked"; case SHORTCUT_NOTIFICATIONS_CLICKED: From ffe47e40cd6584a7e0fd3b160abad3bec277bc36 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Thu, 26 Mar 2020 23:47:54 -0300 Subject: [PATCH 33/58] Added Tenor attribution icon, removed the Giphy one --- .../android/ui/giphy/GiphyPickerActivity.kt | 2 +- .../src/main/res/drawable/img_giphy_100dp.xml | 80 ------------------- .../src/main/res/drawable/img_tenor_100dp.xml | 27 +++++++ 3 files changed, 28 insertions(+), 81 deletions(-) delete mode 100644 WordPress/src/main/res/drawable/img_giphy_100dp.xml create mode 100644 WordPress/src/main/res/drawable/img_tenor_100dp.xml diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt index b0d94b6ea758..6d856221792f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt @@ -202,7 +202,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { val emptyView: ActionableEmptyView = actionable_empty_view emptyView.run { image.setImageResource(R.drawable.img_illustration_media_105dp) - bottomImage.setImageResource(R.drawable.img_giphy_100dp) + bottomImage.setImageResource(R.drawable.img_tenor_100dp) bottomImage.contentDescription = getString(R.string.giphy_powered_by_giphy) } diff --git a/WordPress/src/main/res/drawable/img_giphy_100dp.xml b/WordPress/src/main/res/drawable/img_giphy_100dp.xml deleted file mode 100644 index 7648c59bbe73..000000000000 --- a/WordPress/src/main/res/drawable/img_giphy_100dp.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WordPress/src/main/res/drawable/img_tenor_100dp.xml b/WordPress/src/main/res/drawable/img_tenor_100dp.xml new file mode 100644 index 000000000000..f52b5a88c513 --- /dev/null +++ b/WordPress/src/main/res/drawable/img_tenor_100dp.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + From e4c91bb9b65c50c8bc7e1b520794e74313ff0ff6 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 27 Mar 2020 00:54:45 -0300 Subject: [PATCH 34/58] Fixed Picker ViewModel tests --- .../android/viewmodel/giphy/GiphyPickerViewModelTest.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt index 4c3480cdfd52..c04b9a051852 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt @@ -19,6 +19,7 @@ import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.util.NetworkUtilsWrapper +import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.EmptyDisplayMode import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.State import java.util.Random @@ -33,6 +34,7 @@ class GiphyPickerViewModelTest { private val dataSourceFactory = mock() private val mediaFetcher = mock() + private val analyticsTracker = mock() @Mock private lateinit var networkUtils: NetworkUtilsWrapper @@ -41,7 +43,8 @@ class GiphyPickerViewModelTest { viewModel = GiphyPickerViewModel( dataSourceFactory = dataSourceFactory, networkUtils = networkUtils, - mediaFetcher = mediaFetcher + mediaFetcher = mediaFetcher, + analyticsTrackerWrapper = analyticsTracker ) viewModel.setup(site = mock()) whenever(networkUtils.isNetworkAvailable()).thenReturn(true) From c673a530e01900b064a610b60fa2b6301126b035 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 27 Mar 2020 01:27:51 -0300 Subject: [PATCH 35/58] Formatted tenor image --- .../src/main/res/drawable/img_tenor_100dp.xml | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/WordPress/src/main/res/drawable/img_tenor_100dp.xml b/WordPress/src/main/res/drawable/img_tenor_100dp.xml index f52b5a88c513..fa9d35cedb2e 100644 --- a/WordPress/src/main/res/drawable/img_tenor_100dp.xml +++ b/WordPress/src/main/res/drawable/img_tenor_100dp.xml @@ -1,27 +1,48 @@ - - - - + - - + + android:strokeColor="#00000000" + android:strokeWidth="1" /> - - + + android:strokeColor="#00000000" + android:strokeWidth="1" /> - + + + + android:strokeColor="#00000000" + android:strokeWidth="1" /> From e3efa2419e4004e08c8c22f7610e82f00bc977fa Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 27 Mar 2020 01:44:28 -0300 Subject: [PATCH 36/58] Refactored TenorProviderTest boilerplate --- .../giphy/provider/TenorProviderTest.kt | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 875f581517d2..39783da0b516 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -62,6 +62,10 @@ class TenorProviderTest { val gifResults = mockedTenorResult whenever(gifResponse.results).thenReturn(gifResults) + whenever(gifResponse.next).thenReturn("0") + whenever(gifSearchCall.cancel()).then { + whenever(gifSearchCall.isCanceled).thenReturn(true) + } tenorProviderUnderTest = TenorProvider(context, apiClient) } @@ -69,7 +73,6 @@ class TenorProviderTest { @Test fun `search call should invoke onSuccess with expected GIF list and nextPosition for valid query`() { var onSuccessWasCalled = false - whenever(gifResponse.next).thenReturn("0") tenorProviderUnderTest.search("test", 0, @@ -90,7 +93,6 @@ class TenorProviderTest { @Test fun `search call should invoke onSuccess with expected nextPosition for a valid query`() { var onSuccessWasCalled = false - whenever(gifResponse.next).thenReturn("0") val expectedNextPosition = 0 tenorProviderUnderTest.search("test", @@ -248,10 +250,7 @@ class TenorProviderTest { @Test fun `timeout job should trigger onFailure when nothing is invoked from search`() { var onFailureWasCalled = false - whenever(gifResponse.next).thenReturn("0") - whenever(gifSearchCall.cancel()).then { - whenever(gifSearchCall.isCanceled).thenReturn(true) - } + var onSuccessWasCalled = false runBlockingTest { val context = ApplicationProvider.getApplicationContext() @@ -259,14 +258,16 @@ class TenorProviderTest { tenorProviderUnderTest.search("test", 0, - onSuccess = { actualViewModelCollection, _ -> - fail("Failure handler should not be called") + onSuccess = { _, _ -> + onSuccessWasCalled = true }, onFailure = { onFailureWasCalled = true }) } + assertThat(onFailureWasCalled).isTrue() + assertThat(onSuccessWasCalled).isFalse() assertThat(gifSearchCall.isCanceled).isFalse() } @@ -275,18 +276,13 @@ class TenorProviderTest { var onFailureWasCalled = false var onSuccessWasCalled = false - whenever(gifResponse.next).thenReturn("0") - whenever(gifSearchCall.cancel()).then { - whenever(gifSearchCall.isCanceled).thenReturn(true) - } - runBlockingTest { val context = ApplicationProvider.getApplicationContext() tenorProviderUnderTest = TenorProvider(context, apiClient, this) tenorProviderUnderTest.search("test", 0, - onSuccess = { actualViewModelCollection, _ -> + onSuccess = { _, _ -> onSuccessWasCalled = true }, onFailure = { @@ -309,18 +305,13 @@ class TenorProviderTest { var onSuccessWasCalled = false var expectedException: Throwable? = null - whenever(gifResponse.next).thenReturn("0") - whenever(gifSearchCall.cancel()).then { - whenever(gifSearchCall.isCanceled).thenReturn(true) - } - runBlockingTest { val context = ApplicationProvider.getApplicationContext() tenorProviderUnderTest = TenorProvider(context, apiClient, this) tenorProviderUnderTest.search("test", 0, - onSuccess = { actualViewModelCollection, _ -> + onSuccess = { _, _ -> onSuccessWasCalled = true }, onFailure = { From 1a62bb1c1a013a72c0dcb68e84fdcb89f65dba15 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 27 Mar 2020 17:47:19 -0300 Subject: [PATCH 37/58] Removed unnecessary methods for response and error handling --- .../viewmodel/giphy/provider/TenorProvider.kt | 52 +++++-------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index f76b5678cc20..6dd4e7ab3c79 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -35,6 +35,13 @@ internal class TenorProvider @JvmOverloads constructor( /** * Implementation of the [GifProvider] search method, it will call the Tenor client search * right away with the provided parameters. + * + * If the search request succeeds an [List] of [MutableGiphyMediaViewModel] will be passed with the next position + * for pagination. If there's no next position provided, it will be passed as null. + * + * If the search request fails an [GifRequestFailedException] will be passed with the API + * message. If there's no message provided, a generic message will be applied. + * */ override fun search( query: String, @@ -48,10 +55,13 @@ internal class TenorProvider @JvmOverloads constructor( position.toString(), loadSize, onSuccess = { response -> - handleResponse(response, onSuccess) + val gifList = response.results.map { it.toMutableGifMediaViewModel() } + val nextPosition = response.next.toIntOrNull() + onSuccess(gifList, nextPosition) }, onFailure = { - it?.let { throwable -> handleFailure(throwable, onFailure) } + val errorMessage = it?.message ?: context.getString(string.gifs_list_search_returned_unknown_error) + onFailure(GifRequestFailedException(errorMessage)) } ) } @@ -74,8 +84,8 @@ internal class TenorProvider @JvmOverloads constructor( enqueue(object : WeakRefCallback(context) { override fun success(context: Context, response: GifsResponse?) { this@apply.cancel() - response?.let(onSuccess) - ?: onFailure(buildGifRequestFailure(string.giphy_picker_empty_search_list)) + val defaultErrorMessage = context.getString(string.giphy_picker_empty_search_list) + response?.let(onSuccess) ?: onFailure(GifRequestFailedException(defaultErrorMessage)) } override fun failure(context: Context, throwable: Throwable?) { @@ -131,38 +141,6 @@ internal class TenorProvider @JvmOverloads constructor( CoroutineScope(Dispatchers.Main).launch { onFailure(GifRequestTimeoutException()) } } - /** - * If the search request succeeds an [List] of [MutableGiphyMediaViewModel] will be passed with the next position - * for pagination. If there's no next position provided, it will be passed as null. - * - * Method is inlined for better high-order functions performance - */ - private inline fun handleResponse( - response: GifsResponse, - crossinline onSuccess: (List, Int?) -> Unit - ) = CoroutineScope(Dispatchers.Main).launch { - response.results.map { it.toMutableGifMediaViewModel() } - .let { gifs -> - val nextPosition = response.next.toIntOrNull() - onSuccess(gifs, nextPosition) - } - } - - /** - * If the search request fails an [GifRequestFailedException] will be passed with the API - * message. If there's no message provided, a generic message will be applied. - * - * Method is inlined for better high-order functions performance - */ - private inline fun handleFailure( - throwable: Throwable, - crossinline onFailure: (Throwable) -> Unit - ) = CoroutineScope(Dispatchers.Main).launch { - throwable.message?.let { message -> - onFailure(GifRequestFailedException(message)) - } ?: onFailure(buildGifRequestFailure(string.gifs_list_search_returned_unknown_error)) - } - /** * Every GIF returned by the Tenor will be available as [Result], to better interface * with our app, it will be converted to [MutableGiphyMediaViewModel] to avoid any external @@ -193,8 +171,6 @@ internal class TenorProvider @JvmOverloads constructor( } } ?: MAXIMUM_ALLOWED_LOAD_SIZE - private fun buildGifRequestFailure(resourceId: Int) = GifRequestFailedException(context.getString(resourceId)) - /** * An Exception to describe timeouts within the TenorProvider when a [onFailure] is called */ From a854c9132066396926458a250d8cabcf7b2d29db Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 27 Mar 2020 20:09:19 -0300 Subject: [PATCH 38/58] Replaced Tenor callback implementation to the default retrofit one --- .../viewmodel/giphy/provider/TenorProvider.kt | 44 +------- .../giphy/provider/TenorProviderTest.kt | 105 ++---------------- 2 files changed, 17 insertions(+), 132 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index 6dd4e7ab3c79..4fb14f7b19ad 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -8,18 +8,16 @@ import com.tenor.android.core.constant.MediaFilter import com.tenor.android.core.model.impl.Result import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.IApiClient -import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import org.wordpress.android.R.string import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response /** * Implementation of a GifProvider using the Tenor GIF API as provider @@ -81,20 +79,16 @@ internal class TenorProvider @JvmOverloads constructor( crossinline onSuccess: (GifsResponse) -> Unit, crossinline onFailure: (Throwable?) -> Unit ) = buildSearchCall(query, loadSize, position).apply { - enqueue(object : WeakRefCallback(context) { - override fun success(context: Context, response: GifsResponse?) { - this@apply.cancel() + enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { val defaultErrorMessage = context.getString(string.giphy_picker_empty_search_list) - response?.let(onSuccess) ?: onFailure(GifRequestFailedException(defaultErrorMessage)) + response.body()?.let(onSuccess) ?: onFailure(GifRequestFailedException(defaultErrorMessage)) } - override fun failure(context: Context, throwable: Throwable?) { - this@apply.cancel() + override fun onFailure(call: Call, throwable: Throwable) { onFailure(throwable) } }) - - dispatchTimeoutClock(onFailure) } /** @@ -117,30 +111,6 @@ internal class TenorProvider @JvmOverloads constructor( AspectRatioRange.ALL ) - /** - * This method counts from 0 to [DEFAULT_SECONDS_TO_TIMEOUT] to make sure that - * every request responds within the expected amount of time. - * - * If the call isn't canceled until the timer reaches the limit, - * the [onFailure] will be called passing an [GifRequestTimeoutException] - * - * But if the call is canceled before the timer reaches the limit, - * the coroutine job will right away be canceled and the [onFailure] call - * won't be reached - * - * Method is inlined for better high-order functions performance - */ - private inline fun Call.dispatchTimeoutClock( - crossinline onFailure: (Throwable?) -> Unit - ) = scope.launch { - for (timeTick in 0 until DEFAULT_SECONDS_TO_TIMEOUT) { - if (this@dispatchTimeoutClock.isCanceled) this@launch.cancel() - delay(ONE_SECOND_IN_MILLIS) - } - - CoroutineScope(Dispatchers.Main).launch { onFailure(GifRequestTimeoutException()) } - } - /** * Every GIF returned by the Tenor will be available as [Result], to better interface * with our app, it will be converted to [MutableGiphyMediaViewModel] to avoid any external @@ -181,7 +151,5 @@ internal class TenorProvider @JvmOverloads constructor( * To better refers to the Tenor API maximum GIF limit per request */ private const val MAXIMUM_ALLOWED_LOAD_SIZE = 50 - private const val DEFAULT_SECONDS_TO_TIMEOUT = 10 - private const val ONE_SECOND_IN_MILLIS = 1000L } } diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 39783da0b516..08d723eee57d 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -10,10 +10,8 @@ import com.tenor.android.core.constant.MediaFilter import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.ApiService.Builder import com.tenor.android.core.network.IApiClient -import com.tenor.android.core.response.WeakRefCallback import com.tenor.android.core.response.impl.GifsResponse import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runBlockingTest import org.assertj.core.api.Assertions.assertThat import org.junit.Assert.fail import org.junit.Before @@ -28,10 +26,11 @@ import org.robolectric.annotation.Config import org.wordpress.android.BuildConfig import org.wordpress.android.TestApplication import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException -import org.wordpress.android.viewmodel.giphy.provider.TenorProvider.GifRequestTimeoutException import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.expectedGifMediaViewModelCollection import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.mockedTenorResult import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response @ExperimentalCoroutinesApi @Config(application = TestApplication::class) @@ -41,9 +40,11 @@ class TenorProviderTest { @Mock lateinit var gifSearchCall: Call + @Mock lateinit var callbackResponse: Response + @Mock lateinit var gifResponse: GifsResponse - @Captor lateinit var callbackCaptor: ArgumentCaptor> + @Captor lateinit var callbackCaptor: ArgumentCaptor> private lateinit var tenorProviderUnderTest: TenorProvider @@ -63,9 +64,7 @@ class TenorProviderTest { val gifResults = mockedTenorResult whenever(gifResponse.results).thenReturn(gifResults) whenever(gifResponse.next).thenReturn("0") - whenever(gifSearchCall.cancel()).then { - whenever(gifSearchCall.isCanceled).thenReturn(true) - } + whenever(callbackResponse.body()).thenReturn(gifResponse) tenorProviderUnderTest = TenorProvider(context, apiClient) } @@ -86,7 +85,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value - capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) + capturedCallback.onResponse(gifSearchCall, callbackResponse) assertThat(onSuccessWasCalled).isTrue() } @@ -107,7 +106,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value - capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) + capturedCallback.onResponse(gifSearchCall, callbackResponse) assertThat(onSuccessWasCalled).isTrue() } @@ -128,13 +127,14 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value - capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException("Expected message")) + capturedCallback.onFailure(gifSearchCall, RuntimeException("Expected message")) assertThat(onFailureWasCalled).isTrue() } @Test fun `search call should invoke onFailure when null GifResponse is returned`() { var onFailureWasCalled = false + whenever(callbackResponse.body()).thenReturn(null) tenorProviderUnderTest.search("test", 0, @@ -149,7 +149,7 @@ class TenorProviderTest { verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) val capturedCallback = callbackCaptor.value - capturedCallback.success(ApplicationProvider.getApplicationContext(), null) + capturedCallback.onResponse(gifSearchCall, callbackResponse) assertThat(onFailureWasCalled).isTrue() } @@ -246,87 +246,4 @@ class TenorProviderTest { val requestedLoadSize = argument.value assertThat(requestedLoadSize).isEqualTo(50) } - - @Test - fun `timeout job should trigger onFailure when nothing is invoked from search`() { - var onFailureWasCalled = false - var onSuccessWasCalled = false - - runBlockingTest { - val context = ApplicationProvider.getApplicationContext() - tenorProviderUnderTest = TenorProvider(context, apiClient, this) - - tenorProviderUnderTest.search("test", - 0, - onSuccess = { _, _ -> - onSuccessWasCalled = true - }, - onFailure = { - onFailureWasCalled = true - }) - } - - assertThat(onFailureWasCalled).isTrue() - assertThat(onSuccessWasCalled).isFalse() - assertThat(gifSearchCall.isCanceled).isFalse() - } - - @Test - fun `timeout job should not trigger onFailure when onSuccess is called`() { - var onFailureWasCalled = false - var onSuccessWasCalled = false - - runBlockingTest { - val context = ApplicationProvider.getApplicationContext() - tenorProviderUnderTest = TenorProvider(context, apiClient, this) - - tenorProviderUnderTest.search("test", - 0, - onSuccess = { _, _ -> - onSuccessWasCalled = true - }, - onFailure = { - onFailureWasCalled = true - }) - - verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) - val capturedCallback = callbackCaptor.value - capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) - } - - assertThat(onSuccessWasCalled).isTrue() - assertThat(onFailureWasCalled).isFalse() - assertThat(gifSearchCall.isCanceled).isTrue() - } - - @Test - fun `timeout job should not trigger when onFailure is called from the search`() { - var onFailureWasCalled = false - var onSuccessWasCalled = false - var expectedException: Throwable? = null - - runBlockingTest { - val context = ApplicationProvider.getApplicationContext() - tenorProviderUnderTest = TenorProvider(context, apiClient, this) - - tenorProviderUnderTest.search("test", - 0, - onSuccess = { _, _ -> - onSuccessWasCalled = true - }, - onFailure = { - onFailureWasCalled = true - expectedException = it - }) - - verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) - val capturedCallback = callbackCaptor.value - capturedCallback.failure(ApplicationProvider.getApplicationContext(), RuntimeException("Expected message")) - } - - assertThat(onSuccessWasCalled).isFalse() - assertThat(onFailureWasCalled).isTrue() - assertThat(expectedException).isNotInstanceOf(GifRequestTimeoutException::class.java) - assertThat(gifSearchCall.isCanceled).isTrue() - } } From 4efed5f94ed10e1e8287e95db68c11d8f7f2331a Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 27 Mar 2020 20:12:36 -0300 Subject: [PATCH 39/58] Removed custom timeout exception implementation --- .../android/viewmodel/giphy/provider/TenorProvider.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index 4fb14f7b19ad..735e59acba5c 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -141,11 +141,6 @@ internal class TenorProvider @JvmOverloads constructor( } } ?: MAXIMUM_ALLOWED_LOAD_SIZE - /** - * An Exception to describe timeouts within the TenorProvider when a [onFailure] is called - */ - class GifRequestTimeoutException : Exception("The Tenor request took too long to respond") - companion object { /** * To better refers to the Tenor API maximum GIF limit per request From ec38306cd94b73a3296fa5d3f02aadbff4edd67a Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 27 Mar 2020 20:26:31 -0300 Subject: [PATCH 40/58] Removed coroutine scope injection --- .../android/viewmodel/giphy/provider/TenorProvider.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt index 735e59acba5c..5cb7386d9b23 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt @@ -9,8 +9,6 @@ import com.tenor.android.core.model.impl.Result import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.impl.GifsResponse -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import org.wordpress.android.R.string import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel @@ -25,10 +23,9 @@ import retrofit2.Response * This Provider performs requests to the Tenor API using the [tenorClient]. */ -internal class TenorProvider @JvmOverloads constructor( +internal class TenorProvider constructor( val context: Context, - private val tenorClient: IApiClient, - private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default) + private val tenorClient: IApiClient ) : GifProvider { /** * Implementation of the [GifProvider] search method, it will call the Tenor client search From bbf64190b26d6776b96d9e99dd928870c6b7c1c7 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Mon, 30 Mar 2020 21:39:15 -0300 Subject: [PATCH 41/58] Remove unecessary annotation --- .../android/viewmodel/giphy/provider/TenorProviderTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt index 08d723eee57d..c598611e4a33 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt @@ -32,7 +32,6 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response -@ExperimentalCoroutinesApi @Config(application = TestApplication::class) @RunWith(RobolectricTestRunner::class) class TenorProviderTest { From 40a5873577b45aca0dd1caeab1c356be2405d0e3 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sun, 29 Mar 2020 17:14:51 -0300 Subject: [PATCH 42/58] Renamed all giphy name references inside viewmodel package to only gif --- .../android/modules/ApplicationModule.java | 4 +- .../android/modules/ViewModelModule.java | 6 +- .../android/ui/giphy/GiphyMediaViewHolder.kt | 22 +++---- .../android/ui/giphy/GiphyPickerActivity.kt | 18 +++--- .../ui/giphy/GiphyPickerPagedListAdapter.kt | 16 ++--- .../CoroutineScopedViewModel.kt | 2 +- .../GifMediaFetcher.kt} | 18 +++--- .../GifMediaViewModel.kt} | 4 +- .../GifPickerDataSource.kt} | 24 +++---- .../GifPickerDataSourceFactory.kt} | 28 ++++----- .../GifPickerViewModel.kt} | 52 ++++++++-------- .../MutableGifMediaViewModel.kt} | 12 ++-- .../{giphy => gif}/provider/GifProvider.kt | 8 +-- .../{giphy => gif}/provider/TenorProvider.kt | 16 ++--- .../GifPickerDataSourceTest.kt} | 62 +++++++++---------- .../GifPickerViewModelTest.kt} | 26 ++++---- .../GiphyPickerDataSourceFixtures.kt | 4 +- .../provider/TenorProviderTest.kt | 8 +-- .../provider/TenorProviderTestFixtures.kt | 6 +- 19 files changed, 168 insertions(+), 168 deletions(-) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy => gif}/CoroutineScopedViewModel.kt (97%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyMediaFetcher.kt => gif/GifMediaFetcher.kt} (83%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyMediaViewModel.kt => gif/GifMediaViewModel.kt} (95%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerDataSource.kt => gif/GifPickerDataSource.kt} (85%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerDataSourceFactory.kt => gif/GifPickerDataSourceFactory.kt} (50%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerViewModel.kt => gif/GifPickerViewModel.kt} (88%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy/MutableGiphyMediaViewModel.kt => gif/MutableGifMediaViewModel.kt} (78%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy => gif}/provider/GifProvider.kt (80%) rename WordPress/src/main/java/org/wordpress/android/viewmodel/{giphy => gif}/provider/TenorProvider.kt (88%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerDataSourceTest.kt => gif/GifPickerDataSourceTest.kt} (77%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{giphy/GiphyPickerViewModelTest.kt => gif/GifPickerViewModelTest.kt} (93%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{giphy => gif}/GiphyPickerDataSourceFixtures.kt (55%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{giphy => gif}/provider/TenorProviderTest.kt (95%) rename WordPress/src/test/java/org/wordpress/android/viewmodel/{giphy => gif}/provider/TenorProviderTestFixtures.kt (93%) diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java index 6e0474a2d005..15a93cf44de7 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java @@ -33,8 +33,8 @@ import org.wordpress.android.ui.stats.refresh.lists.widget.minified.StatsMinifiedWidgetConfigureFragment; import org.wordpress.android.util.wizard.WizardManager; import org.wordpress.android.viewmodel.ContextProvider; -import org.wordpress.android.viewmodel.giphy.provider.GifProvider; -import org.wordpress.android.viewmodel.giphy.provider.TenorProvider; +import org.wordpress.android.viewmodel.gif.provider.GifProvider; +import org.wordpress.android.viewmodel.gif.provider.TenorProvider; import org.wordpress.android.viewmodel.helpers.ConnectionStatus; import org.wordpress.android.viewmodel.helpers.ConnectionStatusLiveData; diff --git a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java index cec149670aa7..f2981c1a7386 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/ViewModelModule.java @@ -37,7 +37,7 @@ import org.wordpress.android.viewmodel.activitylog.ActivityLogViewModel; import org.wordpress.android.viewmodel.domains.DomainRegistrationDetailsViewModel; import org.wordpress.android.viewmodel.domains.DomainSuggestionsViewModel; -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel; +import org.wordpress.android.viewmodel.gif.GifPickerViewModel; import org.wordpress.android.viewmodel.history.HistoryViewModel; import org.wordpress.android.viewmodel.main.WPMainActivityViewModel; import org.wordpress.android.viewmodel.pages.PageListViewModel; @@ -218,8 +218,8 @@ abstract class ViewModelModule { @Binds @IntoMap - @ViewModelKey(GiphyPickerViewModel.class) - abstract ViewModel giphyPickerViewModel(GiphyPickerViewModel viewModel); + @ViewModelKey(GifPickerViewModel.class) + abstract ViewModel gifPickerViewModel(GifPickerViewModel viewModel); @Binds @IntoMap diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt index 09b47f52aceb..4e7544fcb28e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt @@ -14,14 +14,14 @@ import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.util.image.ImageType.PHOTO import org.wordpress.android.util.redirectContextClickToLongPressListener -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel +import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** * Represents a single item in the [GiphyPickerActivity]'s grid (RecyclerView). * * This is meant to show a single animated gif. * - * This ViewHolder references a readonly [GiphyMediaViewModel]. It should never update the [GiphyMediaViewModel]. That + * This ViewHolder references a readonly [GifMediaViewModel]. It should never update the [GifMediaViewModel]. That * behavior is handled by the [GiphyPickerViewModel]. This is designed this way so that [GiphyPickerViewModel] * encapsulates all the logic of managing selected items as well as keeping their selection numbers continuous. */ @@ -35,11 +35,11 @@ class GiphyMediaViewHolder( * * If there is no bound [mediaViewModel], this can mean that there was an API error or this is just a placeholder. */ - private val onClickListener: (GiphyMediaViewModel?) -> Unit, + private val onClickListener: (GifMediaViewModel?) -> Unit, /** * A function that is called when the user performs a long press on the thumbnail */ - private val onLongClickListener: (GiphyMediaViewModel) -> Unit, + private val onLongClickListener: (GifMediaViewModel) -> Unit, /** * The view used for this `ViewHolder`. */ @@ -48,13 +48,13 @@ class GiphyMediaViewHolder( * The dimensions used for the ImageView */ thumbnailViewDimensions: ThumbnailViewDimensions -) : LifecycleOwnerViewHolder(itemView) { +) : LifecycleOwnerViewHolder(itemView) { data class ThumbnailViewDimensions(val width: Int, val height: Int) private val thumbnailView: ImageView = itemView.image_thumbnail private val selectionNumberTextView: TextView = itemView.text_selection_count - private var mediaViewModel: GiphyMediaViewModel? = null + private var mediaViewModel: GifMediaViewModel? = null init { thumbnailView.apply { @@ -72,13 +72,13 @@ class GiphyMediaViewHolder( } /** - * Update the views to use the given [GiphyMediaViewModel] + * Update the views to use the given [GifMediaViewModel] * * The [mediaViewModel] is optional because we enable placeholders in the paged list created by - * [org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel]. This causes null values to be bound to + * [org.wordpress.android.viewmodel.gif.GifPickerViewModel]. This causes null values to be bound to * [GiphyMediaViewHolder] instances. */ - override fun bind(item: GiphyMediaViewModel?) { + override fun bind(item: GifMediaViewModel?) { super.bind(item) this.mediaViewModel = item @@ -141,8 +141,8 @@ class GiphyMediaViewHolder( */ fun create( imageManager: ImageManager, - onClickListener: (GiphyMediaViewModel?) -> Unit, - onLongClickListener: (GiphyMediaViewModel) -> Unit, + onClickListener: (GifMediaViewModel?) -> Unit, + onLongClickListener: (GifMediaViewModel) -> Unit, parent: ViewGroup, thumbnailViewDimensions: ThumbnailViewDimensions ): GiphyMediaViewHolder { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt index 6d856221792f..25cddfbf5a8c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt @@ -29,10 +29,10 @@ import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper import org.wordpress.android.util.getDistinct import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.ViewModelFactory -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.State +import org.wordpress.android.viewmodel.gif.GifMediaViewModel +import org.wordpress.android.viewmodel.gif.GifPickerViewModel +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.State import javax.inject.Inject /** @@ -48,7 +48,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { @Inject lateinit var viewModelFactory: ViewModelFactory @Inject lateinit var analyticsTrackerWrapper: AnalyticsTrackerWrapper - private lateinit var viewModel: GiphyPickerViewModel + private lateinit var viewModel: GifPickerViewModel private val gridColumnCount: Int by lazy { if (DisplayUtils.isLandscape(this)) 4 else 3 } @@ -66,7 +66,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { val site = intent.getSerializableExtra(WordPress.SITE) as SiteModel - viewModel = ViewModelProviders.of(this, viewModelFactory).get(GiphyPickerViewModel::class.java) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(GifPickerViewModel::class.java) viewModel.setup(site) // We are intentionally reusing this layout since the UI is very similar. @@ -152,7 +152,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { } /** - * Configure the selection bar and its labels when the [GiphyPickerViewModel] selected items change + * Configure the selection bar and its labels when the [GifPickerViewModel] selected items change */ private fun initializeSelectionBar() { viewModel.selectionBarIsVisible.observe(this, Observer { @@ -277,7 +277,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { * * @param mediaViewModels A non-empty list */ - private fun showPreview(mediaViewModels: List) { + private fun showPreview(mediaViewModels: List) { check(mediaViewModels.isNotEmpty()) val uris = mediaViewModels.map { it.previewImageUri.toString() } @@ -310,7 +310,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { } /** - * Set up enabling/disabling of controls depending on the current [GiphyPickerViewModel.State]: + * Set up enabling/disabling of controls depending on the current [GifPickerViewModel.State]: * * - [State.IDLE]: All normal functions are allowed * - [State.DOWNLOADING] or [State.FINISHED]: "Add", "Preview", searching, and selecting are disabled diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt index 0087e18a2731..6a23479c7f5b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt @@ -5,7 +5,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil.ItemCallback import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.util.image.ImageManager -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel +import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** * An [RecyclerView] adapter to be used with the [PagedList] created by [GiphyPickerViewModel] @@ -13,9 +13,9 @@ import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel class GiphyPickerPagedListAdapter( private val imageManager: ImageManager, private val thumbnailViewDimensions: ThumbnailViewDimensions, - private val onMediaViewClickListener: (GiphyMediaViewModel?) -> Unit, - private val onMediaViewLongClickListener: (GiphyMediaViewModel) -> Unit -) : PagedListAdapter(DIFF_CALLBACK) { + private val onMediaViewClickListener: (GifMediaViewModel?) -> Unit, + private val onMediaViewLongClickListener: (GifMediaViewModel) -> Unit +) : PagedListAdapter(DIFF_CALLBACK) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GiphyMediaViewHolder { return GiphyMediaViewHolder.create( imageManager = imageManager, @@ -31,18 +31,18 @@ class GiphyPickerPagedListAdapter( } companion object { - private val DIFF_CALLBACK = object : ItemCallback() { - override fun areItemsTheSame(oldItem: GiphyMediaViewModel, newItem: GiphyMediaViewModel): Boolean { + private val DIFF_CALLBACK = object : ItemCallback() { + override fun areItemsTheSame(oldItem: GifMediaViewModel, newItem: GifMediaViewModel): Boolean { return oldItem.id == newItem.id } /** - * Always assume that two similar [GiphyMediaViewModel] objects always have the same content. + * Always assume that two similar [GifMediaViewModel] objects always have the same content. * * It is probably extremely unlikely that GIFs from Giphy will change while the user is performing * a search. */ - override fun areContentsTheSame(oldItem: GiphyMediaViewModel, newItem: GiphyMediaViewModel): Boolean { + override fun areContentsTheSame(oldItem: GifMediaViewModel, newItem: GifMediaViewModel): Boolean { return true } } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt similarity index 97% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt index bc33fb90d74d..475e7b23229b 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/CoroutineScopedViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/CoroutineScopedViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.ViewModel import kotlinx.coroutines.CoroutineScope diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt similarity index 83% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt index 38c617edfe2c..1d02c055c486 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaFetcher.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import android.content.Context import android.webkit.MimeTypeMap @@ -18,13 +18,13 @@ import org.wordpress.android.util.WPMediaUtils import javax.inject.Inject /** - * Downloads [GiphyMediaViewModel.largeImageUri] objects and saves them as [MediaModel] + * Downloads [GifMediaViewModel.largeImageUri] objects and saves them as [MediaModel] * * The download happens concurrently and primarily uses [Dispatchers.IO]. This means that we are limited by the number * of threads backed by that `CoroutineDispatcher`. In the future, we should probably add a limit to the number of * GIFs that users can select to reduce the likelihood of OOM exceptions. */ -class GiphyMediaFetcher @Inject constructor( +class GifMediaFetcher @Inject constructor( private val context: Context, private val mediaStore: MediaStore, private val dispatcher: Dispatcher @@ -38,22 +38,22 @@ class GiphyMediaFetcher @Inject constructor( */ @Throws suspend fun fetchAndSave( - giphyMediaViewModels: List, + gifMediaViewModels: List, site: SiteModel ): List = coroutineScope { // Execute [fetchAndSave] for all giphyMediaViewModels first so that they are queued and executed in the // background. We'll call `await()` once they are queued. - return@coroutineScope giphyMediaViewModels.map { - fetchAndSave(scope = this, giphyMediaViewModel = it, site = site) + return@coroutineScope gifMediaViewModels.map { + fetchAndSave(scope = this, gifMediaViewModel = it, site = site) }.map { it.await() } } private fun fetchAndSave( scope: CoroutineScope, - giphyMediaViewModel: GiphyMediaViewModel, + gifMediaViewModel: GifMediaViewModel, site: SiteModel ): Deferred = scope.async(Dispatchers.IO) { - val uri = giphyMediaViewModel.largeImageUri + val uri = gifMediaViewModel.largeImageUri // No need to log the Exception here. The underlying method that is used, [MediaUtils.downloadExternalMedia] // already logs any errors. val downloadedUri = WPMediaUtils.fetchMedia(context, uri) ?: throw Exception("Failed to download the image.") @@ -65,7 +65,7 @@ class GiphyMediaFetcher @Inject constructor( val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension) val mediaModel = FluxCUtils.mediaModelFromLocalUri(context, downloadedUri, mimeType, mediaStore, site.id) - mediaModel.title = giphyMediaViewModel.title + mediaModel.title = gifMediaViewModel.title dispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(mediaModel)) return@async mediaModel diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt index 24a756e717a1..e660e309879f 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import android.net.Uri import androidx.lifecycle.LiveData @@ -15,7 +15,7 @@ import androidx.lifecycle.LiveData * See the [Giphy API docs](https://developers.giphy.com/docs/) for more information on what a [Media] object contains. * Search for "The GIF Object" section. */ -interface GiphyMediaViewModel { +interface GifMediaViewModel { /** * The id from Giphy's [Media] */ diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt similarity index 85% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt index d07195dab666..ba56a1a8d936 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt @@ -1,33 +1,33 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PositionalDataSource -import org.wordpress.android.viewmodel.giphy.provider.GifProvider +import org.wordpress.android.viewmodel.gif.provider.GifProvider /** - * The PagedListDataSource that is created and managed by [GiphyPickerDataSourceFactory] + * The PagedListDataSource that is created and managed by [GifPickerDataSourceFactory] * * This performs paged API requests using the [apiClient]. A new instance of this class must be created if the * [searchQuery] is changed by the user. */ -class GiphyPickerDataSource( +class GifPickerDataSource( private val gifProvider: GifProvider, private val searchQuery: String -) : PositionalDataSource() { +) : PositionalDataSource() { /** * The data structure used for storing failed [loadRange] calls so they can be retried later. */ private data class RangeLoadArguments( val params: LoadRangeParams, - val callback: LoadRangeCallback + val callback: LoadRangeCallback ) /** * The error received when [loadInitial] fails. * * Unlike [rangeLoadErrorEvent], this is not a [LiveData] because the consumer of this method - * [GiphyPickerViewModel] simply uses it to check for null values and reacts to a different event. + * [GifPickerViewModel] simply uses it to check for null values and reacts to a different event. * * This is cleared when [loadInitial] is started. */ @@ -53,15 +53,15 @@ class GiphyPickerDataSource( /** * Always the load the first page (startingPosition = 0) from the Giphy API * - * The [GiphyPickerDataSourceFactory] recreates [GiphyPickerDataSource] instances whenever a new [searchQuery] + * The [GifPickerDataSourceFactory] recreates [GifPickerDataSource] instances whenever a new [searchQuery] * is queued. The [LoadInitialParams.requestedStartPosition] may have a value that is only valid for the * previous [searchQuery]. If that value is greater than the total search results of the new [searchQuery], * a crash will happen. * - * Using `0` as the `startPosition` forces the [GiphyPickerDataSource] consumer to reset the list (UI) from the + * Using `0` as the `startPosition` forces the [GifPickerDataSource] consumer to reset the list (UI) from the * top. */ - override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { + override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) { val startPosition = 0 initialLoadError = null @@ -81,7 +81,7 @@ class GiphyPickerDataSource( */ private fun requestInitialSearch( params: LoadInitialParams, - callback: LoadInitialCallback + callback: LoadInitialCallback ) { val startPosition = 0 gifProvider.search(searchQuery, startPosition, params.requestedLoadSize, @@ -107,7 +107,7 @@ class GiphyPickerDataSource( * Errors are dispatched to [rangeLoadErrorEvent]. If successful, previously failed calls of this method are * automatically retried using [retryAllFailedRangeLoads]. */ - override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { + override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback) { gifProvider.search(searchQuery, params.startPosition, params.loadSize, onSuccess = { gifs, _ -> callback.onResult(gifs) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt similarity index 50% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt index 11cd422259cc..07104445195f 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt @@ -1,27 +1,27 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.paging.DataSource import androidx.paging.DataSource.Factory -import org.wordpress.android.viewmodel.giphy.provider.GifProvider +import org.wordpress.android.viewmodel.gif.provider.GifProvider import javax.inject.Inject /** - * Creates instances of [GiphyPickerDataSource] + * Creates instances of [GifPickerDataSource] * * Whenever the [searchQuery] is changed: * - * 1. The last [GiphyPickerDataSource] is invalidated - * 2. The [LivePagedListBuilder] will create a new [GiphyPickerDataSource] by calling [create] - * 3. The new [GiphyPickerDataSource] will start another paged API request + * 1. The last [GifPickerDataSource] is invalidated + * 2. The [LivePagedListBuilder] will create a new [GifPickerDataSource] by calling [create] + * 3. The new [GifPickerDataSource] will start another paged API request */ -class GiphyPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { +class GifPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { /** * The active search query. * - * When changed, the current [GiphyPickerDataSource] will be invalidated. A new API search will be performed. + * When changed, the current [GifPickerDataSource] will be invalidated. A new API search will be performed. */ var searchQuery: String = "" set(value) { @@ -34,26 +34,26 @@ class GiphyPickerDataSourceFactory @Inject constructor(private val gifProvider: * * We retain this so we can invalidate it later when [searchQuery] is changed. */ - private val dataSource = MutableLiveData() + private val dataSource = MutableLiveData() /** - * The [GiphyPickerDataSource.initialLoadError] of the current [dataSource] + * The [GifPickerDataSource.initialLoadError] of the current [dataSource] */ val initialLoadError: Throwable? get() = dataSource.value?.initialLoadError /** - * The [GiphyPickerDataSource.rangeLoadErrorEvent] of the current [dataSource] + * The [GifPickerDataSource.rangeLoadErrorEvent] of the current [dataSource] */ val rangeLoadErrorEvent: LiveData = Transformations.switchMap(dataSource) { it.rangeLoadErrorEvent } /** * Retries all previously failed page loads. * - * @see [GiphyPickerDataSource.retryAllFailedRangeLoads] + * @see [GifPickerDataSource.retryAllFailedRangeLoads] */ fun retryAllFailedRangeLoads() = dataSource.value?.retryAllFailedRangeLoads() - override fun create(): DataSource { - val dataSource = GiphyPickerDataSource(gifProvider, searchQuery) + override fun create(): DataSource { + val dataSource = GifPickerDataSource(gifProvider, searchQuery) this.dataSource.postValue(dataSource) return dataSource } diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt similarity index 88% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt index 7083d5afee68..84d4c9e6f9b2 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -28,20 +28,20 @@ import javax.inject.Inject * Holds the data for [org.wordpress.android.ui.giphy.GiphyPickerActivity] * * This creates a [PagedList] which can be bound to by a [PagedListAdapter] and also manages the logic of the - * selected media. That includes but not limited to keeping the [GiphyMediaViewModel.selectionNumber] continuous. + * selected media. That includes but not limited to keeping the [GifMediaViewModel.selectionNumber] continuous. * * Calling [setup] is required before using this ViewModel. */ -class GiphyPickerViewModel @Inject constructor( +class GifPickerViewModel @Inject constructor( private val networkUtils: NetworkUtilsWrapper, private val analyticsTrackerWrapper: AnalyticsTrackerWrapper, - private val mediaFetcher: GiphyMediaFetcher, + private val mediaFetcher: GifMediaFetcher, /** - * The [GiphyPickerDataSourceFactory] to use + * The [GifPickerDataSourceFactory] to use * * This is only available in the constructor to allow mocking in tests. */ - private val dataSourceFactory: GiphyPickerDataSourceFactory + private val dataSourceFactory: GifPickerDataSourceFactory ) : CoroutineScopedViewModel() { /** * A result of [downloadSelected] observed using the [downloadResult] LiveData @@ -97,7 +97,7 @@ class GiphyPickerViewModel @Inject constructor( /** * Errors that happened during page loads. * - * @see [GiphyPickerDataSource.rangeLoadErrorEvent] + * @see [GifPickerDataSource.rangeLoadErrorEvent] */ val rangeLoadErrorEvent: LiveData = dataSourceFactory.rangeLoadErrorEvent @@ -115,13 +115,13 @@ class GiphyPickerViewModel @Inject constructor( */ val downloadResult: LiveData = _downloadResult - private val _selectedMediaViewModelList = MutableLiveData>() + private val _selectedMediaViewModelList = MutableLiveData>() /** - * A [Map] of the [GiphyMediaViewModel]s that were selected by the user + * A [Map] of the [GifMediaViewModel]s that were selected by the user * - * This map is sorted in the order that the user picked them. The [String] is the value of [GiphyMediaViewModel.id]. + * This map is sorted in the order that the user picked them. The [String] is the value of [GifMediaViewModel.id]. */ - val selectedMediaViewModelList: LiveData> = _selectedMediaViewModelList + val selectedMediaViewModelList: LiveData> = _selectedMediaViewModelList /** * Returns `true` if the selection bar (UI) should be shown @@ -142,7 +142,7 @@ class GiphyPickerViewModel @Inject constructor( /** * The [PagedList] that should be displayed in the RecyclerView */ - val mediaViewModelPagedList: LiveData> by lazy { + val mediaViewModelPagedList: LiveData> by lazy { val pagedListConfig = PagedList.Config.Builder() .setEnablePlaceholders(false) .setInitialLoadSizeHint(DEFAULT_INITIAL_LOAD_SIZE_HINT) @@ -157,7 +157,7 @@ class GiphyPickerViewModel @Inject constructor( /** * Update the [emptyDisplayMode] depending on the number of API search results or whether there was an error. */ - private val pagedListBoundaryCallback = object : BoundaryCallback() { + private val pagedListBoundaryCallback = object : BoundaryCallback() { override fun onZeroItemsLoaded() { _isPerformingInitialLoad.postValue(false) @@ -170,7 +170,7 @@ class GiphyPickerViewModel @Inject constructor( super.onZeroItemsLoaded() } - override fun onItemAtFrontLoaded(itemAtFront: GiphyMediaViewModel) { + override fun onItemAtFrontLoaded(itemAtFront: GifMediaViewModel) { _isPerformingInitialLoad.postValue(false) _emptyDisplayMode.postValue(EmptyDisplayMode.HIDDEN) super.onItemAtFrontLoaded(itemAtFront) @@ -208,7 +208,7 @@ class GiphyPickerViewModel @Inject constructor( * when, presumably, the user has stopped typing. * * This also clears the [selectedMediaViewModelList]. This makes sense because the user will not be seeing the - * currently selected [GiphyMediaViewModel] if the new search query results are different. + * currently selected [GifMediaViewModel] if the new search query results are different. * * Searching is disabled if downloading or the [query] is the same as the last one. * @@ -240,7 +240,7 @@ class GiphyPickerViewModel @Inject constructor( } /** - * Downloads all the selected [GiphyMediaViewModel] + * Downloads all the selected [GifMediaViewModel] * * When the process is finished, the results will be posted to [downloadResult]. * @@ -285,17 +285,17 @@ class GiphyPickerViewModel @Inject constructor( } /** - * Toggles a [GiphyMediaViewModel]'s `isSelected` property between true and false + * Toggles a [GifMediaViewModel]'s `isSelected` property between true and false * - * This also updates the [GiphyMediaViewModel.selectionNumber] of all the objects in [selectedMediaViewModelList]. + * This also updates the [GifMediaViewModel.selectionNumber] of all the objects in [selectedMediaViewModelList]. */ - fun toggleSelected(mediaViewModel: GiphyMediaViewModel) { + fun toggleSelected(mediaViewModel: GifMediaViewModel) { if (_state.value != State.IDLE) { return } - assert(mediaViewModel is MutableGiphyMediaViewModel) - mediaViewModel as MutableGiphyMediaViewModel + assert(mediaViewModel is MutableGifMediaViewModel) + mediaViewModel as MutableGifMediaViewModel val isSelected = !(mediaViewModel.isSelected.value ?: false) @@ -317,14 +317,14 @@ class GiphyPickerViewModel @Inject constructor( } /** - * Update the [GiphyMediaViewModel.selectionNumber] values so that they are continuous + * Update the [GifMediaViewModel.selectionNumber] values so that they are continuous * - * For example, if the selection numbers are [1, 2, 3, 4, 5] and the 2nd [GiphyMediaViewModel] was removed, we + * For example, if the selection numbers are [1, 2, 3, 4, 5] and the 2nd [GifMediaViewModel] was removed, we * want the selection numbers to be updated to [1, 2, 3, 4] instead of leaving it as [1, 3, 4, 5]. */ - private fun rebuildSelectionNumbers(mediaList: LinkedHashMap) { + private fun rebuildSelectionNumbers(mediaList: LinkedHashMap) { mediaList.values.forEachIndexed { index, mediaViewModel -> - (mediaViewModel as MutableGiphyMediaViewModel).postSelectionNumber(index + 1) + (mediaViewModel as MutableGifMediaViewModel).postSelectionNumber(index + 1) } } @@ -350,7 +350,7 @@ class GiphyPickerViewModel @Inject constructor( /** * Retries all previously failed page loads. * - * @see [GiphyPickerDataSource.retryAllFailedRangeLoads] + * @see [GifPickerDataSource.retryAllFailedRangeLoads] */ fun retryAllFailedRangeLoads() = dataSourceFactory.retryAllFailedRangeLoads() diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt similarity index 78% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt index ec683efd6f8d..ef92c50bc337 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/MutableGiphyMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import android.net.Uri import androidx.lifecycle.LiveData @@ -6,21 +6,21 @@ import androidx.lifecycle.MutableLiveData import org.wordpress.android.viewmodel.SingleLiveEvent /** - * A mutable implementation of [GiphyMediaViewModel] + * A mutable implementation of [GifMediaViewModel] * - * This is meant to be accessible by [GiphyPickerViewModel] and [GiphyPickerDataSource] only. This is designed this - * way so that [GiphyPickerViewModel] encapsulates all the logic of managing selected items as well as keeping their + * This is meant to be accessible by [GifPickerViewModel] and [GifPickerDataSource] only. This is designed this + * way so that [GifPickerViewModel] encapsulates all the logic of managing selected items as well as keeping their * selection numbers continuous. * * The [GiphyPickerViewHolder] should never have access to the mutating methods of this class. */ -data class MutableGiphyMediaViewModel( +data class MutableGifMediaViewModel( override val id: String, override val thumbnailUri: Uri, override val previewImageUri: Uri, override val largeImageUri: Uri, override val title: String -) : GiphyMediaViewModel { +) : GifMediaViewModel { /** * Using [SingleLiveEvent] will prevent calls like this from running immediately when a ViewHolder is bound: * diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt similarity index 80% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt index 1fcb7fba3253..0aee13220740 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/GifProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/GifProvider.kt @@ -1,6 +1,6 @@ -package org.wordpress.android.viewmodel.giphy.provider +package org.wordpress.android.viewmodel.gif.provider -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel +import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** * Interface to interact with a GIF provider API avoiding coupling with the concrete implementation @@ -13,7 +13,7 @@ interface GifProvider { * @param position to request results starting from a given position for that query * @param loadSize to request a result list limited to a specific amount * @param onSuccess will be called if the Provider had success finding GIFs - * and will deliver a [List] of [GiphyMediaViewModel] with all matching GIFs + * and will deliver a [List] of [GifMediaViewModel] with all matching GIFs * and a [Int] describing the next position for pagination * @param onFailure will be called if the Provider didn't succeed with the task of bringing GIFs, * the delivered String will describe the error to be presented to the user @@ -22,7 +22,7 @@ interface GifProvider { query: String, position: Int, loadSize: Int? = null, - onSuccess: (List, Int?) -> Unit, + onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt similarity index 88% rename from WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt rename to WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index 5cb7386d9b23..e4edd55e7e17 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/giphy/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy.provider +package org.wordpress.android.viewmodel.gif.provider import android.content.Context import android.net.Uri @@ -10,9 +10,9 @@ import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.impl.GifsResponse import org.wordpress.android.R.string -import org.wordpress.android.viewmodel.giphy.GiphyMediaViewModel -import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel -import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException +import org.wordpress.android.viewmodel.gif.GifMediaViewModel +import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel +import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -31,7 +31,7 @@ internal class TenorProvider constructor( * Implementation of the [GifProvider] search method, it will call the Tenor client search * right away with the provided parameters. * - * If the search request succeeds an [List] of [MutableGiphyMediaViewModel] will be passed with the next position + * If the search request succeeds an [List] of [MutableGifMediaViewModel] will be passed with the next position * for pagination. If there's no next position provided, it will be passed as null. * * If the search request fails an [GifRequestFailedException] will be passed with the API @@ -42,7 +42,7 @@ internal class TenorProvider constructor( query: String, position: Int, loadSize: Int?, - onSuccess: (List, Int?) -> Unit, + onSuccess: (List, Int?) -> Unit, onFailure: (Throwable) -> Unit ) { tenorClient.enqueueSearchRequest( @@ -110,10 +110,10 @@ internal class TenorProvider constructor( /** * Every GIF returned by the Tenor will be available as [Result], to better interface - * with our app, it will be converted to [MutableGiphyMediaViewModel] to avoid any external + * with our app, it will be converted to [MutableGifMediaViewModel] to avoid any external * coupling with the Tenor API */ - private fun Result.toMutableGifMediaViewModel() = MutableGiphyMediaViewModel( + private fun Result.toMutableGifMediaViewModel() = MutableGifMediaViewModel( id, Uri.parse(urlFromCollectionFormat(MediaCollectionFormat.GIF_NANO)), Uri.parse(urlFromCollectionFormat(MediaCollectionFormat.GIF_TINY)), diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt similarity index 77% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt index 476cf13732d1..65f8f27867e5 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.paging.PositionalDataSource.LoadInitialCallback import androidx.paging.PositionalDataSource.LoadInitialParams @@ -16,23 +16,23 @@ import org.junit.Before import org.junit.Test import org.mockito.Mock import org.mockito.MockitoAnnotations -import org.wordpress.android.viewmodel.giphy.GiphyPickerDataSourceFixtures.expectedGifMediaViewModelCollection -import org.wordpress.android.viewmodel.giphy.provider.GifProvider -import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException +import org.wordpress.android.viewmodel.gif.GiphyPickerDataSourceFixtures.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.gif.provider.GifProvider +import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException -class GiphyPickerDataSourceTest { +class GifPickerDataSourceTest { @Mock lateinit var gifProvider: GifProvider - lateinit var onSuccessCaptor: KArgumentCaptor<(List, Int?) -> Unit> + lateinit var onSuccessCaptor: KArgumentCaptor<(List, Int?) -> Unit> lateinit var onFailureCaptor: KArgumentCaptor<(Throwable) -> Unit> - private lateinit var pickerDataSourceUnderTest: GiphyPickerDataSource + private lateinit var pickerDataSourceUnderTest: GifPickerDataSource @Before fun setUp() { MockitoAnnotations.initMocks(this) - pickerDataSourceUnderTest = GiphyPickerDataSource(gifProvider, "test") + pickerDataSourceUnderTest = GifPickerDataSource(gifProvider, "test") onSuccessCaptor = argumentCaptor() onFailureCaptor = argumentCaptor() } @@ -42,15 +42,15 @@ class GiphyPickerDataSourceTest { var onResultWasCalled = false val params = LoadInitialParams(0, 20, 5, false) - val dataSourceCallback = object : LoadInitialCallback() { - override fun onResult(data: MutableList, position: Int, totalCount: Int) { + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { onResultWasCalled = true assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) assertThat(position).isEqualTo(0) assertThat(totalCount).isEqualTo(4) } - override fun onResult(data: MutableList, position: Int) { + override fun onResult(data: MutableList, position: Int) { fail("Wrong onResult called") } } @@ -67,15 +67,15 @@ class GiphyPickerDataSourceTest { var onResultWasCalled = false val params = LoadInitialParams(0, 20, 5, false) - val dataSourceCallback = object : LoadInitialCallback() { - override fun onResult(data: MutableList, position: Int, totalCount: Int) { + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { onResultWasCalled = true assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) assertThat(position).isEqualTo(0) assertThat(totalCount).isEqualTo(4) } - override fun onResult(data: MutableList, position: Int) { + override fun onResult(data: MutableList, position: Int) { fail("Wrong onResult called") } } @@ -92,15 +92,15 @@ class GiphyPickerDataSourceTest { var onResultWasCalled = false val params = LoadInitialParams(0, 20, 5, false) - val dataSourceCallback = object : LoadInitialCallback() { - override fun onResult(data: MutableList, position: Int, totalCount: Int) { + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { onResultWasCalled = true assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) assertThat(position).isEqualTo(0) assertThat(totalCount).isEqualTo(4) } - override fun onResult(data: MutableList, position: Int) { + override fun onResult(data: MutableList, position: Int) { fail("Wrong onResult called") } } @@ -115,18 +115,18 @@ class GiphyPickerDataSourceTest { @Test fun `loadInitial should call onResult with emptyList when search query is blank`() { var onResultWasCalled = false - pickerDataSourceUnderTest = GiphyPickerDataSource(gifProvider, "") + pickerDataSourceUnderTest = GifPickerDataSource(gifProvider, "") val params = LoadInitialParams(0, 20, 5, false) - val dataSourceCallback = object : LoadInitialCallback() { - override fun onResult(data: MutableList, position: Int, totalCount: Int) { + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { onResultWasCalled = true assertThat(data).isEmpty() assertThat(position).isEqualTo(0) assertThat(totalCount).isEqualTo(0) } - override fun onResult(data: MutableList, position: Int) { + override fun onResult(data: MutableList, position: Int) { fail("Wrong onResult called") } } @@ -142,15 +142,15 @@ class GiphyPickerDataSourceTest { val expectedThrowable = GifRequestFailedException("Test throwable") val params = LoadInitialParams(0, 20, 5, false) - val dataSourceCallback = object : LoadInitialCallback() { - override fun onResult(data: MutableList, position: Int, totalCount: Int) { + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { onResultWasCalled = true assertThat(data).isEmpty() assertThat(position).isEqualTo(0) assertThat(totalCount).isEqualTo(0) } - override fun onResult(data: MutableList, position: Int) { + override fun onResult(data: MutableList, position: Int) { fail("Wrong onResult called") } } @@ -169,12 +169,12 @@ class GiphyPickerDataSourceTest { val expectedThrowable = GifRequestFailedException("Test throwable") val params = LoadInitialParams(0, 20, 5, false) - val dataSourceCallback = object : LoadInitialCallback() { - override fun onResult(data: MutableList, position: Int, totalCount: Int) { + val dataSourceCallback = object : LoadInitialCallback() { + override fun onResult(data: MutableList, position: Int, totalCount: Int) { onResultWasCalled = true } - override fun onResult(data: MutableList, position: Int) { + override fun onResult(data: MutableList, position: Int) { fail("Wrong onResult called") } } @@ -195,8 +195,8 @@ class GiphyPickerDataSourceTest { var onResultWasCalled = false val params = LoadRangeParams(0, 20) - val dataSourceCallback = object: LoadRangeCallback() { - override fun onResult(data: MutableList) { + val dataSourceCallback = object: LoadRangeCallback() { + override fun onResult(data: MutableList) { onResultWasCalled = true assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) } @@ -214,8 +214,8 @@ class GiphyPickerDataSourceTest { val spiedDataSource = spy(pickerDataSourceUnderTest) val params = LoadRangeParams(0, 20) - val dataSourceCallback = object: LoadRangeCallback() { - override fun onResult(data: MutableList) {} + val dataSourceCallback = object: LoadRangeCallback() { + override fun onResult(data: MutableList) {} } spiedDataSource.loadRange(params, dataSourceCallback) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt similarity index 93% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt index c04b9a051852..22ab766e93c8 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.paging.PositionalDataSource.LoadInitialCallback @@ -20,27 +20,27 @@ import org.mockito.junit.MockitoJUnitRunner import org.wordpress.android.fluxc.model.MediaModel import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.EmptyDisplayMode -import org.wordpress.android.viewmodel.giphy.GiphyPickerViewModel.State +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.EmptyDisplayMode +import org.wordpress.android.viewmodel.gif.GifPickerViewModel.State import java.util.Random import java.util.UUID @RunWith(MockitoJUnitRunner::class) -class GiphyPickerViewModelTest { +class GifPickerViewModelTest { @get:Rule val rule = InstantTaskExecutorRule() - private lateinit var viewModel: GiphyPickerViewModel + private lateinit var viewModel: GifPickerViewModel - private val dataSourceFactory = mock() - private val mediaFetcher = mock() + private val dataSourceFactory = mock() + private val mediaFetcher = mock() private val analyticsTracker = mock() @Mock private lateinit var networkUtils: NetworkUtilsWrapper @Before fun setUp() { - viewModel = GiphyPickerViewModel( + viewModel = GifPickerViewModel( dataSourceFactory = dataSourceFactory, networkUtils = networkUtils, mediaFetcher = mediaFetcher, @@ -150,12 +150,12 @@ class GiphyPickerViewModelTest { @Test fun `when search results are empty, the empty view should be visible and says there are no results`() { // Arrange - val dataSource = mock() + val dataSource = mock() whenever(dataSourceFactory.create()).thenReturn(dataSource) whenever(dataSourceFactory.searchQuery).thenReturn("dummy") - val callbackCaptor = argumentCaptor>() + val callbackCaptor = argumentCaptor>() doNothing().whenever(dataSource).loadInitial(any(), callbackCaptor.capture()) // Observe mediaViewModelPagedList so the DataSourceFactory will be activated and perform API requests @@ -177,12 +177,12 @@ class GiphyPickerViewModelTest { @Test fun `when the initial load fails, the empty view should show a network error`() { // Arrange - val dataSource = mock() + val dataSource = mock() whenever(dataSourceFactory.create()).thenReturn(dataSource) whenever(dataSourceFactory.initialLoadError).thenReturn(mock()) - val callbackCaptor = argumentCaptor>() + val callbackCaptor = argumentCaptor>() doNothing().whenever(dataSource).loadInitial(any(), callbackCaptor.capture()) // Observe mediaViewModelPagedList so the DataSourceFactory will be activated and perform API requests @@ -316,7 +316,7 @@ class GiphyPickerViewModelTest { id = Random().nextInt() } - private fun createGiphyMediaViewModel() = MutableGiphyMediaViewModel( + private fun createGiphyMediaViewModel() = MutableGifMediaViewModel( id = UUID.randomUUID().toString(), thumbnailUri = mock(), largeImageUri = mock(), diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFixtures.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GiphyPickerDataSourceFixtures.kt similarity index 55% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFixtures.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GiphyPickerDataSourceFixtures.kt index c9e894e839e0..c147cc45a519 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/GiphyPickerDataSourceFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GiphyPickerDataSourceFixtures.kt @@ -1,9 +1,9 @@ -package org.wordpress.android.viewmodel.giphy +package org.wordpress.android.viewmodel.gif import com.nhaarman.mockitokotlin2.mock object GiphyPickerDataSourceFixtures { - internal val expectedGifMediaViewModelCollection: List = listOf( + internal val expectedGifMediaViewModelCollection: List = listOf( mock(), mock(), mock(), diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt similarity index 95% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt index c598611e4a33..e5ce3747249d 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy.provider +package org.wordpress.android.viewmodel.gif.provider import android.content.Context import androidx.test.core.app.ApplicationProvider @@ -25,9 +25,9 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.wordpress.android.BuildConfig import org.wordpress.android.TestApplication -import org.wordpress.android.viewmodel.giphy.provider.GifProvider.GifRequestFailedException -import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.expectedGifMediaViewModelCollection -import org.wordpress.android.viewmodel.giphy.provider.TenorProviderTestFixtures.mockedTenorResult +import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException +import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestFixtures.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.gif.provider.TenorProviderTestFixtures.mockedTenorResult import retrofit2.Call import retrofit2.Callback import retrofit2.Response diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestFixtures.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestFixtures.kt similarity index 93% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestFixtures.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestFixtures.kt index 855cf6ae85fb..7a3ef1cd6ce5 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/giphy/provider/TenorProviderTestFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTestFixtures.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.viewmodel.giphy.provider +package org.wordpress.android.viewmodel.gif.provider import android.net.Uri import com.nhaarman.mockitokotlin2.mock @@ -7,7 +7,7 @@ import com.tenor.android.core.constant.MediaCollectionFormat import com.tenor.android.core.model.impl.Media import com.tenor.android.core.model.impl.MediaCollection import com.tenor.android.core.model.impl.Result -import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel +import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel object TenorProviderTestFixtures { internal val mockedTenorResult @@ -48,7 +48,7 @@ object TenorProviderTestFixtures { mock().apply { whenever(this.url).thenReturn(mockContent) } private fun createExpectedGifMediaViewModel(expectedContent: String) = - MutableGiphyMediaViewModel( + MutableGifMediaViewModel( expectedContent, Uri.parse("$expectedContent gif_nano"), Uri.parse("$expectedContent gif_tiny"), From 3a41fcb1a466bd63bfe19c2b347d01cb1ff122d4 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sun, 29 Mar 2020 17:28:28 -0300 Subject: [PATCH 43/58] Renamed all giphy name references inside ui package to only gif --- WordPress/src/main/AndroidManifest.xml | 2 +- .../android/modules/AppComponent.java | 4 ++-- .../android/ui/ActivityLauncher.java | 4 ++-- .../GifMediaViewHolder.kt} | 14 ++++++------- .../GifPickerActivity.kt} | 20 +++++++++---------- .../GifPickerPagedListAdapter.kt} | 14 ++++++------- .../LifecycleOwnerViewHolder.kt | 2 +- .../ui/media/MediaBrowserActivity.java | 6 +++--- .../android/ui/posts/EditPostActivity.java | 6 +++--- .../viewmodel/gif/GifPickerViewModel.kt | 2 +- 10 files changed, 37 insertions(+), 37 deletions(-) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy/GiphyMediaViewHolder.kt => gif/GifMediaViewHolder.kt} (94%) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy/GiphyPickerActivity.kt => gif/GifPickerActivity.kt} (95%) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy/GiphyPickerPagedListAdapter.kt => gif/GifPickerPagedListAdapter.kt} (81%) rename WordPress/src/main/java/org/wordpress/android/ui/{giphy => gif}/LifecycleOwnerViewHolder.kt (99%) diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 3855fffeea59..b093bdd0a95f 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -529,7 +529,7 @@ android:label="" android:theme="@style/WordPress.NoActionBar" /> diff --git a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java index a9edf87b9af5..d29752d0dedf 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java @@ -40,7 +40,7 @@ import org.wordpress.android.ui.domains.DomainRegistrationActivity; import org.wordpress.android.ui.domains.DomainRegistrationDetailsFragment; import org.wordpress.android.ui.domains.DomainSuggestionsFragment; -import org.wordpress.android.ui.giphy.GiphyPickerActivity; +import org.wordpress.android.ui.gif.GifPickerActivity; import org.wordpress.android.ui.history.HistoryAdapter; import org.wordpress.android.ui.history.HistoryDetailContainerFragment; import org.wordpress.android.ui.main.AddContentAdapter; @@ -438,7 +438,7 @@ public interface AppComponent extends AndroidInjector { void inject(JetpackRemoteInstallFragment jetpackRemoteInstallFragment); - void inject(GiphyPickerActivity object); + void inject(GifPickerActivity object); void inject(PlansListAdapter object); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java index c3c887b2e174..8f379d598ce0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java @@ -38,7 +38,7 @@ import org.wordpress.android.ui.comments.CommentsActivity; import org.wordpress.android.ui.domains.DomainRegistrationActivity; import org.wordpress.android.ui.domains.DomainRegistrationActivity.DomainRegistrationPurpose; -import org.wordpress.android.ui.giphy.GiphyPickerActivity; +import org.wordpress.android.ui.gif.GifPickerActivity; import org.wordpress.android.ui.history.HistoryDetailActivity; import org.wordpress.android.ui.history.HistoryDetailContainerFragment; import org.wordpress.android.ui.history.HistoryListItem.Revision; @@ -179,7 +179,7 @@ public static void showGifPickerForResult(Activity activity, @NonNull SiteModel properties.put("from", activity.getClass().getSimpleName()); AnalyticsTracker.track(Stat.GIF_PICKER_ACCESSED, properties); - Intent intent = new Intent(activity, GiphyPickerActivity.class); + Intent intent = new Intent(activity, GifPickerActivity.class); intent.putExtra(WordPress.SITE, site); activity.startActivityForResult(intent, requestCode); } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifMediaViewHolder.kt similarity index 94% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gif/GifMediaViewHolder.kt index 4e7544fcb28e..a4f535d2730f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifMediaViewHolder.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gif import android.view.LayoutInflater import android.view.View @@ -17,7 +17,7 @@ import org.wordpress.android.util.redirectContextClickToLongPressListener import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** - * Represents a single item in the [GiphyPickerActivity]'s grid (RecyclerView). + * Represents a single item in the [GifPickerActivity]'s grid (RecyclerView). * * This is meant to show a single animated gif. * @@ -25,7 +25,7 @@ import org.wordpress.android.viewmodel.gif.GifMediaViewModel * behavior is handled by the [GiphyPickerViewModel]. This is designed this way so that [GiphyPickerViewModel] * encapsulates all the logic of managing selected items as well as keeping their selection numbers continuous. */ -class GiphyMediaViewHolder( +class GifMediaViewHolder( /** * The [ImageManager] to use for loading an image in to the ImageView */ @@ -76,7 +76,7 @@ class GiphyMediaViewHolder( * * The [mediaViewModel] is optional because we enable placeholders in the paged list created by * [org.wordpress.android.viewmodel.gif.GifPickerViewModel]. This causes null values to be bound to - * [GiphyMediaViewHolder] instances. + * [GifMediaViewHolder] instances. */ override fun bind(item: GifMediaViewModel?) { super.bind(item) @@ -137,7 +137,7 @@ class GiphyMediaViewHolder( private const val THUMBNAIL_SCALE_SELECTED: Float = 0.8f /** - * Create the layout and a new instance of [GiphyMediaViewHolder] + * Create the layout and a new instance of [GifMediaViewHolder] */ fun create( imageManager: ImageManager, @@ -145,11 +145,11 @@ class GiphyMediaViewHolder( onLongClickListener: (GifMediaViewModel) -> Unit, parent: ViewGroup, thumbnailViewDimensions: ThumbnailViewDimensions - ): GiphyMediaViewHolder { + ): GifMediaViewHolder { // We are intentionally reusing this layout since the UI is very similar. val view = LayoutInflater.from(parent.context) .inflate(R.layout.media_picker_thumbnail, parent, false) - return GiphyMediaViewHolder( + return GifMediaViewHolder( imageManager = imageManager, onClickListener = onClickListener, onLongClickListener = onLongClickListener, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerActivity.kt similarity index 95% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerActivity.kt index 25cddfbf5a8c..be4721255be7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerActivity.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gif import android.app.Activity import android.content.Intent @@ -19,7 +19,7 @@ import org.wordpress.android.WordPress import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.ui.ActionableEmptyView -import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions +import org.wordpress.android.ui.gif.GifMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.ui.LocaleAwareActivity import org.wordpress.android.ui.media.MediaPreviewActivity import org.wordpress.android.util.AniUtils @@ -40,9 +40,9 @@ import javax.inject.Inject * * Important: Giphy is currently disabled everywhere. We are planning to replace it with a different service provider. */ -class GiphyPickerActivity : LocaleAwareActivity() { +class GifPickerActivity : LocaleAwareActivity() { /** - * Used for loading images in [GiphyMediaViewHolder] + * Used for loading images in [GifMediaViewHolder] */ @Inject lateinit var imageManager: ImageManager @Inject lateinit var viewModelFactory: ViewModelFactory @@ -53,7 +53,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { private val gridColumnCount: Int by lazy { if (DisplayUtils.isLandscape(this)) 4 else 3 } /** - * Passed to the [GiphyMediaViewHolder] which will be used as its dimensions + * Passed to the [GifMediaViewHolder] which will be used as its dimensions */ private val thumbnailViewDimensions: ThumbnailViewDimensions by lazy { val width = DisplayUtils.getDisplayPixelWidth(this) / gridColumnCount @@ -93,10 +93,10 @@ class GiphyPickerActivity : LocaleAwareActivity() { } /** - * Configure the RecyclerView to use [GiphyPickerPagedListAdapter] and display the items in a grid + * Configure the RecyclerView to use [GifPickerPagedListAdapter] and display the items in a grid */ private fun initializeRecyclerView() { - val pagedListAdapter = GiphyPickerPagedListAdapter( + val pagedListAdapter = GifPickerPagedListAdapter( imageManager = imageManager, thumbnailViewDimensions = thumbnailViewDimensions, onMediaViewClickListener = { mediaViewModel -> @@ -112,7 +112,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { ) recycler.apply { - layoutManager = GridLayoutManager(this@GiphyPickerActivity, gridColumnCount) + layoutManager = GridLayoutManager(this@GifPickerActivity, gridColumnCount) adapter = pagedListAdapter } @@ -253,7 +253,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { event ?: return@Observer ToastUtils.showToast( - this@GiphyPickerActivity, + this@GifPickerActivity, R.string.giphy_picker_endless_scroll_network_error, ToastUtils.Duration.LONG ) @@ -301,7 +301,7 @@ class GiphyPickerActivity : LocaleAwareActivity() { finish() } else if (result?.errorMessageStringResId != null) { ToastUtils.showToast( - this@GiphyPickerActivity, + this@GifPickerActivity, result.errorMessageStringResId, ToastUtils.Duration.SHORT ) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerPagedListAdapter.kt similarity index 81% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerPagedListAdapter.kt index 6a23479c7f5b..ee687df79fe2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/GiphyPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerPagedListAdapter.kt @@ -1,23 +1,23 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gif import android.view.ViewGroup import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil.ItemCallback -import org.wordpress.android.ui.giphy.GiphyMediaViewHolder.ThumbnailViewDimensions +import org.wordpress.android.ui.gif.GifMediaViewHolder.ThumbnailViewDimensions import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** * An [RecyclerView] adapter to be used with the [PagedList] created by [GiphyPickerViewModel] */ -class GiphyPickerPagedListAdapter( +class GifPickerPagedListAdapter( private val imageManager: ImageManager, private val thumbnailViewDimensions: ThumbnailViewDimensions, private val onMediaViewClickListener: (GifMediaViewModel?) -> Unit, private val onMediaViewLongClickListener: (GifMediaViewModel) -> Unit -) : PagedListAdapter(DIFF_CALLBACK) { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GiphyMediaViewHolder { - return GiphyMediaViewHolder.create( +) : PagedListAdapter(DIFF_CALLBACK) { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GifMediaViewHolder { + return GifMediaViewHolder.create( imageManager = imageManager, onClickListener = onMediaViewClickListener, onLongClickListener = onMediaViewLongClickListener, @@ -26,7 +26,7 @@ class GiphyPickerPagedListAdapter( ) } - override fun onBindViewHolder(holder: GiphyMediaViewHolder, position: Int) { + override fun onBindViewHolder(holder: GifMediaViewHolder, position: Int) { holder.bind(getItem(position)) } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/gif/LifecycleOwnerViewHolder.kt similarity index 99% rename from WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt rename to WordPress/src/main/java/org/wordpress/android/ui/gif/LifecycleOwnerViewHolder.kt index 7c207dc25c48..60b213c7a4b8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/giphy/LifecycleOwnerViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gif/LifecycleOwnerViewHolder.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.giphy +package org.wordpress.android.ui.gif import android.view.View import android.view.View.OnAttachStateChangeListener diff --git a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java index b69d4808f660..a59279aac169 100755 --- a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java @@ -63,7 +63,7 @@ import org.wordpress.android.ui.ActivityLauncher; import org.wordpress.android.ui.LocaleAwareActivity; import org.wordpress.android.ui.RequestCodes; -import org.wordpress.android.ui.giphy.GiphyPickerActivity; +import org.wordpress.android.ui.gif.GifPickerActivity; import org.wordpress.android.ui.media.MediaGridFragment.MediaFilter; import org.wordpress.android.ui.media.MediaGridFragment.MediaGridListener; import org.wordpress.android.ui.media.services.MediaDeleteService; @@ -470,8 +470,8 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { break; case RequestCodes.GIF_PICKER: if (resultCode == RESULT_OK - && data.hasExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS)) { - int[] mediaLocalIds = data.getIntArrayExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS); + && data.hasExtra(GifPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS)) { + int[] mediaLocalIds = data.getIntArrayExtra(GifPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS); ArrayList mediaModels = new ArrayList<>(); for (int localId : mediaLocalIds) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index 182fff62d662..c851d739c4cb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -101,7 +101,7 @@ import org.wordpress.android.ui.PagePostCreationSourcesDetail; import org.wordpress.android.ui.RequestCodes; import org.wordpress.android.ui.Shortcut; -import org.wordpress.android.ui.giphy.GiphyPickerActivity; +import org.wordpress.android.ui.gif.GifPickerActivity; import org.wordpress.android.ui.history.HistoryListItem.Revision; import org.wordpress.android.ui.media.MediaBrowserActivity; import org.wordpress.android.ui.media.MediaBrowserType; @@ -2264,8 +2264,8 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } break; case RequestCodes.GIF_PICKER: - if (data.hasExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS)) { - int[] localIds = data.getIntArrayExtra(GiphyPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS); + if (data.hasExtra(GifPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS)) { + int[] localIds = data.getIntArrayExtra(GifPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS); mEditorMedia.addMediaFromGiphyToPostAsync(localIds); } break; diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt index 84d4c9e6f9b2..70474d15fb48 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt @@ -25,7 +25,7 @@ import org.wordpress.android.viewmodel.SingleLiveEvent import javax.inject.Inject /** - * Holds the data for [org.wordpress.android.ui.giphy.GiphyPickerActivity] + * Holds the data for [org.wordpress.android.ui.gif.GifPickerActivity] * * This creates a [PagedList] which can be bound to by a [PagedListAdapter] and also manages the logic of the * selected media. That includes but not limited to keeping the [GifMediaViewModel.selectionNumber] continuous. From b5b0af6beb568cc053070c7426638e3e650cf1a4 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sun, 29 Mar 2020 17:53:43 -0300 Subject: [PATCH 44/58] Replaced all Giphy string references to Tenor --- WordPress/src/main/res/values-ar/strings.xml | 10 +++++----- WordPress/src/main/res/values-el/strings.xml | 2 +- WordPress/src/main/res/values-en-rAU/strings.xml | 10 +++++----- WordPress/src/main/res/values-en-rCA/strings.xml | 10 +++++----- WordPress/src/main/res/values-en-rGB/strings.xml | 10 +++++----- WordPress/src/main/res/values-es-rCL/strings.xml | 10 +++++----- WordPress/src/main/res/values-es-rVE/strings.xml | 10 +++++----- WordPress/src/main/res/values-he/strings.xml | 10 +++++----- WordPress/src/main/res/values-id/strings.xml | 10 +++++----- WordPress/src/main/res/values-it/strings.xml | 10 +++++----- WordPress/src/main/res/values-ja/strings.xml | 10 +++++----- WordPress/src/main/res/values-ko/strings.xml | 10 +++++----- WordPress/src/main/res/values-nb/strings.xml | 10 +++++----- WordPress/src/main/res/values-nl/strings.xml | 4 ++-- WordPress/src/main/res/values-pl/strings.xml | 10 +++++----- WordPress/src/main/res/values-pt-rBR/strings.xml | 10 +++++----- WordPress/src/main/res/values-ro/strings.xml | 10 +++++----- WordPress/src/main/res/values-ru/strings.xml | 10 +++++----- WordPress/src/main/res/values-sk/strings.xml | 4 ++-- WordPress/src/main/res/values-sq/strings.xml | 10 +++++----- WordPress/src/main/res/values-sv/strings.xml | 10 +++++----- WordPress/src/main/res/values-tr/strings.xml | 10 +++++----- WordPress/src/main/res/values-zh-rCN/strings.xml | 10 +++++----- WordPress/src/main/res/values-zh-rHK/strings.xml | 10 +++++----- WordPress/src/main/res/values-zh-rTW/strings.xml | 10 +++++----- WordPress/src/main/res/values/strings.xml | 12 ++++++------ 26 files changed, 121 insertions(+), 121 deletions(-) diff --git a/WordPress/src/main/res/values-ar/strings.xml b/WordPress/src/main/res/values-ar/strings.xml index 0205ca8a18e0..49e956a1510a 100644 --- a/WordPress/src/main/res/values-ar/strings.xml +++ b/WordPress/src/main/res/values-ar/strings.xml @@ -614,11 +614,11 @@ Language: ar لا توجد بيانات لهذه الفترة إزالة موقع من الوسائط يتعذر علينا فتح الإحصاءات في الوقت الحالي. يرجى المحاولة مجددًا في وقت لاحق - مدعون من GIPHY - فشل تحميل بعض الوسائط بسبب وجود خطأ في الشبكة. - لا توجد وسائط مطابقة لبحثك - ابحث للعثور على صور بتنسيق GIF لإضافتها إلى مكتبة الوسائط الخاصة بك! - البحث في Giphy + مدعون من TENOR + فشل تحميل بعض الوسائط بسبب وجود خطأ في الشبكة. + لا توجد وسائط مطابقة لبحثك + ابحث للعثور على صور بتنسيق GIF لإضافتها إلى مكتبة الوسائط الخاصة بك! + البحث في Tenor مشاهدات الكاتب الكُتّاب diff --git a/WordPress/src/main/res/values-el/strings.xml b/WordPress/src/main/res/values-el/strings.xml index fb46d670dbf4..3bb620352217 100644 --- a/WordPress/src/main/res/values-el/strings.xml +++ b/WordPress/src/main/res/values-el/strings.xml @@ -55,7 +55,7 @@ Language: el_GR %1$d από %2$d Δημιουργία ιστότοπου Αναίρεση - Αναζήτηση στο Giphy + Αναζήτηση στο Tenor Προβολές Συγγραφέας Συγγραφείς diff --git a/WordPress/src/main/res/values-en-rAU/strings.xml b/WordPress/src/main/res/values-en-rAU/strings.xml index 889aeda5aa51..dc0d8343a656 100644 --- a/WordPress/src/main/res/values-en-rAU/strings.xml +++ b/WordPress/src/main/res/values-en-rAU/strings.xml @@ -378,11 +378,11 @@ Language: en_AU No data for this period Remove location from media We cannot open the statistics at the moment. Please try again later - Powered by GIPHY - Some media failed to load due to a network error. - No media matching your search - Search to find GIFs to add to your Media Library! - Search Giphy + Powered by TENOR + Some media failed to load due to a network error. + No media matching your search + Search to find GIFs to add to your Media Library! + Search Tenor Views Author Authors diff --git a/WordPress/src/main/res/values-en-rCA/strings.xml b/WordPress/src/main/res/values-en-rCA/strings.xml index 12b4c2d12dcd..ba6fbcfcf198 100644 --- a/WordPress/src/main/res/values-en-rCA/strings.xml +++ b/WordPress/src/main/res/values-en-rCA/strings.xml @@ -473,11 +473,11 @@ Language: en_CA No data for this period Remove location from media We cannot open the statistics at the moment. Please try again later - Powered by GIPHY - Some media failed to load due to a network error. - No media matching your search - Search to find GIFs to add to your Media Library! - Search Giphy + Powered by TENOR + Some media failed to load due to a network error. + No media matching your search + Search to find GIFs to add to your Media Library! + Search Tenor Views Author Authors diff --git a/WordPress/src/main/res/values-en-rGB/strings.xml b/WordPress/src/main/res/values-en-rGB/strings.xml index a004ce89206e..8932ce5ab0c7 100644 --- a/WordPress/src/main/res/values-en-rGB/strings.xml +++ b/WordPress/src/main/res/values-en-rGB/strings.xml @@ -614,11 +614,11 @@ Language: en_GB No data for this period Remove location from media We cannot open the statistics at the moment. Please try again later - Powered by GIPHY - Some media failed to load due to a network error. - No media matching your search - Search to find GIFs to add to your Media Library! - Search Giphy + Powered by TENOR + Some media failed to load due to a network error. + No media matching your search + Search to find GIFs to add to your Media Library! + Search Tenor Views Author Authors diff --git a/WordPress/src/main/res/values-es-rCL/strings.xml b/WordPress/src/main/res/values-es-rCL/strings.xml index b552e7dd122d..46e52aa740db 100644 --- a/WordPress/src/main/res/values-es-rCL/strings.xml +++ b/WordPress/src/main/res/values-es-rCL/strings.xml @@ -141,11 +141,11 @@ Language: es_CL No hay datos para este período Quita la ubicación de los medios No podemos abrir las estadísticas en este momento. Por favor inténtalo de nuevo más tarde - Desarrollado por GIPHY - Algunos medios no pudieron cargarse debido a un error de red. - No hay medios que coincidan con tu búsqueda - ¡Busca para encontrar GIFs para añadirlos a tu Biblioteca de Medios! - Buscar en Giphy + Desarrollado por TENOR + Algunos medios no pudieron cargarse debido a un error de red. + No hay medios que coincidan con tu búsqueda + ¡Busca para encontrar GIFs para añadirlos a tu Biblioteca de Medios! + Buscar en Tenor Vistas Autor Autores diff --git a/WordPress/src/main/res/values-es-rVE/strings.xml b/WordPress/src/main/res/values-es-rVE/strings.xml index 235e0f516aaa..5830e18a35ec 100644 --- a/WordPress/src/main/res/values-es-rVE/strings.xml +++ b/WordPress/src/main/res/values-es-rVE/strings.xml @@ -614,11 +614,11 @@ Language: es_VE No hay datos en este periodo Eliminar la ubicación de los medios No podemos abrir las estadísticas en este momento. Por favor, inténtalo de nuevo más tarde - Creado por GIPHY - Algunos medios no se cargaron debido a un error de red. - Ningún medio coincide con tu búsqueda - ¡Busca para encontrar GIFs para añadir a tu biblioteca de medios! - Buscar en Giphy + Creado por TENOR + Algunos medios no se cargaron debido a un error de red. + Ningún medio coincide con tu búsqueda + ¡Busca para encontrar GIFs para añadir a tu biblioteca de medios! + Buscar en Tenor Vistas Autor Autores diff --git a/WordPress/src/main/res/values-he/strings.xml b/WordPress/src/main/res/values-he/strings.xml index 362a3859f0cd..235a65de90ae 100644 --- a/WordPress/src/main/res/values-he/strings.xml +++ b/WordPress/src/main/res/values-he/strings.xml @@ -557,11 +557,11 @@ Language: he_IL אין נתונים לתקופה זו הסרת מיקום ממדיה אין לנו אפשרות לפתוח את הנתונים הסטטיסטיים כעת. יש לנסות שוב מאוחר יותר - מופעל באמצעות GIPHY - הטעינה של חלק מקובצי המדיה נכשלה עקב שגיאת רשת. - לא נמצאו פרטי מדיה שמתאימים לחיפוש שלך - חיפוש קובצי GIF שניתן להוסיף לספריית מדיה שלך! - חיפוש ב-Giphy + מופעל באמצעות TENOR + הטעינה של חלק מקובצי המדיה נכשלה עקב שגיאת רשת. + לא נמצאו פרטי מדיה שמתאימים לחיפוש שלך + חיפוש קובצי GIF שניתן להוסיף לספריית מדיה שלך! + חיפוש ב-Tenor צפיות מחבר מחברים diff --git a/WordPress/src/main/res/values-id/strings.xml b/WordPress/src/main/res/values-id/strings.xml index 8fffd4d2887e..715217197b40 100644 --- a/WordPress/src/main/res/values-id/strings.xml +++ b/WordPress/src/main/res/values-id/strings.xml @@ -554,11 +554,11 @@ Language: id Tidak ada data selama periode ini Hapus lokasi dari media Saat ini kami tidak dapat membuka statistik. Harap coba lagi nanti - Didukung oleh GIPHY - Sebagian media gagal dimuat karena terdapat error jaringan. - Tidak ada media yang cocok dengan pencarian Anda - Cari GIF untuk ditambahkan ke Pustaka Media Anda! - Cari di Giphy + Didukung oleh TENOR + Sebagian media gagal dimuat karena terdapat error jaringan. + Tidak ada media yang cocok dengan pencarian Anda + Cari GIF untuk ditambahkan ke Pustaka Media Anda! + Cari di Tenor Tampilan Penulis Penulis diff --git a/WordPress/src/main/res/values-it/strings.xml b/WordPress/src/main/res/values-it/strings.xml index c10f3a8703ad..c9823a468e51 100644 --- a/WordPress/src/main/res/values-it/strings.xml +++ b/WordPress/src/main/res/values-it/strings.xml @@ -542,11 +542,11 @@ Language: it Nessun dato per questo periodo Rimuovi posizione dal contenuto multimediale Non è possibile aprire le statistiche. Riprova più tardi - Powered by GIPHY - Alcuni caricamenti multimediali non sono riusciti a causa di un errore di rete. - Nessun media corrispondente alla tua ricerca - Cerca per trovare GIF da aggiungere alla tua Libreria multimediale! - Cerca in Giphy + Powered by TENOR + Alcuni caricamenti multimediali non sono riusciti a causa di un errore di rete. + Nessun media corrispondente alla tua ricerca + Cerca per trovare GIF da aggiungere alla tua Libreria multimediale! + Cerca in Tenor Visualizzazioni Autore Autori diff --git a/WordPress/src/main/res/values-ja/strings.xml b/WordPress/src/main/res/values-ja/strings.xml index 707691413ae8..70e118404f6b 100644 --- a/WordPress/src/main/res/values-ja/strings.xml +++ b/WordPress/src/main/res/values-ja/strings.xml @@ -558,11 +558,11 @@ Language: ja_JP この期間のデータがありません メディアから位置情報を削除する 現在統計を開けません。後ほど、もう一度お試しください - Powered by GIPHY - ネットワークエラーにより一部のメディアが読み込めませんでした。 - 検索と一致するメディアがありません - GIF を検索して、メディアライブラリに追加してください。 - Giphy を検索する + Powered by TENOR + ネットワークエラーにより一部のメディアが読み込めませんでした。 + 検索と一致するメディアがありません + GIF を検索して、メディアライブラリに追加してください。 + Tenor を検索する 表示回数 投稿者 投稿者 diff --git a/WordPress/src/main/res/values-ko/strings.xml b/WordPress/src/main/res/values-ko/strings.xml index aabe30ad038b..11c60644ea0f 100644 --- a/WordPress/src/main/res/values-ko/strings.xml +++ b/WordPress/src/main/res/values-ko/strings.xml @@ -553,11 +553,11 @@ Language: ko_KR 이 기간에 데이터 없음 미디어에서 위치 제거 지금은 통계를 열 수 없습니다. 나중에 다시 시도해 주세요. - GIPHY 제공 - 네트워크 오류로 인해 일부 미디어를 로드하지 못했습니다. - 검색과 일치하는 미디어 없음 - GIF를 검색하여 미디어 라이브러리에 추가하세요! - Giphy 검색 + TENOR 제공 + 네트워크 오류로 인해 일부 미디어를 로드하지 못했습니다. + 검색과 일치하는 미디어 없음 + GIF를 검색하여 미디어 라이브러리에 추가하세요! + Tenor 검색 조회수 글쓴이 글쓴이 diff --git a/WordPress/src/main/res/values-nb/strings.xml b/WordPress/src/main/res/values-nb/strings.xml index 12a0a0d4a5a7..8ee7181c2d85 100644 --- a/WordPress/src/main/res/values-nb/strings.xml +++ b/WordPress/src/main/res/values-nb/strings.xml @@ -530,11 +530,11 @@ Language: nb_NO Ingen data for denne perioden Fjern dette stedet fra media Vi kan ikke åpne statistikken i øyeblikket. Vennligst prøv igjen senere - Drevet av GIPHY - Noe media kunne ikke lastes på grunn av en nettverksfeil. - Ingen media passet ditt søk - Søk for å finne GIF-er å legge til i ditt mediebibliotek! - Søk Giphy + Drevet av TENOR + Noe media kunne ikke lastes på grunn av en nettverksfeil. + Ingen media passet ditt søk + Søk for å finne GIF-er å legge til i ditt mediebibliotek! + Søk Tenor Visninger Forfatter Forfattere diff --git a/WordPress/src/main/res/values-nl/strings.xml b/WordPress/src/main/res/values-nl/strings.xml index c1679f5819a3..b5a922b6cffb 100644 --- a/WordPress/src/main/res/values-nl/strings.xml +++ b/WordPress/src/main/res/values-nl/strings.xml @@ -512,8 +512,8 @@ Language: nl Geen gegevens voor deze periode Locatie van media verwijderen We kunnen de statistieken momenteel niet openen. Probeer het later opnieuw - Mogelijk gemaakt door GIPHY - Zoek op Giphy + Mogelijk gemaakt door TENOR + Zoek op Tenor Auteur Auteurs Zoekterm diff --git a/WordPress/src/main/res/values-pl/strings.xml b/WordPress/src/main/res/values-pl/strings.xml index 2747cd90c004..5ff49353a203 100644 --- a/WordPress/src/main/res/values-pl/strings.xml +++ b/WordPress/src/main/res/values-pl/strings.xml @@ -610,11 +610,11 @@ Language: pl Brak danych dla tego okresu Usuń lokalizację GPS z plików mediów Nie możemy w tym momencie otworzyć statystyk. Spróbuj ponownie później - Wspierane przez GIPHY - Niektórych plików mediów nie udało się przesłać z powodu błędu sieci. - Brak plików mediów dopasowanych do twojego zapytania - Przeszukaj aby znaleźć pliki GIF które możesz dodać do swojej biblioteki mediów! - Przeszukaj Giphy + Wspierane przez TENOR + Niektórych plików mediów nie udało się przesłać z powodu błędu sieci. + Brak plików mediów dopasowanych do twojego zapytania + Przeszukaj aby znaleźć pliki GIF które możesz dodać do swojej biblioteki mediów! + Przeszukaj Tenor Wyświetleń Autor Autorzy diff --git a/WordPress/src/main/res/values-pt-rBR/strings.xml b/WordPress/src/main/res/values-pt-rBR/strings.xml index 0785ed1501a7..814a6fba2a7e 100644 --- a/WordPress/src/main/res/values-pt-rBR/strings.xml +++ b/WordPress/src/main/res/values-pt-rBR/strings.xml @@ -559,11 +559,11 @@ Language: pt_BR Nenhum dado para esse período Remover localização de mídia Não conseguimos abrir as estatísticas agora. Tente novamente mais tarde. - Oferecido pelo GIPHY - Alguns arquivos não puderam ser carregados devido a problemas com a conexão. - Nenhuma mídia corresponde à sua pesquisa - Pesquise para encontrar gifs para adicionar à sua biblioteca de mídias. - Pesquisar no Giphy + Oferecido pelo TENOR + Alguns arquivos não puderam ser carregados devido a problemas com a conexão. + Nenhuma mídia corresponde à sua pesquisa + Pesquise para encontrar gifs para adicionar à sua biblioteca de mídias. + Pesquisar no Tenor Visualizações Autor Autores diff --git a/WordPress/src/main/res/values-ro/strings.xml b/WordPress/src/main/res/values-ro/strings.xml index 84c0eb15525a..2fe651e06123 100644 --- a/WordPress/src/main/res/values-ro/strings.xml +++ b/WordPress/src/main/res/values-ro/strings.xml @@ -614,11 +614,11 @@ Language: ro Nu există date pentru această perioadă Înlătură locația din Media Pentru moment, nu putem deschide statisticile. Te rog reîncearcă mai târziu - Propulsat de GIPHY - Unele elemente media au eșuat la încărcare din cauza unei erori de rețea. - Nu s-a potrivit niciun element media cu căutarea ta - Caută pentru a găsi imagini GIF pe care să le adaugi în Biblioteca ta media! - Caută cu Giphy + Propulsat de TENOR + Unele elemente media au eșuat la încărcare din cauza unei erori de rețea. + Nu s-a potrivit niciun element media cu căutarea ta + Caută pentru a găsi imagini GIF pe care să le adaugi în Biblioteca ta media! + Caută cu Tenor Vizualizări Autor Autori diff --git a/WordPress/src/main/res/values-ru/strings.xml b/WordPress/src/main/res/values-ru/strings.xml index ee6a709df17f..b3a98f261e85 100644 --- a/WordPress/src/main/res/values-ru/strings.xml +++ b/WordPress/src/main/res/values-ru/strings.xml @@ -614,11 +614,11 @@ Language: ru Для указанного периода нет данных Убрать данные местоположения из медиафайлов Извините, статистика в данный момент недоступна, попробуйте позже. - Работает с GIPHY - Некоторые медиафайлы не загрузились из-за ошибки сети. - Мультимедиа по критериям поиска не найдены - Найдите GIF изображения и добавьте их в медиатеку! - Поиск в Giphy + Работает с TENOR + Некоторые медиафайлы не загрузились из-за ошибки сети. + Мультимедиа по критериям поиска не найдены + Найдите GIF изображения и добавьте их в медиатеку! + Поиск в Tenor Просмотры Автор Авторы diff --git a/WordPress/src/main/res/values-sk/strings.xml b/WordPress/src/main/res/values-sk/strings.xml index 463ffda16d17..db12bd87dfa7 100644 --- a/WordPress/src/main/res/values-sk/strings.xml +++ b/WordPress/src/main/res/values-sk/strings.xml @@ -44,8 +44,8 @@ Language: sk Vrátiť späť Žiadne dáta pre toto obdobie Odstrániť lokáciu z médiá - Poháňa GIPHY - Vyhľadať v Giphy + Poháňa TENOR + Vyhľadať v Tenor Zobrazenia Autor Autori diff --git a/WordPress/src/main/res/values-sq/strings.xml b/WordPress/src/main/res/values-sq/strings.xml index 2a2e77a1f011..447d428ebcc9 100644 --- a/WordPress/src/main/res/values-sq/strings.xml +++ b/WordPress/src/main/res/values-sq/strings.xml @@ -614,11 +614,11 @@ Language: sq_AL S’ka të dhëna për këtë periudhë Hiqe vendndodhjen prej mediash S’i hapim dot statistikat tani. Ju lutemi, riprovoni më vonë - Bazuar në Giphy - Dështoi ngarkimi për ca media, për shkak të një gabimi rrjeti. - S’ka media që përputhet me kërkimin tuaj - Kërkoni për të gjetur GIF-e që t’i shtoni te Mediateka juaj! - Kërkoni në Giphy + Bazuar në Tenor + Dështoi ngarkimi për ca media, për shkak të një gabimi rrjeti. + S’ka media që përputhet me kërkimin tuaj + Kërkoni për të gjetur GIF-e që t’i shtoni te Mediateka juaj! + Kërkoni në Tenor Parje Autor Autorë diff --git a/WordPress/src/main/res/values-sv/strings.xml b/WordPress/src/main/res/values-sv/strings.xml index 5570c93ee2eb..b34959fca4b1 100644 --- a/WordPress/src/main/res/values-sv/strings.xml +++ b/WordPress/src/main/res/values-sv/strings.xml @@ -614,11 +614,11 @@ Language: sv_SE Inga uppgifter för denna tidsperiod Avlägsna position från media Just nu går det inte att öppna statistiken. Försök igen senare - Drivs med hjälp av GIPHY - Vissa mediefiler kunde inte laddas på grund av nätverksproblem. - Inga media matchar din sökning - Leta efter GIF-filer du kan lägga till i ditt mediebibliotek! - Sök i Giphy + Drivs med hjälp av TENOR + Vissa mediefiler kunde inte laddas på grund av nätverksproblem. + Inga media matchar din sökning + Leta efter GIF-filer du kan lägga till i ditt mediebibliotek! + Sök i Tenor Visningar Författare Författare diff --git a/WordPress/src/main/res/values-tr/strings.xml b/WordPress/src/main/res/values-tr/strings.xml index a742c0010d85..4e2f029b6dca 100644 --- a/WordPress/src/main/res/values-tr/strings.xml +++ b/WordPress/src/main/res/values-tr/strings.xml @@ -559,11 +559,11 @@ Language: tr Bu dönem için veri yok Ortam dosyasından konum bilgisini kaldır Şu anda istatistikleri açamıyoruz. Lütfen daha sonra tekrar deneyiniz. - GIPHY tarafından sağlanır - Ağ hatası nedeniyle bazı ortam dosyaları yüklenemedi. - Aramanızla eşleşen bir ortam yok - Ortam kütüphanenize GIF bulup eklemek için arayın! - Giphy\'de ara + TENOR tarafından sağlanır + Ağ hatası nedeniyle bazı ortam dosyaları yüklenemedi. + Aramanızla eşleşen bir ortam yok + Ortam kütüphanenize GIF bulup eklemek için arayın! + Tenor\'de ara Görüntülemeler Yazar Yazarlar diff --git a/WordPress/src/main/res/values-zh-rCN/strings.xml b/WordPress/src/main/res/values-zh-rCN/strings.xml index 6ebbec25ac04..e91e375f5a50 100644 --- a/WordPress/src/main/res/values-zh-rCN/strings.xml +++ b/WordPress/src/main/res/values-zh-rCN/strings.xml @@ -502,11 +502,11 @@ Language: zh_CN 没有此时间段的数据 从媒体删除位置信息 我们现在无法打开统计信息。请稍后重试 - 由 GIPHY 提供支持 - 由于网络错误,无法加载某些媒体。 - 没有与您的搜索匹配的媒体 - 搜索查找要添加到您的媒体库中的 GIF! - 搜索 Giphy + 由 TENOR 提供支持 + 由于网络错误,无法加载某些媒体。 + 没有与您的搜索匹配的媒体 + 搜索查找要添加到您的媒体库中的 GIF! + 搜索 Tenor 浏览量 作者 作者 diff --git a/WordPress/src/main/res/values-zh-rHK/strings.xml b/WordPress/src/main/res/values-zh-rHK/strings.xml index 23e9cc316b71..bc404074e04c 100644 --- a/WordPress/src/main/res/values-zh-rHK/strings.xml +++ b/WordPress/src/main/res/values-zh-rHK/strings.xml @@ -549,11 +549,11 @@ Language: zh_TW 此期間沒有資料 從媒體移除位置資訊 目前我們無法開啟統計資料。請稍後再試一次 - 由 GIPHY 建置 - 網路發生錯誤,導致部份媒體載入失敗。 - 沒有符合你搜尋條件的媒體 - 搜尋免費 GIF 以新增至你的媒體庫! - 搜尋 Giphy + 由 TENOR 建置 + 網路發生錯誤,導致部份媒體載入失敗。 + 沒有符合你搜尋條件的媒體 + 搜尋免費 GIF 以新增至你的媒體庫! + 搜尋 Tenor 瀏覽數 作者 作者 diff --git a/WordPress/src/main/res/values-zh-rTW/strings.xml b/WordPress/src/main/res/values-zh-rTW/strings.xml index 23e9cc316b71..bc404074e04c 100644 --- a/WordPress/src/main/res/values-zh-rTW/strings.xml +++ b/WordPress/src/main/res/values-zh-rTW/strings.xml @@ -549,11 +549,11 @@ Language: zh_TW 此期間沒有資料 從媒體移除位置資訊 目前我們無法開啟統計資料。請稍後再試一次 - 由 GIPHY 建置 - 網路發生錯誤,導致部份媒體載入失敗。 - 沒有符合你搜尋條件的媒體 - 搜尋免費 GIF 以新增至你的媒體庫! - 搜尋 Giphy + 由 TENOR 建置 + 網路發生錯誤,導致部份媒體載入失敗。 + 沒有符合你搜尋條件的媒體 + 搜尋免費 GIF 以新增至你的媒體庫! + 搜尋 Tenor 瀏覽數 作者 作者 diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 417f7f8af489..82cc6b542cc6 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2255,12 +2255,12 @@ Photos provided by %s - Search Tenor - Search to find GIFs to add to your Media Library! - No media matching your search - Some media failed to load due to a network error. - Sorry, there was a problem - Powered by Tenor + Search Tenor + Search to find GIFs to add to your Media Library! + No media matching your search + Some media failed to load due to a network error. + Sorry, there was a problem + Powered by Tenor Saving post as draft From 0ed14836c5362158bbb20adf0c0a61abf88b7269 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sun, 29 Mar 2020 18:05:14 -0300 Subject: [PATCH 45/58] Adjusted all remaining documentation and code referencing Giphy --- .../android/ui/gif/GifMediaViewHolder.kt | 2 +- .../android/ui/gif/GifPickerActivity.kt | 14 ++++++------- .../ui/gif/GifPickerPagedListAdapter.kt | 4 ++-- .../android/ui/posts/EditPostActivity.java | 2 +- .../ui/posts/editor/media/EditorMedia.kt | 2 +- .../android/viewmodel/gif/GifMediaFetcher.kt | 2 +- .../viewmodel/gif/GifMediaViewModel.kt | 14 +++++-------- .../viewmodel/gif/GifPickerDataSource.kt | 4 ++-- .../viewmodel/gif/GifPickerViewModel.kt | 4 ++-- .../viewmodel/gif/MutableGifMediaViewModel.kt | 2 +- .../viewmodel/gif/provider/TenorProvider.kt | 6 ++++-- .../ui/posts/editor/media/EditorMediaTest.kt | 4 ++-- ...ures.kt => GifPickerDataSourceFixtures.kt} | 2 +- .../viewmodel/gif/GifPickerDataSourceTest.kt | 2 +- .../viewmodel/gif/GifPickerViewModelTest.kt | 20 +++++++++---------- 15 files changed, 40 insertions(+), 44 deletions(-) rename WordPress/src/test/java/org/wordpress/android/viewmodel/gif/{GiphyPickerDataSourceFixtures.kt => GifPickerDataSourceFixtures.kt} (87%) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gif/GifMediaViewHolder.kt b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifMediaViewHolder.kt index a4f535d2730f..610256836843 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gif/GifMediaViewHolder.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifMediaViewHolder.kt @@ -22,7 +22,7 @@ import org.wordpress.android.viewmodel.gif.GifMediaViewModel * This is meant to show a single animated gif. * * This ViewHolder references a readonly [GifMediaViewModel]. It should never update the [GifMediaViewModel]. That - * behavior is handled by the [GiphyPickerViewModel]. This is designed this way so that [GiphyPickerViewModel] + * behavior is handled by the [GifPickerViewModel]. This is designed this way so that [GifPickerViewModel] * encapsulates all the logic of managing selected items as well as keeping their selection numbers continuous. */ class GifMediaViewHolder( diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerActivity.kt index be4721255be7..babf2dc45000 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerActivity.kt @@ -36,9 +36,7 @@ import org.wordpress.android.viewmodel.gif.GifPickerViewModel.State import javax.inject.Inject /** - * Allows searching of gifs from Giphy - * - * Important: Giphy is currently disabled everywhere. We are planning to replace it with a different service provider. + * Allows searching of gifs from a giving provider */ class GifPickerActivity : LocaleAwareActivity() { /** @@ -126,7 +124,7 @@ class GifPickerActivity : LocaleAwareActivity() { * Configure the search view to execute search when the keyboard's Done button is pressed. */ private fun initializeSearchView() { - search_view.queryHint = getString(R.string.giphy_picker_search_hint) + search_view.queryHint = getString(R.string.gif_picker_search_hint) search_view.setOnQueryTextListener(object : OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { @@ -203,7 +201,7 @@ class GifPickerActivity : LocaleAwareActivity() { emptyView.run { image.setImageResource(R.drawable.img_illustration_media_105dp) bottomImage.setImageResource(R.drawable.img_tenor_100dp) - bottomImage.contentDescription = getString(R.string.giphy_powered_by_giphy) + bottomImage.contentDescription = getString(R.string.gif_powered_by_tenor) } viewModel.emptyDisplayMode.getDistinct().observe(this, Observer { emptyDisplayMode -> @@ -216,7 +214,7 @@ class GifPickerActivity : LocaleAwareActivity() { updateLayoutForSearch(isSearching = true, topMargin = 0) visibility = View.VISIBLE - title.setText(R.string.giphy_picker_empty_search_list) + title.setText(R.string.gif_picker_empty_search_list) image.visibility = View.GONE bottomImage.visibility = View.GONE } @@ -226,7 +224,7 @@ class GifPickerActivity : LocaleAwareActivity() { updateLayoutForSearch(isSearching = false, topMargin = 0) visibility = View.VISIBLE - title.setText(R.string.giphy_picker_initial_empty_text) + title.setText(R.string.gif_picker_initial_empty_text) image.visibility = View.VISIBLE bottomImage.visibility = View.VISIBLE } @@ -254,7 +252,7 @@ class GifPickerActivity : LocaleAwareActivity() { ToastUtils.showToast( this@GifPickerActivity, - R.string.giphy_picker_endless_scroll_network_error, + R.string.gif_picker_endless_scroll_network_error, ToastUtils.Duration.LONG ) }) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerPagedListAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerPagedListAdapter.kt index ee687df79fe2..29350ba3c590 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerPagedListAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/gif/GifPickerPagedListAdapter.kt @@ -8,7 +8,7 @@ import org.wordpress.android.util.image.ImageManager import org.wordpress.android.viewmodel.gif.GifMediaViewModel /** - * An [RecyclerView] adapter to be used with the [PagedList] created by [GiphyPickerViewModel] + * An [RecyclerView] adapter to be used with the [PagedList] created by [GifPickerViewModel] */ class GifPickerPagedListAdapter( private val imageManager: ImageManager, @@ -39,7 +39,7 @@ class GifPickerPagedListAdapter( /** * Always assume that two similar [GifMediaViewModel] objects always have the same content. * - * It is probably extremely unlikely that GIFs from Giphy will change while the user is performing + * It is probably extremely unlikely that GIFs will change while the user is performing * a search. */ override fun areContentsTheSame(oldItem: GifMediaViewModel, newItem: GifMediaViewModel): Boolean { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java index c851d739c4cb..d607bd0b661d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java @@ -2266,7 +2266,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case RequestCodes.GIF_PICKER: if (data.hasExtra(GifPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS)) { int[] localIds = data.getIntArrayExtra(GifPickerActivity.KEY_SAVED_MEDIA_MODEL_LOCAL_IDS); - mEditorMedia.addMediaFromGiphyToPostAsync(localIds); + mEditorMedia.addGifMediaToPostAsync(localIds); } break; case RequestCodes.HISTORY_DETAIL: diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt index 0267ab08af3f..e885e5b411b8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/editor/media/EditorMedia.kt @@ -138,7 +138,7 @@ class EditorMedia @Inject constructor( /** * This won't create a MediaModel. It assumes the model was already created. */ - fun addMediaFromGiphyToPostAsync(localMediaIds: IntArray) { + fun addGifMediaToPostAsync(localMediaIds: IntArray) { launch { addLocalMediaToPostUseCase.addLocalMediaToEditorAsync( localMediaIds.toList(), diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt index 1d02c055c486..4d5073c4b6ab 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaFetcher.kt @@ -41,7 +41,7 @@ class GifMediaFetcher @Inject constructor( gifMediaViewModels: List, site: SiteModel ): List = coroutineScope { - // Execute [fetchAndSave] for all giphyMediaViewModels first so that they are queued and executed in the + // Execute [fetchAndSave] for all gifMediaViewModels first so that they are queued and executed in the // background. We'll call `await()` once they are queued. return@coroutineScope gifMediaViewModels.map { fetchAndSave(scope = this, gifMediaViewModel = it, site = site) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt index e660e309879f..4aa766b0cd10 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt @@ -4,20 +4,16 @@ import android.net.Uri import androidx.lifecycle.LiveData /** - * A data-representation of [GiphyMediaViewHolder] + * A data-representation of [GifMediaViewHolder] * - * The values of this class comes from Giphy's [Media] model. The [Media] object is big so we use this class to - * only keep a minimal amount of memory. This also hides the complexity of navigating the values of [Media]. + * The values of this class comes from [GifProvider] as a list. * - * This class also houses the selection status. The [GiphyMediaViewHolder] observes the [isSelected] and + * This class also houses the selection status. The [GifMediaViewHolder] observes the [isSelected] and * [selectionNumber] properties to update itself. - * - * See the [Giphy API docs](https://developers.giphy.com/docs/) for more information on what a [Media] object contains. - * Search for "The GIF Object" section. */ interface GifMediaViewModel { /** - * The id from Giphy's [Media] + * The id from GIF [Media] */ val id: String /** @@ -37,7 +33,7 @@ interface GifMediaViewModel { */ val largeImageUri: Uri /** - * The title that appears on giphy.com + * The title that appears on the GIF */ val title: String /** diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt index ba56a1a8d936..72ce9ef85cdc 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSource.kt @@ -51,7 +51,7 @@ class GifPickerDataSource( private val failedRangeLoadArguments = mutableListOf() /** - * Always the load the first page (startingPosition = 0) from the Giphy API + * Always the load the first page (startingPosition = 0) from the Gif API * * The [GifPickerDataSourceFactory] recreates [GifPickerDataSource] instances whenever a new [searchQuery] * is queued. The [LoadInitialParams.requestedStartPosition] may have a value that is only valid for the @@ -102,7 +102,7 @@ class GifPickerDataSource( } /** - * Load a given range of items ([params]) from the Giphy API. + * Load a given range of items ([params]) from the Gif API. * * Errors are dispatched to [rangeLoadErrorEvent]. If successful, previously failed calls of this method are * automatically retried using [retryAllFailedRangeLoads]. diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt index 70474d15fb48..69d2a03acddd 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerViewModel.kt @@ -269,8 +269,8 @@ class GifPickerViewModel @Inject constructor( _state.postValue(State.DOWNLOADING) val result = try { - val giphyMediaViewModels = _selectedMediaViewModelList.value?.values?.toList() ?: emptyList() - val mediaModels = mediaFetcher.fetchAndSave(giphyMediaViewModels, site) + val gifMediaViewModels = _selectedMediaViewModelList.value?.values?.toList() ?: emptyList() + val mediaModels = mediaFetcher.fetchAndSave(gifMediaViewModels, site) DownloadResult(mediaModels = mediaModels) } catch (e: CancellationException) { // We don't need to handle coroutine cancellations. The UI should just do nothing. diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt index ef92c50bc337..2fee820ad649 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/MutableGifMediaViewModel.kt @@ -12,7 +12,7 @@ import org.wordpress.android.viewmodel.SingleLiveEvent * way so that [GifPickerViewModel] encapsulates all the logic of managing selected items as well as keeping their * selection numbers continuous. * - * The [GiphyPickerViewHolder] should never have access to the mutating methods of this class. + * The [GifPickerViewHolder] should never have access to the mutating methods of this class. */ data class MutableGifMediaViewModel( override val id: String, diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index e4edd55e7e17..84877aee1d40 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -55,7 +55,7 @@ internal class TenorProvider constructor( onSuccess(gifList, nextPosition) }, onFailure = { - val errorMessage = it?.message ?: context.getString(string.gifs_list_search_returned_unknown_error) + val errorMessage = it?.message ?: context.getString(string.gif_list_search_returned_unknown_error) onFailure(GifRequestFailedException(errorMessage)) } ) @@ -78,7 +78,7 @@ internal class TenorProvider constructor( ) = buildSearchCall(query, loadSize, position).apply { enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { - val defaultErrorMessage = context.getString(string.giphy_picker_empty_search_list) + val defaultErrorMessage = context.getString(string.gif_picker_empty_search_list) response.body()?.let(onSuccess) ?: onFailure(GifRequestFailedException(defaultErrorMessage)) } @@ -112,6 +112,8 @@ internal class TenorProvider constructor( * Every GIF returned by the Tenor will be available as [Result], to better interface * with our app, it will be converted to [MutableGifMediaViewModel] to avoid any external * coupling with the Tenor API + * + * See the [Tenor API docs](https://tenor.com/gifapi/documentation#responseobjects) for more information on what a [Result] object contains. */ private fun Result.toMutableGifMediaViewModel() = MutableGifMediaViewModel( id, diff --git a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt index ea896b5e7cce..037177a2fa19 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/posts/editor/media/EditorMediaTest.kt @@ -121,7 +121,7 @@ class EditorMediaTest : BaseUnitTest() { } @Test - fun `addMediaFromGiphyToPostAsync invokes addLocalMediaToEditorAsync with all media`() = test { + fun `addGifMediaToPostAsync invokes addLocalMediaToEditorAsync with all media`() = test { // Arrange val localIdArray = listOf(1, 2, 3).toIntArray() val addLocalMediaToPostUseCase = createAddLocalMediaToPostUseCase() @@ -130,7 +130,7 @@ class EditorMediaTest : BaseUnitTest() { createEditorMedia( addLocalMediaToPostUseCase = addLocalMediaToPostUseCase ) - .addMediaFromGiphyToPostAsync(localIdArray) + .addGifMediaToPostAsync(localIdArray) // Assert verify(addLocalMediaToPostUseCase).addLocalMediaToEditorAsync( eq(localIdArray.toList()), diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GiphyPickerDataSourceFixtures.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFixtures.kt similarity index 87% rename from WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GiphyPickerDataSourceFixtures.kt rename to WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFixtures.kt index c147cc45a519..0dd6848c5049 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GiphyPickerDataSourceFixtures.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFixtures.kt @@ -2,7 +2,7 @@ package org.wordpress.android.viewmodel.gif import com.nhaarman.mockitokotlin2.mock -object GiphyPickerDataSourceFixtures { +object GifPickerDataSourceFixtures { internal val expectedGifMediaViewModelCollection: List = listOf( mock(), mock(), diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt index 65f8f27867e5..6b58e5ea3aee 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt @@ -16,7 +16,7 @@ import org.junit.Before import org.junit.Test import org.mockito.Mock import org.mockito.MockitoAnnotations -import org.wordpress.android.viewmodel.gif.GiphyPickerDataSourceFixtures.expectedGifMediaViewModelCollection +import org.wordpress.android.viewmodel.gif.GifPickerDataSourceFixtures.expectedGifMediaViewModelCollection import org.wordpress.android.viewmodel.gif.provider.GifProvider import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt index 22ab766e93c8..01179c5b952a 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerViewModelTest.kt @@ -52,7 +52,7 @@ class GifPickerViewModelTest { @Test fun `when setting a mediaViewModel as selected, it adds that to the selected list`() { - val mediaViewModel = createGiphyMediaViewModel() + val mediaViewModel = createGifMediaViewModel() viewModel.toggleSelected(mediaViewModel) @@ -64,7 +64,7 @@ class GifPickerViewModelTest { @Test fun `when setting a mediaViewModel as selected, it updates the isSelected and selectedNumber`() { - val mediaViewModel = createGiphyMediaViewModel() + val mediaViewModel = createGifMediaViewModel() viewModel.toggleSelected(mediaViewModel) @@ -75,7 +75,7 @@ class GifPickerViewModelTest { @Test fun `when toggling an already selected mediaViewModel, it gets deselected and removed from the selected list`() { // Arrange - val mediaViewModel = createGiphyMediaViewModel() + val mediaViewModel = createGifMediaViewModel() viewModel.toggleSelected(mediaViewModel) // Act @@ -91,10 +91,10 @@ class GifPickerViewModelTest { @Test fun `when deselecting a mediaViewModel, it rebuilds the selectedNumbers so they are continuous`() { // Arrange - val alpha = createGiphyMediaViewModel() - val bravo = createGiphyMediaViewModel() - val charlie = createGiphyMediaViewModel() - val delta = createGiphyMediaViewModel() + val alpha = createGifMediaViewModel() + val bravo = createGifMediaViewModel() + val charlie = createGifMediaViewModel() + val delta = createGifMediaViewModel() listOf(alpha, bravo, charlie, delta).forEach(viewModel::toggleSelected) @@ -121,7 +121,7 @@ class GifPickerViewModelTest { @Test fun `when the searchQuery is changed, it clears the selected mediaViewModel list`() { // Arrange - val mediaViewModel = createGiphyMediaViewModel() + val mediaViewModel = createGifMediaViewModel() viewModel.toggleSelected(mediaViewModel) // Act @@ -287,7 +287,7 @@ class GifPickerViewModelTest { } check(viewModel.state.value == State.FINISHED) - viewModel.toggleSelected(createGiphyMediaViewModel()) + viewModel.toggleSelected(createGifMediaViewModel()) // Assert assertThat(viewModel.selectedMediaViewModelList.value).isNull() @@ -316,7 +316,7 @@ class GifPickerViewModelTest { id = Random().nextInt() } - private fun createGiphyMediaViewModel() = MutableGifMediaViewModel( + private fun createGifMediaViewModel() = MutableGifMediaViewModel( id = UUID.randomUUID().toString(), thumbnailUri = mock(), largeImageUri = mock(), From af0aaa77a2ea438492db3ccf7a695d2d9224c04f Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 31 Mar 2020 22:41:11 -0300 Subject: [PATCH 46/58] Adjust GifMediaViewModel documentation --- .../org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt index 4aa766b0cd10..b0ff105ef692 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifMediaViewModel.kt @@ -13,7 +13,7 @@ import androidx.lifecycle.LiveData */ interface GifMediaViewModel { /** - * The id from GIF [Media] + * The GIF unique id */ val id: String /** From 35f8d0a2d2456f9c39896e52d245d1f0a1999d47 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 31 Mar 2020 22:41:40 -0300 Subject: [PATCH 47/58] Removed maven reference for giphy SDK --- WordPress/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 91202c04a861..9c0b58418299 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -15,7 +15,6 @@ repositories { google() jcenter() maven { url 'https://zendesk.jfrog.io/zendesk/repo' } - maven { url "https://giphy.bintray.com/giphy-sdk" } maven { url "https://www.jitpack.io" } maven { url "http://dl.bintray.com/terl/lazysodium-maven" } } From 93fe31c41df17f78232388ba44a8d4ef6d38ff61 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 1 Apr 2020 10:27:59 -0300 Subject: [PATCH 48/58] Removed translations of gif strings --- WordPress/src/main/res/values-ar/strings.xml | 5 ----- WordPress/src/main/res/values-el/strings.xml | 1 - WordPress/src/main/res/values-en-rAU/strings.xml | 5 ----- WordPress/src/main/res/values-en-rCA/strings.xml | 5 ----- WordPress/src/main/res/values-en-rGB/strings.xml | 5 ----- WordPress/src/main/res/values-es-rCL/strings.xml | 5 ----- WordPress/src/main/res/values-es-rMX/strings.xml | 5 ----- WordPress/src/main/res/values-es-rVE/strings.xml | 5 ----- WordPress/src/main/res/values-he/strings.xml | 5 ----- WordPress/src/main/res/values-id/strings.xml | 5 ----- WordPress/src/main/res/values-it/strings.xml | 5 ----- WordPress/src/main/res/values-ja/strings.xml | 5 ----- WordPress/src/main/res/values-kmr/strings.xml | 5 ----- WordPress/src/main/res/values-ko/strings.xml | 5 ----- WordPress/src/main/res/values-nb/strings.xml | 5 ----- WordPress/src/main/res/values-nl/strings.xml | 2 -- WordPress/src/main/res/values-pl/strings.xml | 5 ----- WordPress/src/main/res/values-pt-rBR/strings.xml | 5 ----- WordPress/src/main/res/values-ro/strings.xml | 5 ----- WordPress/src/main/res/values-ru/strings.xml | 5 ----- WordPress/src/main/res/values-sk/strings.xml | 2 -- WordPress/src/main/res/values-sq/strings.xml | 5 ----- WordPress/src/main/res/values-sv/strings.xml | 5 ----- WordPress/src/main/res/values-tr/strings.xml | 5 ----- WordPress/src/main/res/values-zh-rCN/strings.xml | 5 ----- WordPress/src/main/res/values-zh-rHK/strings.xml | 5 ----- WordPress/src/main/res/values-zh-rTW/strings.xml | 5 ----- 27 files changed, 125 deletions(-) diff --git a/WordPress/src/main/res/values-ar/strings.xml b/WordPress/src/main/res/values-ar/strings.xml index 49e956a1510a..34946cd49933 100644 --- a/WordPress/src/main/res/values-ar/strings.xml +++ b/WordPress/src/main/res/values-ar/strings.xml @@ -614,11 +614,6 @@ Language: ar لا توجد بيانات لهذه الفترة إزالة موقع من الوسائط يتعذر علينا فتح الإحصاءات في الوقت الحالي. يرجى المحاولة مجددًا في وقت لاحق - مدعون من TENOR - فشل تحميل بعض الوسائط بسبب وجود خطأ في الشبكة. - لا توجد وسائط مطابقة لبحثك - ابحث للعثور على صور بتنسيق GIF لإضافتها إلى مكتبة الوسائط الخاصة بك! - البحث في Tenor مشاهدات الكاتب الكُتّاب diff --git a/WordPress/src/main/res/values-el/strings.xml b/WordPress/src/main/res/values-el/strings.xml index 3bb620352217..358c66dcce2c 100644 --- a/WordPress/src/main/res/values-el/strings.xml +++ b/WordPress/src/main/res/values-el/strings.xml @@ -55,7 +55,6 @@ Language: el_GR %1$d από %2$d Δημιουργία ιστότοπου Αναίρεση - Αναζήτηση στο Tenor Προβολές Συγγραφέας Συγγραφείς diff --git a/WordPress/src/main/res/values-en-rAU/strings.xml b/WordPress/src/main/res/values-en-rAU/strings.xml index dc0d8343a656..1ae880a91998 100644 --- a/WordPress/src/main/res/values-en-rAU/strings.xml +++ b/WordPress/src/main/res/values-en-rAU/strings.xml @@ -378,11 +378,6 @@ Language: en_AU No data for this period Remove location from media We cannot open the statistics at the moment. Please try again later - Powered by TENOR - Some media failed to load due to a network error. - No media matching your search - Search to find GIFs to add to your Media Library! - Search Tenor Views Author Authors diff --git a/WordPress/src/main/res/values-en-rCA/strings.xml b/WordPress/src/main/res/values-en-rCA/strings.xml index ba6fbcfcf198..47551845a740 100644 --- a/WordPress/src/main/res/values-en-rCA/strings.xml +++ b/WordPress/src/main/res/values-en-rCA/strings.xml @@ -473,11 +473,6 @@ Language: en_CA No data for this period Remove location from media We cannot open the statistics at the moment. Please try again later - Powered by TENOR - Some media failed to load due to a network error. - No media matching your search - Search to find GIFs to add to your Media Library! - Search Tenor Views Author Authors diff --git a/WordPress/src/main/res/values-en-rGB/strings.xml b/WordPress/src/main/res/values-en-rGB/strings.xml index 8932ce5ab0c7..a77945f3ee2c 100644 --- a/WordPress/src/main/res/values-en-rGB/strings.xml +++ b/WordPress/src/main/res/values-en-rGB/strings.xml @@ -614,11 +614,6 @@ Language: en_GB No data for this period Remove location from media We cannot open the statistics at the moment. Please try again later - Powered by TENOR - Some media failed to load due to a network error. - No media matching your search - Search to find GIFs to add to your Media Library! - Search Tenor Views Author Authors diff --git a/WordPress/src/main/res/values-es-rCL/strings.xml b/WordPress/src/main/res/values-es-rCL/strings.xml index 46e52aa740db..12f3d8331b9a 100644 --- a/WordPress/src/main/res/values-es-rCL/strings.xml +++ b/WordPress/src/main/res/values-es-rCL/strings.xml @@ -141,11 +141,6 @@ Language: es_CL No hay datos para este período Quita la ubicación de los medios No podemos abrir las estadísticas en este momento. Por favor inténtalo de nuevo más tarde - Desarrollado por TENOR - Algunos medios no pudieron cargarse debido a un error de red. - No hay medios que coincidan con tu búsqueda - ¡Busca para encontrar GIFs para añadirlos a tu Biblioteca de Medios! - Buscar en Tenor Vistas Autor Autores diff --git a/WordPress/src/main/res/values-es-rMX/strings.xml b/WordPress/src/main/res/values-es-rMX/strings.xml index a1a30fa3f85a..30e67c3e1442 100644 --- a/WordPress/src/main/res/values-es-rMX/strings.xml +++ b/WordPress/src/main/res/values-es-rMX/strings.xml @@ -614,11 +614,6 @@ Language: es_MX No hay datos en este periodo Eliminar la ubicación de los medios No podemos abrir las estadísticas en este momento. Por favor inténtalo de nuevo más tarde - Desarrollado por GIPHY - Algunos medios no se pudieron cargar debido a un error de red. - No hay medios que coincidan con tu búsqueda. - ¡Busca para encontrar GIFs para agregar a tu biblioteca de medios! - Buscar en Giphy Vistas Autor Autores diff --git a/WordPress/src/main/res/values-es-rVE/strings.xml b/WordPress/src/main/res/values-es-rVE/strings.xml index 5830e18a35ec..631d80afe381 100644 --- a/WordPress/src/main/res/values-es-rVE/strings.xml +++ b/WordPress/src/main/res/values-es-rVE/strings.xml @@ -614,11 +614,6 @@ Language: es_VE No hay datos en este periodo Eliminar la ubicación de los medios No podemos abrir las estadísticas en este momento. Por favor, inténtalo de nuevo más tarde - Creado por TENOR - Algunos medios no se cargaron debido a un error de red. - Ningún medio coincide con tu búsqueda - ¡Busca para encontrar GIFs para añadir a tu biblioteca de medios! - Buscar en Tenor Vistas Autor Autores diff --git a/WordPress/src/main/res/values-he/strings.xml b/WordPress/src/main/res/values-he/strings.xml index 235a65de90ae..ba4e1f233de8 100644 --- a/WordPress/src/main/res/values-he/strings.xml +++ b/WordPress/src/main/res/values-he/strings.xml @@ -557,11 +557,6 @@ Language: he_IL אין נתונים לתקופה זו הסרת מיקום ממדיה אין לנו אפשרות לפתוח את הנתונים הסטטיסטיים כעת. יש לנסות שוב מאוחר יותר - מופעל באמצעות TENOR - הטעינה של חלק מקובצי המדיה נכשלה עקב שגיאת רשת. - לא נמצאו פרטי מדיה שמתאימים לחיפוש שלך - חיפוש קובצי GIF שניתן להוסיף לספריית מדיה שלך! - חיפוש ב-Tenor צפיות מחבר מחברים diff --git a/WordPress/src/main/res/values-id/strings.xml b/WordPress/src/main/res/values-id/strings.xml index 715217197b40..8de1d426cf2b 100644 --- a/WordPress/src/main/res/values-id/strings.xml +++ b/WordPress/src/main/res/values-id/strings.xml @@ -554,11 +554,6 @@ Language: id Tidak ada data selama periode ini Hapus lokasi dari media Saat ini kami tidak dapat membuka statistik. Harap coba lagi nanti - Didukung oleh TENOR - Sebagian media gagal dimuat karena terdapat error jaringan. - Tidak ada media yang cocok dengan pencarian Anda - Cari GIF untuk ditambahkan ke Pustaka Media Anda! - Cari di Tenor Tampilan Penulis Penulis diff --git a/WordPress/src/main/res/values-it/strings.xml b/WordPress/src/main/res/values-it/strings.xml index c9823a468e51..0e624805d8fe 100644 --- a/WordPress/src/main/res/values-it/strings.xml +++ b/WordPress/src/main/res/values-it/strings.xml @@ -542,11 +542,6 @@ Language: it Nessun dato per questo periodo Rimuovi posizione dal contenuto multimediale Non è possibile aprire le statistiche. Riprova più tardi - Powered by TENOR - Alcuni caricamenti multimediali non sono riusciti a causa di un errore di rete. - Nessun media corrispondente alla tua ricerca - Cerca per trovare GIF da aggiungere alla tua Libreria multimediale! - Cerca in Tenor Visualizzazioni Autore Autori diff --git a/WordPress/src/main/res/values-ja/strings.xml b/WordPress/src/main/res/values-ja/strings.xml index 70e118404f6b..66413c7053a2 100644 --- a/WordPress/src/main/res/values-ja/strings.xml +++ b/WordPress/src/main/res/values-ja/strings.xml @@ -558,11 +558,6 @@ Language: ja_JP この期間のデータがありません メディアから位置情報を削除する 現在統計を開けません。後ほど、もう一度お試しください - Powered by TENOR - ネットワークエラーにより一部のメディアが読み込めませんでした。 - 検索と一致するメディアがありません - GIF を検索して、メディアライブラリに追加してください。 - Tenor を検索する 表示回数 投稿者 投稿者 diff --git a/WordPress/src/main/res/values-kmr/strings.xml b/WordPress/src/main/res/values-kmr/strings.xml index 19f0a4ed4a88..c7095da7f11d 100644 --- a/WordPress/src/main/res/values-kmr/strings.xml +++ b/WordPress/src/main/res/values-kmr/strings.xml @@ -302,11 +302,6 @@ Language: ku_TR Ji bo vê heyamê dane tune Ji medyayê cih rake Rêjejimar vêga nayên vekirin. Paştre dîsa biceribîne. - Bi piştevaniya GIPHYê - Ji ber çewtiya girêdanê barkirina hinek medyayan biserneket. - Lêgerîna te bi ti medyayan re hevber nebû - Ji bo tu GIFan tevlî PirtukxaneyaMedyayê bike, bigere! - Li ser Giphyê bigere Dîtin Nivîskar Nivîskar diff --git a/WordPress/src/main/res/values-ko/strings.xml b/WordPress/src/main/res/values-ko/strings.xml index 11c60644ea0f..471e218801fc 100644 --- a/WordPress/src/main/res/values-ko/strings.xml +++ b/WordPress/src/main/res/values-ko/strings.xml @@ -553,11 +553,6 @@ Language: ko_KR 이 기간에 데이터 없음 미디어에서 위치 제거 지금은 통계를 열 수 없습니다. 나중에 다시 시도해 주세요. - TENOR 제공 - 네트워크 오류로 인해 일부 미디어를 로드하지 못했습니다. - 검색과 일치하는 미디어 없음 - GIF를 검색하여 미디어 라이브러리에 추가하세요! - Tenor 검색 조회수 글쓴이 글쓴이 diff --git a/WordPress/src/main/res/values-nb/strings.xml b/WordPress/src/main/res/values-nb/strings.xml index 8ee7181c2d85..21da82b50980 100644 --- a/WordPress/src/main/res/values-nb/strings.xml +++ b/WordPress/src/main/res/values-nb/strings.xml @@ -530,11 +530,6 @@ Language: nb_NO Ingen data for denne perioden Fjern dette stedet fra media Vi kan ikke åpne statistikken i øyeblikket. Vennligst prøv igjen senere - Drevet av TENOR - Noe media kunne ikke lastes på grunn av en nettverksfeil. - Ingen media passet ditt søk - Søk for å finne GIF-er å legge til i ditt mediebibliotek! - Søk Tenor Visninger Forfatter Forfattere diff --git a/WordPress/src/main/res/values-nl/strings.xml b/WordPress/src/main/res/values-nl/strings.xml index b5a922b6cffb..06952a24e903 100644 --- a/WordPress/src/main/res/values-nl/strings.xml +++ b/WordPress/src/main/res/values-nl/strings.xml @@ -512,8 +512,6 @@ Language: nl Geen gegevens voor deze periode Locatie van media verwijderen We kunnen de statistieken momenteel niet openen. Probeer het later opnieuw - Mogelijk gemaakt door TENOR - Zoek op Tenor Auteur Auteurs Zoekterm diff --git a/WordPress/src/main/res/values-pl/strings.xml b/WordPress/src/main/res/values-pl/strings.xml index 5ff49353a203..f24f07bd4b4a 100644 --- a/WordPress/src/main/res/values-pl/strings.xml +++ b/WordPress/src/main/res/values-pl/strings.xml @@ -610,11 +610,6 @@ Language: pl Brak danych dla tego okresu Usuń lokalizację GPS z plików mediów Nie możemy w tym momencie otworzyć statystyk. Spróbuj ponownie później - Wspierane przez TENOR - Niektórych plików mediów nie udało się przesłać z powodu błędu sieci. - Brak plików mediów dopasowanych do twojego zapytania - Przeszukaj aby znaleźć pliki GIF które możesz dodać do swojej biblioteki mediów! - Przeszukaj Tenor Wyświetleń Autor Autorzy diff --git a/WordPress/src/main/res/values-pt-rBR/strings.xml b/WordPress/src/main/res/values-pt-rBR/strings.xml index 814a6fba2a7e..4fa08504a000 100644 --- a/WordPress/src/main/res/values-pt-rBR/strings.xml +++ b/WordPress/src/main/res/values-pt-rBR/strings.xml @@ -559,11 +559,6 @@ Language: pt_BR Nenhum dado para esse período Remover localização de mídia Não conseguimos abrir as estatísticas agora. Tente novamente mais tarde. - Oferecido pelo TENOR - Alguns arquivos não puderam ser carregados devido a problemas com a conexão. - Nenhuma mídia corresponde à sua pesquisa - Pesquise para encontrar gifs para adicionar à sua biblioteca de mídias. - Pesquisar no Tenor Visualizações Autor Autores diff --git a/WordPress/src/main/res/values-ro/strings.xml b/WordPress/src/main/res/values-ro/strings.xml index 2fe651e06123..41bef6b1b2e9 100644 --- a/WordPress/src/main/res/values-ro/strings.xml +++ b/WordPress/src/main/res/values-ro/strings.xml @@ -614,11 +614,6 @@ Language: ro Nu există date pentru această perioadă Înlătură locația din Media Pentru moment, nu putem deschide statisticile. Te rog reîncearcă mai târziu - Propulsat de TENOR - Unele elemente media au eșuat la încărcare din cauza unei erori de rețea. - Nu s-a potrivit niciun element media cu căutarea ta - Caută pentru a găsi imagini GIF pe care să le adaugi în Biblioteca ta media! - Caută cu Tenor Vizualizări Autor Autori diff --git a/WordPress/src/main/res/values-ru/strings.xml b/WordPress/src/main/res/values-ru/strings.xml index b3a98f261e85..dab84cf0079b 100644 --- a/WordPress/src/main/res/values-ru/strings.xml +++ b/WordPress/src/main/res/values-ru/strings.xml @@ -614,11 +614,6 @@ Language: ru Для указанного периода нет данных Убрать данные местоположения из медиафайлов Извините, статистика в данный момент недоступна, попробуйте позже. - Работает с TENOR - Некоторые медиафайлы не загрузились из-за ошибки сети. - Мультимедиа по критериям поиска не найдены - Найдите GIF изображения и добавьте их в медиатеку! - Поиск в Tenor Просмотры Автор Авторы diff --git a/WordPress/src/main/res/values-sk/strings.xml b/WordPress/src/main/res/values-sk/strings.xml index db12bd87dfa7..a3e156cfd385 100644 --- a/WordPress/src/main/res/values-sk/strings.xml +++ b/WordPress/src/main/res/values-sk/strings.xml @@ -44,8 +44,6 @@ Language: sk Vrátiť späť Žiadne dáta pre toto obdobie Odstrániť lokáciu z médiá - Poháňa TENOR - Vyhľadať v Tenor Zobrazenia Autor Autori diff --git a/WordPress/src/main/res/values-sq/strings.xml b/WordPress/src/main/res/values-sq/strings.xml index 447d428ebcc9..6e5b160f3be8 100644 --- a/WordPress/src/main/res/values-sq/strings.xml +++ b/WordPress/src/main/res/values-sq/strings.xml @@ -614,11 +614,6 @@ Language: sq_AL S’ka të dhëna për këtë periudhë Hiqe vendndodhjen prej mediash S’i hapim dot statistikat tani. Ju lutemi, riprovoni më vonë - Bazuar në Tenor - Dështoi ngarkimi për ca media, për shkak të një gabimi rrjeti. - S’ka media që përputhet me kërkimin tuaj - Kërkoni për të gjetur GIF-e që t’i shtoni te Mediateka juaj! - Kërkoni në Tenor Parje Autor Autorë diff --git a/WordPress/src/main/res/values-sv/strings.xml b/WordPress/src/main/res/values-sv/strings.xml index b34959fca4b1..232991df40b7 100644 --- a/WordPress/src/main/res/values-sv/strings.xml +++ b/WordPress/src/main/res/values-sv/strings.xml @@ -614,11 +614,6 @@ Language: sv_SE Inga uppgifter för denna tidsperiod Avlägsna position från media Just nu går det inte att öppna statistiken. Försök igen senare - Drivs med hjälp av TENOR - Vissa mediefiler kunde inte laddas på grund av nätverksproblem. - Inga media matchar din sökning - Leta efter GIF-filer du kan lägga till i ditt mediebibliotek! - Sök i Tenor Visningar Författare Författare diff --git a/WordPress/src/main/res/values-tr/strings.xml b/WordPress/src/main/res/values-tr/strings.xml index 4e2f029b6dca..b84be1ff01b5 100644 --- a/WordPress/src/main/res/values-tr/strings.xml +++ b/WordPress/src/main/res/values-tr/strings.xml @@ -559,11 +559,6 @@ Language: tr Bu dönem için veri yok Ortam dosyasından konum bilgisini kaldır Şu anda istatistikleri açamıyoruz. Lütfen daha sonra tekrar deneyiniz. - TENOR tarafından sağlanır - Ağ hatası nedeniyle bazı ortam dosyaları yüklenemedi. - Aramanızla eşleşen bir ortam yok - Ortam kütüphanenize GIF bulup eklemek için arayın! - Tenor\'de ara Görüntülemeler Yazar Yazarlar diff --git a/WordPress/src/main/res/values-zh-rCN/strings.xml b/WordPress/src/main/res/values-zh-rCN/strings.xml index e91e375f5a50..998d5617ec3c 100644 --- a/WordPress/src/main/res/values-zh-rCN/strings.xml +++ b/WordPress/src/main/res/values-zh-rCN/strings.xml @@ -502,11 +502,6 @@ Language: zh_CN 没有此时间段的数据 从媒体删除位置信息 我们现在无法打开统计信息。请稍后重试 - 由 TENOR 提供支持 - 由于网络错误,无法加载某些媒体。 - 没有与您的搜索匹配的媒体 - 搜索查找要添加到您的媒体库中的 GIF! - 搜索 Tenor 浏览量 作者 作者 diff --git a/WordPress/src/main/res/values-zh-rHK/strings.xml b/WordPress/src/main/res/values-zh-rHK/strings.xml index bc404074e04c..097b6a04c581 100644 --- a/WordPress/src/main/res/values-zh-rHK/strings.xml +++ b/WordPress/src/main/res/values-zh-rHK/strings.xml @@ -549,11 +549,6 @@ Language: zh_TW 此期間沒有資料 從媒體移除位置資訊 目前我們無法開啟統計資料。請稍後再試一次 - 由 TENOR 建置 - 網路發生錯誤,導致部份媒體載入失敗。 - 沒有符合你搜尋條件的媒體 - 搜尋免費 GIF 以新增至你的媒體庫! - 搜尋 Tenor 瀏覽數 作者 作者 diff --git a/WordPress/src/main/res/values-zh-rTW/strings.xml b/WordPress/src/main/res/values-zh-rTW/strings.xml index bc404074e04c..097b6a04c581 100644 --- a/WordPress/src/main/res/values-zh-rTW/strings.xml +++ b/WordPress/src/main/res/values-zh-rTW/strings.xml @@ -549,11 +549,6 @@ Language: zh_TW 此期間沒有資料 從媒體移除位置資訊 目前我們無法開啟統計資料。請稍後再試一次 - 由 TENOR 建置 - 網路發生錯誤,導致部份媒體載入失敗。 - 沒有符合你搜尋條件的媒體 - 搜尋免費 GIF 以新增至你的媒體庫! - 搜尋 Tenor 瀏覽數 作者 作者 From a27b47ab1a305917983b59087e095c5a317cc1e3 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 1 Apr 2020 21:26:34 -0300 Subject: [PATCH 49/58] Added local tenor feature flag through BuildConfig --- WordPress/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 9c0b58418299..03e84d63dc8c 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -67,6 +67,7 @@ android { testInstrumentationRunner 'org.wordpress.android.WordPressTestRunner' buildConfigField "boolean", "OFFER_GUTENBERG", "true" + buildConfigField "boolean", "TENOR_AVAILABLE", "false" } // Gutenberg's dependency - react-native-video is using @@ -98,6 +99,7 @@ android { wasabi { // "hot" version, can be installed along release, alpha or beta versions applicationId "org.wordpress.android.beta" dimension "buildType" + buildConfigField "boolean", "TENOR_AVAILABLE", "true" } } From dfc607f66a8026393a7fae6916590b5fb49d3a3e Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 1 Apr 2020 21:29:03 -0300 Subject: [PATCH 50/58] Added Tenor selection availability through BuildConfig inside EditPostActivity --- .../android/ui/photopicker/PhotoPickerFragment.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java index cb0283615c2c..7b3cbb4032d4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/photopicker/PhotoPickerFragment.java @@ -24,6 +24,7 @@ import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import org.wordpress.android.BuildConfig; import org.wordpress.android.R; import org.wordpress.android.WordPress; import org.wordpress.android.analytics.AnalyticsTracker; @@ -300,11 +301,13 @@ public boolean onMenuItemClick(MenuItem item) { } }); - MenuItem itemGif = popup.getMenu().add(R.string.photo_picker_gif); - itemGif.setOnMenuItemClickListener(item -> { - doIconClicked(PhotoPickerIcon.GIF); - return true; - }); + if (BuildConfig.TENOR_AVAILABLE) { + MenuItem itemGif = popup.getMenu().add(R.string.photo_picker_gif); + itemGif.setOnMenuItemClickListener(item -> { + doIconClicked(PhotoPickerIcon.GIF); + return true; + }); + } } popup.show(); From 4a0cc138ac797cf7da8d2131a69d37a6a6e34a1b Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 1 Apr 2020 21:29:45 -0300 Subject: [PATCH 51/58] Added Tenor selection availability through BuildConfig inside MediaBrowserActivity --- .../org/wordpress/android/ui/media/MediaBrowserActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java index a59279aac169..fad5d85fb0c2 100755 --- a/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/media/MediaBrowserActivity.java @@ -887,7 +887,7 @@ public void showAddMediaPopup() { }); } - if (mBrowserType.isBrowser()) { + if (mBrowserType.isBrowser() && BuildConfig.TENOR_AVAILABLE) { popup.getMenu().add(R.string.photo_picker_gif).setOnMenuItemClickListener( item -> { doAddMediaItemClicked(AddMenuItem.ITEM_CHOOSE_GIF); From d5122436caf1507f7accdcac27e492082d8cbff6 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Wed, 1 Apr 2020 23:31:04 -0300 Subject: [PATCH 52/58] Added the Tenor availability to the alpha build --- WordPress/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 03e84d63dc8c..340aa48311c3 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -67,7 +67,7 @@ android { testInstrumentationRunner 'org.wordpress.android.WordPressTestRunner' buildConfigField "boolean", "OFFER_GUTENBERG", "true" - buildConfigField "boolean", "TENOR_AVAILABLE", "false" + buildConfigField "boolean", "TENOR_AVAILABLE", "true" } // Gutenberg's dependency - react-native-video is using @@ -88,6 +88,7 @@ android { } versionCode 845 buildConfigField "boolean", "ME_ACTIVITY_AVAILABLE", "false" + buildConfigField "boolean", "TENOR_AVAILABLE", "false" } zalpha { // alpha version - enable experimental features @@ -99,7 +100,6 @@ android { wasabi { // "hot" version, can be installed along release, alpha or beta versions applicationId "org.wordpress.android.beta" dimension "buildType" - buildConfigField "boolean", "TENOR_AVAILABLE", "true" } } From 41cdfaf03139284ae350b9cfa5937fb8982b889c Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 3 Apr 2020 19:25:38 -0300 Subject: [PATCH 53/58] Added Tenor library license attribution --- WordPress/src/main/assets/licenses.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/WordPress/src/main/assets/licenses.html b/WordPress/src/main/assets/licenses.html index fb28beaa1cb2..73e104be88dc 100644 --- a/WordPress/src/main/assets/licenses.html +++ b/WordPress/src/main/assets/licenses.html @@ -34,6 +34,7 @@

Additional Libraries

  • okio/okhttp: Copyright 2013 Square, Inc.
  • EventBus: Copyright 2012-2016 Markus Junginger, greenrobot
  • Mobile 4 Media: Copyright 2016, INDExOS
  • +
  • Tenor Android Core: Copyright 2017, Tenor Inc

  • @@ -44,10 +45,5 @@

    Additional Libraries

  • GraphView: Copyright 2013, Jonas Gehring
  • -

    The following is licensed under Mozilla Public License Version 2.0

    - - From f3bf4e3877dbd9806fe198170d80284f11526835 Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 3 Apr 2020 22:41:39 -0300 Subject: [PATCH 54/58] Fixed checkstyle errors --- .../android/viewmodel/gif/GifPickerDataSourceFactory.kt | 4 +++- .../android/viewmodel/gif/GifPickerDataSourceTest.kt | 6 +++--- .../android/viewmodel/gif/provider/TenorProviderTest.kt | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt index 07104445195f..30546f9a4177 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceFactory.kt @@ -17,7 +17,9 @@ import javax.inject.Inject * 2. The [LivePagedListBuilder] will create a new [GifPickerDataSource] by calling [create] * 3. The new [GifPickerDataSource] will start another paged API request */ -class GifPickerDataSourceFactory @Inject constructor(private val gifProvider: GifProvider) : Factory() { +class GifPickerDataSourceFactory @Inject constructor( + private val gifProvider: GifProvider +) : Factory() { /** * The active search query. * diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt index 6b58e5ea3aee..cda0efc1d200 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/GifPickerDataSourceTest.kt @@ -88,7 +88,7 @@ class GifPickerDataSourceTest { } @Test - fun `loadInitial should call onResult with correct position when search is successful but next position is incorrect`() { + fun `loadInitial should call onResult with position when search is successful but next position is incorrect`() { var onResultWasCalled = false val params = LoadInitialParams(0, 20, 5, false) @@ -195,7 +195,7 @@ class GifPickerDataSourceTest { var onResultWasCalled = false val params = LoadRangeParams(0, 20) - val dataSourceCallback = object: LoadRangeCallback() { + val dataSourceCallback = object : LoadRangeCallback() { override fun onResult(data: MutableList) { onResultWasCalled = true assertThat(data).isEqualTo(expectedGifMediaViewModelCollection) @@ -214,7 +214,7 @@ class GifPickerDataSourceTest { val spiedDataSource = spy(pickerDataSourceUnderTest) val params = LoadRangeParams(0, 20) - val dataSourceCallback = object: LoadRangeCallback() { + val dataSourceCallback = object : LoadRangeCallback() { override fun onResult(data: MutableList) {} } spiedDataSource.loadRange(params, dataSourceCallback) diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt index e5ce3747249d..109a17270817 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt @@ -11,7 +11,6 @@ import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.ApiService.Builder import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.impl.GifsResponse -import kotlinx.coroutines.ExperimentalCoroutinesApi import org.assertj.core.api.Assertions.assertThat import org.junit.Assert.fail import org.junit.Before From 2ad832ac6dea80780a4e99c78dfb677883d06a8e Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Fri, 3 Apr 2020 23:00:10 -0300 Subject: [PATCH 55/58] Replaced UI string usage for Exception for internal constant string --- .../wordpress/android/viewmodel/gif/provider/TenorProvider.kt | 3 ++- WordPress/src/main/res/values/strings.xml | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index 84877aee1d40..acd7f83558ee 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -55,7 +55,7 @@ internal class TenorProvider constructor( onSuccess(gifList, nextPosition) }, onFailure = { - val errorMessage = it?.message ?: context.getString(string.gif_list_search_returned_unknown_error) + val errorMessage = it?.message ?: DEFAULT_EXCEPTION_MESSAGE onFailure(GifRequestFailedException(errorMessage)) } ) @@ -145,5 +145,6 @@ internal class TenorProvider constructor( * To better refers to the Tenor API maximum GIF limit per request */ private const val MAXIMUM_ALLOWED_LOAD_SIZE = 50 + private const val DEFAULT_EXCEPTION_MESSAGE = "Sorry, there was a problem" } } diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 82cc6b542cc6..d63be1f52c57 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2259,7 +2259,6 @@ Search to find GIFs to add to your Media Library! No media matching your search Some media failed to load due to a network error. - Sorry, there was a problem Powered by Tenor From ceac8979e866b71b351fe5f3d3eac9f4ab88c1ba Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Sat, 4 Apr 2020 19:23:30 -0300 Subject: [PATCH 56/58] Removed UI string usage from the exception for empty search result inside Tenor --- .../android/viewmodel/gif/provider/TenorProvider.kt | 12 ++++++++---- .../viewmodel/gif/provider/TenorProviderTest.kt | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index acd7f83558ee..e2a6c18f7f51 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -9,7 +9,6 @@ import com.tenor.android.core.model.impl.Result import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.impl.GifsResponse -import org.wordpress.android.R.string import org.wordpress.android.viewmodel.gif.GifMediaViewModel import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException @@ -78,8 +77,8 @@ internal class TenorProvider constructor( ) = buildSearchCall(query, loadSize, position).apply { enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { - val defaultErrorMessage = context.getString(string.gif_picker_empty_search_list) - response.body()?.let(onSuccess) ?: onFailure(GifRequestFailedException(defaultErrorMessage)) + response.body()?.let(onSuccess) ?: onFailure(GifRequestFailedException( + SEARCH_FOUND_NOTHING_EXCEPTION_MESSAGE)) } override fun onFailure(call: Call, throwable: Throwable) { @@ -145,6 +144,11 @@ internal class TenorProvider constructor( * To better refers to the Tenor API maximum GIF limit per request */ private const val MAXIMUM_ALLOWED_LOAD_SIZE = 50 - private const val DEFAULT_EXCEPTION_MESSAGE = "Sorry, there was a problem" + + /** + * Exception messages the ones that TenorProvider can create + */ + private const val DEFAULT_EXCEPTION_MESSAGE = "There was a problem handling the request" + private const val SEARCH_FOUND_NOTHING_EXCEPTION_MESSAGE = "No media found for this search query" } } diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt index 109a17270817..4a4087dc942d 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt @@ -142,7 +142,7 @@ class TenorProviderTest { onFailure = { throwable -> onFailureWasCalled = true assertThat(throwable).isInstanceOf(GifRequestFailedException::class.java) - assertThat(throwable.message).isEqualTo("No media matching your search") + assertThat(throwable.message).isEqualTo("No media found for this search query") }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) From 0c09c88d77d77acd9a152dad0546e9093563578b Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 7 Apr 2020 00:06:33 -0300 Subject: [PATCH 57/58] Revert TenorProvider string usage with lint unused suppression --- .../viewmodel/gif/provider/TenorProvider.kt | 14 +++++--------- WordPress/src/main/res/values/strings.xml | 7 +++++-- .../viewmodel/gif/provider/TenorProviderTest.kt | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt index e2a6c18f7f51..de6c56718267 100644 --- a/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt +++ b/WordPress/src/main/java/org/wordpress/android/viewmodel/gif/provider/TenorProvider.kt @@ -9,6 +9,7 @@ import com.tenor.android.core.model.impl.Result import com.tenor.android.core.network.ApiClient import com.tenor.android.core.network.IApiClient import com.tenor.android.core.response.impl.GifsResponse +import org.wordpress.android.R import org.wordpress.android.viewmodel.gif.GifMediaViewModel import org.wordpress.android.viewmodel.gif.MutableGifMediaViewModel import org.wordpress.android.viewmodel.gif.provider.GifProvider.GifRequestFailedException @@ -54,7 +55,8 @@ internal class TenorProvider constructor( onSuccess(gifList, nextPosition) }, onFailure = { - val errorMessage = it?.message ?: DEFAULT_EXCEPTION_MESSAGE + val errorMessage = it?.message + ?: context.getString(R.string.gif_list_search_returned_unknown_error) onFailure(GifRequestFailedException(errorMessage)) } ) @@ -77,8 +79,8 @@ internal class TenorProvider constructor( ) = buildSearchCall(query, loadSize, position).apply { enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { - response.body()?.let(onSuccess) ?: onFailure(GifRequestFailedException( - SEARCH_FOUND_NOTHING_EXCEPTION_MESSAGE)) + val errorMessage = context.getString(R.string.gif_picker_empty_search_list) + response.body()?.let(onSuccess) ?: onFailure(GifRequestFailedException(errorMessage)) } override fun onFailure(call: Call, throwable: Throwable) { @@ -144,11 +146,5 @@ internal class TenorProvider constructor( * To better refers to the Tenor API maximum GIF limit per request */ private const val MAXIMUM_ALLOWED_LOAD_SIZE = 50 - - /** - * Exception messages the ones that TenorProvider can create - */ - private const val DEFAULT_EXCEPTION_MESSAGE = "There was a problem handling the request" - private const val SEARCH_FOUND_NOTHING_EXCEPTION_MESSAGE = "No media found for this search query" } } diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index d63be1f52c57..fda6b28d4054 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2256,10 +2256,13 @@ Search Tenor + Powered by Tenor Search to find GIFs to add to your Media Library! - No media matching your search Some media failed to load due to a network error. - Powered by Tenor + + No media matching your search + + There was a problem handling the request Saving post as draft diff --git a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt index 4a4087dc942d..109a17270817 100644 --- a/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/viewmodel/gif/provider/TenorProviderTest.kt @@ -142,7 +142,7 @@ class TenorProviderTest { onFailure = { throwable -> onFailureWasCalled = true assertThat(throwable).isInstanceOf(GifRequestFailedException::class.java) - assertThat(throwable.message).isEqualTo("No media found for this search query") + assertThat(throwable.message).isEqualTo("No media matching your search") }) verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) From 13e88ec3e3e7b2ab3ac19a4419cf65067715602e Mon Sep 17 00:00:00 2001 From: Thomaz Cortez Date: Tue, 7 Apr 2020 09:09:07 -0300 Subject: [PATCH 58/58] Changed the unused resources suppression declaration --- WordPress/src/main/res/values/strings.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index fda6b28d4054..3e59d06a4e75 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2259,10 +2259,8 @@ Powered by Tenor Search to find GIFs to add to your Media Library! Some media failed to load due to a network error. - - No media matching your search - - There was a problem handling the request + No media matching your search + There was a problem handling the request Saving post as draft