Tenor API integrated with GIF Picker#1
Tenor API integrated with GIF Picker#1ThomazFB merged 30 commits intoissue/11456-add-tenor-supportfrom
Conversation
…ed to the PickerDataSourceFactory
…ewModel and GifPickerDataSource
…dded more documentation
…dded more documentation
…eature/insert-tenor-api
planarvoid
left a comment
There was a problem hiding this comment.
thanks for the changes! Overall it looks really good 👍 I have some comments, feel free to let me know what you think.
I've encountered a crash when searching for the string "isengard" (don't ask me why):
java.lang.IllegalArgumentException: PositionalDataSource requires initial load size to be a multiple of page size to support internal tiling. loadSize 3, position 0, totalCount 4, pageSize 21
at androidx.paging.PositionalDataSource$LoadInitialCallbackImpl.onResult(PositionalDataSource.java:223)
at org.wordpress.android.viewmodel.giphy.GiphyPickerDataSource$requestInitialSearch$1.invoke(GiphyPickerDataSource.kt:91)
at org.wordpress.android.viewmodel.giphy.GiphyPickerDataSource$requestInitialSearch$1.invoke(GiphyPickerDataSource.kt:14)
at org.wordpress.android.viewmodel.giphy.provider.TenorProvider$search$$inlined$simpleSearch$1.success(TenorProvider.kt:195)
at org.wordpress.android.viewmodel.giphy.provider.TenorProvider$search$$inlined$simpleSearch$1.success(TenorProvider.kt:104)
at com.tenor.android.core.response.WeakRefCallback.success(WeakRefCallback.java:184)
at com.tenor.android.core.response.WeakRefCallback.access$100(WeakRefCallback.java:30)
at com.tenor.android.core.response.WeakRefCallback$1.run(WeakRefCallback.java:88)
at com.tenor.android.core.weakref.WeakRefRunnable.run(WeakRefRunnable.java:34)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
| import com.tenor.android.core.model.impl.Result | ||
| import org.wordpress.android.viewmodel.giphy.MutableGiphyMediaViewModel | ||
|
|
||
| class TenorProviderTestUtils { |
There was a problem hiding this comment.
I think it would be cleaner to make this an object and remove the companion object.
And personally I'd call this class Fixtures even though I see there is no Fixture class yet in the WPAndroid project.
There was a problem hiding this comment.
I liked a lot your suggestion for Fixture nomenclature, it makes a lot more sense. Maybe we could suggest starting inserting this kind of unit test code from now on? I've committed the change in 61e7bca. What do you think?
| verify(gifSearchCall, times(1)).enqueue(callbackCaptor.capture()) | ||
| val capturedCallback = callbackCaptor.value | ||
| capturedCallback.success(ApplicationProvider.getApplicationContext(), gifResponse) | ||
| assertTrue("onSuccess should be called", onSuccessWasCalled) |
There was a problem hiding this comment.
I usually prefer usage of assertThat(onSuccessWasCalled).isTrue() from the org.assertj.core.api.Assertions.assertThat package. This is not very important but it tends to be more readable if you have more than one assertion.
There was a problem hiding this comment.
Awesome suggestion, it really improves the assertion readability, it's done! Changed in 11fde9b.
| * the init will use the default implementation provided by the Tenor library. | ||
| */ | ||
| init { | ||
| ApiService.Builder(context, IApiClient::class.java).apply { |
There was a problem hiding this comment.
I was wondering about initializing the api client in the init method. I was thinking that maybe it might be nicer to either do it in the ApplicationModule and directly inject the proper ApiClient or if this doesn't work, use the laze initialization on the apiClient by lazy {}.
There was a problem hiding this comment.
Nice! Makes a lot of sense, I was intentionally trying to keep the API configuration inside the Provider, but your suggestion to initializing it inside the ApplicationModule created an opening for a more concise dependency construction inside the TenorProvider. Thanks! The change is committed at 0b7035d.
There was a problem hiding this comment.
Thanks for the change! I think both options (application module and kotlin lazy load) would be fine, it just felt that the init is somehow between these two approaches 👍
|
|
||
| internal class TenorProvider @JvmOverloads constructor( | ||
| val context: Context, | ||
| tenorClient: IApiClient? = null |
There was a problem hiding this comment.
Is this field planned to be injected? Or could it be removed?
There was a problem hiding this comment.
This field was created to make an easy opening for unit tests but allowing it as an optional value without disregard the API initialization. I think the change at 0b7035d already solved this point since the initialization of the API is now being made outside the TenorProvider, at the ApplicationModule, and the injection of the IApiClient happens right there after the API key configuration.
What do you think?
There was a problem hiding this comment.
good point about the unit tests, I like the way it's done now
| /** | ||
| * To better refers to the Tenor API maximum GIF limit per request | ||
| */ | ||
| private val maximumAllowedLoadSize = 50 |
There was a problem hiding this comment.
Just for consistency, I'd move this to the companion object and use snake case.
| .setEnablePlaceholders(false) | ||
| .setPrefetchDistance(15) | ||
| .setInitialLoadSizeHint(42) | ||
| .setPageSize(21) |
There was a problem hiding this comment.
Maybe pull out all of these constants to a companion object?
…actored the class to become a object
Hi @planarvoid! Thank you for your review! I replied to every conversation with the proposed fix! About this crash, it was a desync between the position track returned by Tenor and our PositionalDataSource when a small list of GIFs is returned for a given query, so the reason why "isengard" was crashing the app is that this query only returns 3 GIFs, triggering this bug. With that said, I made the DataSource more resilient to this kind of scenario. The change is committed in f7ec187. |
Summary
This Pull Request brings integration for the Tenor API within the pre-existent GIF selection code inside the app. As described at issue 11456.
The solution proposes the following implementation:
A
GifProviderinterface must be the only coupling between all code for the GIF picker and the Tenor implementation, avoiding any reference to the Tenor library and making it easy to replace the Provider as we're doing nowThe
TenorProviderimplements theGifProviderinterface and is injected within theDataSourcevia Dagger, this way only theAppModuleknows about theTenorProvider. Also, theTenorProvideris covered by unit tests in theTenorProviderTestclass.The already implemented pagination feature and list actions are all kept and integrated to work smoothly with the
GifProvider, this integration happens through the availablePositionalDataSource, The Tenor implementation makes sure that positioning tracking is respectedThe original integration with the
MediaBrowserActivitywas restored, making GIF selection available againKnown missing points for upcoming Pull Requests
EditPostActivitynot restored yetTesting
wp.tenor.api_keyas the value inside yourgradle.propertiesChoose from Tenoroptionselection,previewandaddare all working as expectedPR submission checklist
RELEASE-NOTES.txtif necessary.