This repository has been archived by the owner on May 26, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #203 from Vacxe/feature/view_pager_2
Feature support for ViewPager2
- Loading branch information
Showing
19 changed files
with
550 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
kakao/src/main/kotlin/com/agoda/kakao/common/matchers/ViewPager2AdapterSizeMatcher.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
@file:Suppress("unused") | ||
|
||
package com.agoda.kakao.common.matchers | ||
|
||
import android.view.View | ||
import androidx.test.espresso.matcher.BoundedMatcher | ||
import androidx.viewpager2.widget.ViewPager2 | ||
import org.hamcrest.Description | ||
|
||
/** | ||
* Matches ViewPager2 with count of children | ||
* | ||
* @param size of children count in ViewPager2 | ||
*/ | ||
class ViewPager2AdapterSizeMatcher(private val size: Int) : BoundedMatcher<View, ViewPager2>(ViewPager2::class.java) { | ||
|
||
private var itemCount: Int = 0 | ||
|
||
override fun matchesSafely(view: ViewPager2) = run { | ||
itemCount = view.adapter?.itemCount ?: 0 | ||
itemCount == size | ||
} | ||
|
||
override fun describeTo(description: Description) { | ||
description | ||
.appendText("ViewPager2 with ") | ||
.appendValue(size) | ||
.appendText(" item(s), but got with ") | ||
.appendValue(itemCount) | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
kakao/src/main/kotlin/com/agoda/kakao/pager2/KEmptyViewPagerItem.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
@file:Suppress("unused") | ||
|
||
package com.agoda.kakao.pager2 | ||
|
||
import android.view.View | ||
import org.hamcrest.Matcher | ||
|
||
/** | ||
* Empty implementation of KViewPagerItem | ||
* | ||
* Use this if you want to perform/assert on the root view of view holder | ||
* | ||
* @param parent Matcher of the root view of view holder | ||
* @see KViewPagerItem | ||
*/ | ||
class KEmptyViewPagerItem(parent: Matcher<View>) : KViewPagerItem<KEmptyViewPagerItem>(parent) |
132 changes: 132 additions & 0 deletions
132
kakao/src/main/kotlin/com/agoda/kakao/pager2/KViewPager2.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
@file:Suppress("unused") | ||
|
||
package com.agoda.kakao.pager2 | ||
|
||
import android.view.View | ||
import androidx.test.espresso.DataInteraction | ||
import androidx.test.espresso.Root | ||
import androidx.test.espresso.matcher.RootMatchers | ||
import com.agoda.kakao.common.KakaoDslMarker | ||
import com.agoda.kakao.common.actions.SwipeableActions | ||
import com.agoda.kakao.common.assertions.BaseAssertions | ||
import com.agoda.kakao.common.builders.ViewBuilder | ||
import com.agoda.kakao.delegate.ViewInteractionDelegate | ||
import org.hamcrest.Matcher | ||
import kotlin.reflect.KClass | ||
|
||
/** | ||
* View with SwipeableActions and ViewPager2Assertions | ||
* | ||
* @see SwipeableActions | ||
*/ | ||
@KakaoDslMarker | ||
class KViewPager2 : ViewPager2Actions, ViewPager2AdapterAssertions, SwipeableActions, BaseAssertions { | ||
val matcher: Matcher<View> | ||
val itemTypes: Map<KClass<out KViewPagerItem<*>>, KViewPagerItemType<KViewPagerItem<*>>> | ||
|
||
override val view: ViewInteractionDelegate | ||
override var root: Matcher<Root> = RootMatchers.DEFAULT | ||
|
||
/** | ||
* Constructs view class with view interaction from given ViewBuilder | ||
* | ||
* @param builder ViewBuilder which will result in view's interaction | ||
* @param itemTypeBuilder Lambda with receiver where you pass your item providers | ||
* | ||
* @see ViewBuilder | ||
*/ | ||
constructor(builder: ViewBuilder.() -> Unit, itemTypeBuilder: KViewPagerItemTypeBuilder.() -> Unit) { | ||
val vb = ViewBuilder().apply(builder) | ||
matcher = vb.getViewMatcher() | ||
view = vb.getViewInteractionDelegate() | ||
itemTypes = KViewPagerItemTypeBuilder().apply(itemTypeBuilder).itemTypes | ||
} | ||
|
||
/** | ||
* Constructs view class with parent and view interaction from given ViewBuilder | ||
* | ||
* @param parent Matcher that will be used as parent in isDescendantOfA() matcher | ||
* @param builder ViewBuilder which will result in view's interaction | ||
* @param itemTypeBuilder Lambda with receiver where you pass your item providers | ||
* | ||
* @see ViewBuilder | ||
*/ | ||
constructor( | ||
parent: Matcher<View>, builder: ViewBuilder.() -> Unit, | ||
itemTypeBuilder: KViewPagerItemTypeBuilder.() -> Unit | ||
) : this({ | ||
isDescendantOfA { withMatcher(parent) } | ||
builder(this) | ||
}, itemTypeBuilder) | ||
|
||
/** | ||
* Constructs view class with parent and view interaction from given ViewBuilder | ||
* | ||
* @param parent DataInteraction that will be used as parent to ViewBuilder | ||
* @param builder ViewBuilder which will result in view's interaction | ||
* @param itemTypeBuilder Lambda with receiver where you pass your item providers | ||
* | ||
* @see ViewBuilder | ||
*/ | ||
@Suppress("UNCHECKED_CAST") | ||
constructor( | ||
parent: DataInteraction, builder: ViewBuilder.() -> Unit, | ||
itemTypeBuilder: KViewPagerItemTypeBuilder.() -> Unit | ||
) { | ||
val makeTargetMatcher = DataInteraction::class.java.getDeclaredMethod("makeTargetMatcher") | ||
val parentMatcher = makeTargetMatcher.invoke(parent) | ||
|
||
val vb = ViewBuilder().apply { | ||
isDescendantOfA { withMatcher(parentMatcher as Matcher<View>) } | ||
builder(this) | ||
} | ||
|
||
matcher = vb.getViewMatcher() | ||
view = vb.getViewInteractionDelegate() | ||
itemTypes = KViewPagerItemTypeBuilder().apply(itemTypeBuilder).itemTypes | ||
} | ||
|
||
/** | ||
* Performs given actions/assertion on child at given position | ||
* | ||
* @param T Type of item at given position. Must be registered via constructor. | ||
* @param position Position of item in adapter | ||
* @param function Tail lambda which receiver will be matched item with given type T | ||
*/ | ||
inline fun <reified T : KViewPagerItem<*>> childAt(position: Int, function: T.() -> Unit) { | ||
val provideItem = itemTypes.getOrElse(T::class) { | ||
throw IllegalStateException("${T::class.java.simpleName} did not register to KViewPager2") | ||
}.provideItem | ||
|
||
try { | ||
scrollTo(position) | ||
} catch (error: Throwable) { | ||
} | ||
|
||
function(provideItem(matcher) as T).also { inRoot { withMatcher(this@KViewPager2.root) } } | ||
} | ||
|
||
/** | ||
* Operator that allows usage of DSL style | ||
* | ||
* @param function Tail lambda with receiver which is your view | ||
*/ | ||
operator fun invoke(function: KViewPager2.() -> Unit) { | ||
function(this) | ||
} | ||
|
||
/** | ||
* Infix function for invoking lambda on your view | ||
* | ||
* Sometimes instance of view is a result of a function or constructor. | ||
* In this specific case you can't call invoke() since it will be considered as | ||
* tail lambda of your fun/constructor. In such cases please use this function. | ||
* | ||
* @param function Tail lambda with receiver which is your view | ||
* @return This object | ||
*/ | ||
infix fun perform(function: KViewPager2.() -> Unit): KViewPager2 { | ||
function(this) | ||
return this | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
kakao/src/main/kotlin/com/agoda/kakao/pager2/KViewPagerItem.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
@file:Suppress("unused") | ||
|
||
package com.agoda.kakao.pager2 | ||
|
||
import android.view.View | ||
import androidx.test.espresso.Espresso | ||
import androidx.test.espresso.ViewAction | ||
import androidx.test.espresso.ViewAssertion | ||
import androidx.test.espresso.ViewInteraction | ||
import androidx.test.espresso.matcher.RootMatchers | ||
import com.agoda.kakao.common.KakaoDslMarker | ||
import com.agoda.kakao.common.actions.BaseActions | ||
import com.agoda.kakao.common.assertions.BaseAssertions | ||
import com.agoda.kakao.delegate.ViewInteractionDelegate | ||
import com.agoda.kakao.intercept.Interceptable | ||
import org.hamcrest.Matcher | ||
|
||
/** | ||
* Base class for KViewPager2 adapter items | ||
* | ||
* Please extend this class to provide custom view pager 2 view item types | ||
* | ||
* @param T type of your item. Used to enable invoke() and perform() on descendants | ||
* @param matcher Matcher of root view of adapter item. Can be used as parent for all views inside item. | ||
* | ||
* @see KViewPagerItemTypeBuilder | ||
*/ | ||
@Suppress("UNCHECKED_CAST") | ||
@KakaoDslMarker | ||
open class KViewPagerItem<out T>(matcher: Matcher<View>) : BaseActions, BaseAssertions, | ||
Interceptable<ViewInteraction, ViewAssertion, ViewAction> { | ||
override val view = ViewInteractionDelegate(Espresso.onView(matcher)) | ||
override var root = RootMatchers.DEFAULT | ||
|
||
/** | ||
* Operator that allows usage of DSL style | ||
* | ||
* @param function Tail lambda with receiver which is your view | ||
*/ | ||
operator fun invoke(function: T.() -> Unit) { | ||
function(this as T) | ||
} | ||
|
||
/** | ||
* Infix function for invoking lambda on your view | ||
* | ||
* Sometimes instance of view is a result of a function or constructor. | ||
* In this specific case you can't call invoke() since it will be considered as | ||
* tail lambda of your fun/constructor. In such cases please use this function. | ||
* | ||
* @param function Tail lambda with receiver which is your view | ||
* @return This object | ||
*/ | ||
infix fun perform(function: T.() -> Unit): T { | ||
function(this as T) | ||
return this | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
kakao/src/main/kotlin/com/agoda/kakao/pager2/KViewPagerItemType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@file:Suppress("unused") | ||
|
||
package com.agoda.kakao.pager2 | ||
|
||
import android.view.View | ||
import org.hamcrest.Matcher | ||
|
||
/** | ||
* For internal use. Don't use manually. | ||
* | ||
* Holds type and corresponding provider function | ||
*/ | ||
class KViewPagerItemType<out T : KViewPagerItem<*>>(val provideItem: (Matcher<View>) -> T) |
40 changes: 40 additions & 0 deletions
40
kakao/src/main/kotlin/com/agoda/kakao/pager2/KViewPagerItemTypeBuilder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
@file:Suppress("unused") | ||
|
||
package com.agoda.kakao.pager2 | ||
|
||
import android.view.View | ||
import com.agoda.kakao.common.KakaoDslMarker | ||
import org.hamcrest.Matcher | ||
import kotlin.reflect.KClass | ||
|
||
/** | ||
* Class that maps types to providing functions | ||
* | ||
* To be able to support different item types in KViewPager2, this class | ||
* adds support for mapping item type classes to functions that provide them. | ||
* KEmptyViewPagerItem is added by default. | ||
* | ||
* @see itemType | ||
* @see KEmptyViewPagerItem | ||
*/ | ||
@KakaoDslMarker | ||
class KViewPagerItemTypeBuilder { | ||
val itemTypes = mutableMapOf<KClass<out KViewPagerItem<*>>, KViewPagerItemType<KViewPagerItem<*>>>() | ||
|
||
init { | ||
itemTypes[KViewPagerItem::class] = KViewPagerItemType { matcher -> KEmptyViewPagerItem(matcher) } | ||
itemTypes[KEmptyViewPagerItem::class] = KViewPagerItemType { matcher -> KEmptyViewPagerItem(matcher) } | ||
} | ||
|
||
/** | ||
* Adds entry that helps KViewPager2 to automatically build child views | ||
* | ||
* To make it work, you need to pass here function (lambda, constructor), that takes matcher and returns | ||
* instance of your item type. In this case, matcher actually matches root view of your adapter item. | ||
* | ||
* @param provideItem Function that takes matcher of item's root view and returns instance of item view | ||
*/ | ||
inline fun <reified T : KViewPagerItem<*>> itemType(noinline provideItem: (Matcher<View>) -> T) { | ||
itemTypes[T::class] = KViewPagerItemType(provideItem) | ||
} | ||
} |
Oops, something went wrong.