Merge "Run KspTypeTests with javac" into androidx-main
diff --git a/paging/common/api/current.txt b/paging/common/api/current.txt
index c0867a3..5a10493 100644
--- a/paging/common/api/current.txt
+++ b/paging/common/api/current.txt
@@ -291,23 +291,22 @@
public final class PagingData<T> {
method public static <T> androidx.paging.PagingData<T> empty();
- method @CheckResult public androidx.paging.PagingData<T> filter(kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
- method @CheckResult public <R> androidx.paging.PagingData<R> flatMap(kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
- method @CheckResult public androidx.paging.PagingData<T> insertFooterItem(T item);
- method @CheckResult public androidx.paging.PagingData<T> insertHeaderItem(T item);
- method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T> pagingData, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
- method @CheckResult public <R> androidx.paging.PagingData<R> map(kotlin.jvm.functions.Function1<? super T,? extends R> transform);
field public static final androidx.paging.PagingData.Companion Companion;
}
public static final class PagingData.Companion {
method public <T> androidx.paging.PagingData<T> empty();
method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
- method @CheckResult public <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T> pagingData, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
}
- public final class PagingDataKt {
+ public final class PagingDataTransforms {
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertFooterItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertHeaderItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <R, T extends R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends R> transform);
}
public abstract class PagingSource<Key, Value> {
diff --git a/paging/common/api/public_plus_experimental_current.txt b/paging/common/api/public_plus_experimental_current.txt
index 9641951..3b7ae06 100644
--- a/paging/common/api/public_plus_experimental_current.txt
+++ b/paging/common/api/public_plus_experimental_current.txt
@@ -292,23 +292,22 @@
public final class PagingData<T> {
method public static <T> androidx.paging.PagingData<T> empty();
- method @CheckResult public androidx.paging.PagingData<T> filter(kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
- method @CheckResult public <R> androidx.paging.PagingData<R> flatMap(kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
- method @CheckResult public androidx.paging.PagingData<T> insertFooterItem(T item);
- method @CheckResult public androidx.paging.PagingData<T> insertHeaderItem(T item);
- method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T> pagingData, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
- method @CheckResult public <R> androidx.paging.PagingData<R> map(kotlin.jvm.functions.Function1<? super T,? extends R> transform);
field public static final androidx.paging.PagingData.Companion Companion;
}
public static final class PagingData.Companion {
method public <T> androidx.paging.PagingData<T> empty();
method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
- method @CheckResult public <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T> pagingData, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
}
- public final class PagingDataKt {
+ public final class PagingDataTransforms {
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertFooterItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertHeaderItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <R, T extends R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends R> transform);
}
public abstract class PagingSource<Key, Value> {
diff --git a/paging/common/api/restricted_current.txt b/paging/common/api/restricted_current.txt
index c0867a3..5a10493 100644
--- a/paging/common/api/restricted_current.txt
+++ b/paging/common/api/restricted_current.txt
@@ -291,23 +291,22 @@
public final class PagingData<T> {
method public static <T> androidx.paging.PagingData<T> empty();
- method @CheckResult public androidx.paging.PagingData<T> filter(kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
- method @CheckResult public <R> androidx.paging.PagingData<R> flatMap(kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
method public static <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
- method @CheckResult public androidx.paging.PagingData<T> insertFooterItem(T item);
- method @CheckResult public androidx.paging.PagingData<T> insertHeaderItem(T item);
- method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T> pagingData, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
- method @CheckResult public <R> androidx.paging.PagingData<R> map(kotlin.jvm.functions.Function1<? super T,? extends R> transform);
field public static final androidx.paging.PagingData.Companion Companion;
}
public static final class PagingData.Companion {
method public <T> androidx.paging.PagingData<T> empty();
method public <T> androidx.paging.PagingData<T> from(java.util.List<? extends T> data);
- method @CheckResult public <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T> pagingData, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
}
- public final class PagingDataKt {
+ public final class PagingDataTransforms {
+ method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> predicate);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends java.lang.Iterable<? extends R>> transform);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertFooterItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <T> androidx.paging.PagingData<T> insertHeaderItem(androidx.paging.PagingData<T>, T item);
+ method @CheckResult public static <R, T extends R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function2<? super T,? super T,? extends R> generator);
+ method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, java.util.concurrent.Executor executor, kotlin.jvm.functions.Function1<? super T,? extends R> transform);
}
public abstract class PagingSource<Key, Value> {
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagingData.kt b/paging/common/src/main/kotlin/androidx/paging/PagingData.kt
index 61548a2..7a320d3 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagingData.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagingData.kt
@@ -16,10 +16,8 @@
package androidx.paging
-import androidx.annotation.CheckResult
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
/**
* Container for Paged data from a single generation of loads.
@@ -31,80 +29,6 @@
internal val flow: Flow<PageEvent<T>>,
internal val receiver: UiReceiver
) {
- /**
- * Returns a [PagingData] containing the result of applying the given [transform] to each
- * element, as it is loaded.
- *
- * @see map
- */
- @JvmName("map")
- @CheckResult
- fun <R : Any> mapSync(transform: (T) -> R): PagingData<R> = transform { event ->
- event.map { transform(it) }
- }
-
- /**
- * Returns a [PagingData] of all elements returned from applying the given [transform]
- * to each element, as it is loaded.
- *
- * @see flatMap
- */
- @JvmName("flatMap")
- @CheckResult
- fun <R : Any> flatMapSync(transform: (T) -> Iterable<R>): PagingData<R> = transform { event ->
- event.flatMap { transform(it) }
- }
-
- /**
- * Returns a [PagingData] containing only elements matching the given [predicate]
- *
- * @see filter
- */
- @JvmName("filter")
- @CheckResult
- fun filterSync(predicate: (T) -> Boolean): PagingData<T> = transform { event ->
- event.filter { predicate(it) }
- }
-
- /**
- * Returns a [PagingData] containing each original element, with the passed header [item] added
- * to the start of the list.
- *
- * The header [item] is added to a loaded page which marks the end of the data stream in the
- * prepend direction by returning null in [PagingSource.LoadResult.Page.prevKey]. It will be
- * removed if the first page in the list is dropped, which can happen in the case of loaded
- * pages exceeding [PagedList.Config.maxSize].
- *
- * Note: This operation is not idempotent, calling it multiple times will continually add
- * more headers to the start of the list, which can be useful if multiple header items are
- * required.
- *
- * @see [insertFooterItem]
- */
- @CheckResult
- fun insertHeaderItem(item: T) = insertSeparators { before, _ ->
- if (before == null) item else null
- }
-
- /**
- * Returns a [PagingData] containing each original element, with the passed footer [item] added
- * to the end of the list.
- *
- * The footer [item] is added to a loaded page which marks the end of the data stream in the
- * append direction, either by returning null in [PagingSource.LoadResult.Page.nextKey]. It
- * will be removed if the first page in the list is dropped, which can happen in the case of
- * loaded* pages exceeding [PagedList.Config.maxSize].
- *
- * Note: This operation is not idempotent, calling it multiple times will continually add
- * more footers to the end of the list, which can be useful if multiple footer items are
- * required.
- *
- * @see [insertHeaderItem]
- */
- @CheckResult
- fun insertFooterItem(item: T) = insertSeparators { _, after ->
- if (after == null) item else null
- }
companion object {
internal val NOOP_RECEIVER = object : UiReceiver {
@@ -116,7 +40,7 @@
}
@Suppress("MemberVisibilityCanBePrivate") // synthetic access
- internal val EMPTY = PagingData<Any>(
+ internal val EMPTY = PagingData(
flow = flowOf(PageEvent.Insert.EMPTY_REFRESH_LOCAL),
receiver = NOOP_RECEIVER
)
@@ -156,172 +80,5 @@
),
receiver = NOOP_RECEIVER
)
-
- // NOTE: samples in the doc below are manually imported from Java code in the samples
- // project, since Java cannot be linked with @sample.
- // DO NOT CHANGE THE BELOW COMMENT WITHOUT MAKING THE CORRESPONDING CHANGE IN `samples/`
- /**
- * Returns a [PagingData] containing each original element, with an optional separator
- * generated by [generator], given the elements before and after (or null, in boundary
- * conditions).
- *
- * Note that this transform is applied asynchronously, as pages are loaded. Potential
- * separators between pages are only computed once both pages are loaded.
- *
- * **Kotlin callers should instead use the suspending extension function variant of
- * insertSeparators**
- *
- * ```
- * /*
- * * Create letter separators in an alphabetically sorted list.
- * *
- * * For example, if the input is:
- * * "apple", "apricot", "banana", "carrot"
- * *
- * * The operator would output:
- * * "A", "apple", "apricot", "B", "banana", "C", "carrot"
- * */
- * pagingDataStream.map((pagingData) ->
- * // map outer stream, so we can perform transformations on each paging generation
- * PagingData.insertSeparators(pagingData,
- * (@Nullable String before, @Nullable String after) -> {
- * if (after != null && (before == null
- * || before.charAt(0) != after.charAt(0))) {
- * // separator - after is first item that starts with its first letter
- * return Character.toString(Character.toUpperCase(after.charAt(0)));
- * } else {
- * // no separator - either end of list, or first
- * // letters of items are the same
- * return null;
- * }
- * }));
- *
- * /*
- * * Create letter separators in an alphabetically sorted list of Items, with UiModel objects.
- * *
- * * For example, if the input is (each an `Item`):
- * * "apple", "apricot", "banana", "carrot"
- * *
- * * The operator would output a list of UiModels corresponding to:
- * * "A", "apple", "apricot", "B", "banana", "C", "carrot"
- * */
- * pagingDataStream.map((itemPagingData) -> {
- * // map outer stream, so we can perform transformations on each paging generation
- *
- * // first convert items in stream to UiModel.Item
- * PagingData<UiModel.ItemModel> itemModelPagingData =
- * itemPagingData.map(UiModel.ItemModel::new);
- *
- * // Now insert UiModel.Separators, which makes the PagingData of generic type UiModel
- * return PagingData.insertSeparators(
- * itemModelPagingData,
- * (@Nullable UiModel.ItemModel before, @Nullable UiModel.ItemModel after) -> {
- * if (after != null && (before == null
- * || before.item.label.charAt(0) != after.item.label.charAt(0))) {
- * // separator - after is first item that starts with its first letter
- * return new UiModel.SeparatorModel(
- * Character.toUpperCase(after.item.label.charAt(0)));
- * } else {
- * // no separator - either end of list, or first
- * // letters of items are the same
- * return null;
- * }
- * });
- * });
- *
- * public class UiModel {
- * static class ItemModel extends UiModel {
- * public Item item;
- * ItemModel(Item item) {
- * this.item = item;
- * }
- * }
- * static class SeparatorModel extends UiModel {
- * public char character;
- * SeparatorModel(char character) {
- * this.character = character;
- * }
- * }
- * }
- */
- @JvmStatic
- @CheckResult
- fun <T : R, R : Any> insertSeparators(
- pagingData: PagingData<T>,
- generator: (T?, T?) -> R?
- ): PagingData<R> {
- return pagingData.insertSeparators { before, after -> generator(before, after) }
- }
}
}
-
-private inline fun <T : Any, R : Any> PagingData<T>.transform(
- crossinline transform: suspend (PageEvent<T>) -> PageEvent<R>
-) = PagingData(
- flow = flow.map { transform(it) },
- receiver = receiver
-)
-
-/**
- * Returns a [PagingData] containing the result of applying the given [transform] to each
- * element, as it is loaded.
- */
-@CheckResult
-@JvmSynthetic
-fun <T : Any, R : Any> PagingData<T>.map(
- transform: suspend (T) -> R
-): PagingData<R> = transform { it.map(transform) }
-
-/**
- * Returns a [PagingData] of all elements returned from applying the given [transform]
- * to each element, as it is loaded.
- */
-@CheckResult
-@JvmSynthetic
-fun <T : Any, R : Any> PagingData<T>.flatMap(
- transform: suspend (T) -> Iterable<R>
-): PagingData<R> = transform { it.flatMap(transform) }
-
-/**
- * Returns a [PagingData] containing only elements matching the given [predicate]
- */
-@CheckResult
-@JvmSynthetic
-fun <T : Any> PagingData<T>.filter(
- predicate: suspend (T) -> Boolean
-): PagingData<T> = transform { it.filter(predicate) }
-
-/**
- * Returns a [PagingData] containing each original element, with an optional separator
- * generated by [generator], given the elements before and after (or null, in boundary
- * conditions).
- *
- * Note that this transform is applied asynchronously, as pages are loaded. Potential
- * separators between pages are only computed once both pages are loaded.
- *
- * @sample androidx.paging.samples.insertSeparatorsSample
- * @sample androidx.paging.samples.insertSeparatorsUiModelSample
- */
-@CheckResult
-@JvmSynthetic
-fun <T : R, R : Any> PagingData<T>.insertSeparators(
- generator: suspend (T?, T?) -> R?
-): PagingData<R> {
- // This function must be an extension method, as it indirectly imposes a constraint on
- // the type of T (because T extends R). Ideally it would be declared not be an
- // extension, to make this method discoverable for Java callers, but we need to support
- // the common UI model pattern for separators:
- // class UiModel
- // class ItemModel: UiModel
- // class SeparatorModel: UiModel
- return PagingData(
- flow = flow.insertEventSeparators(generator),
- receiver = receiver
- )
-}
-
-internal interface UiReceiver {
- fun accessHint(viewportHint: ViewportHint)
- fun retry()
- fun refresh()
-}
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagingDataTransforms.kt b/paging/common/src/main/kotlin/androidx/paging/PagingDataTransforms.kt
new file mode 100644
index 0000000..5f42dc1
--- /dev/null
+++ b/paging/common/src/main/kotlin/androidx/paging/PagingDataTransforms.kt
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:JvmName("PagingDataTransforms")
+
+package androidx.paging
+
+import androidx.annotation.CheckResult
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.withContext
+import java.util.concurrent.Executor
+
+private inline fun <T : Any, R : Any> PagingData<T>.transform(
+ crossinline transform: suspend (PageEvent<T>) -> PageEvent<R>
+) = PagingData(
+ flow = flow.map { transform(it) },
+ receiver = receiver
+)
+
+/**
+ * Returns a [PagingData] containing the result of applying the given [transform] to each
+ * element, as it is loaded.
+ */
+@CheckResult
+@JvmSynthetic
+fun <T : Any, R : Any> PagingData<T>.map(
+ transform: suspend (T) -> R
+): PagingData<R> = transform { it.map(transform) }
+
+/**
+ * Returns a [PagingData] containing the result of applying the given [transform] to each
+ * element, as it is loaded.
+ *
+ * @see PagingData.map
+ */
+@CheckResult
+fun <T : Any, R : Any> PagingData<T>.map(
+ executor: Executor,
+ transform: (T) -> R,
+): PagingData<R> = transform { event ->
+ withContext(executor.asCoroutineDispatcher()) {
+ event.map { transform(it) }
+ }
+}
+
+/**
+ * Returns a [PagingData] of all elements returned from applying the given [transform]
+ * to each element, as it is loaded.
+ */
+@CheckResult
+@JvmSynthetic
+fun <T : Any, R : Any> PagingData<T>.flatMap(
+ transform: suspend (T) -> Iterable<R>
+): PagingData<R> = transform { it.flatMap(transform) }
+
+/**
+ * Returns a [PagingData] of all elements returned from applying the given [transform]
+ * to each element, as it is loaded.
+ *
+ * @see flatMap
+ */
+@CheckResult
+fun <T : Any, R : Any> PagingData<T>.flatMap(
+ executor: Executor,
+ transform: (T) -> Iterable<R>
+): PagingData<R> = transform { event ->
+ withContext(executor.asCoroutineDispatcher()) {
+ event.flatMap { transform(it) }
+ }
+}
+
+/**
+ * Returns a [PagingData] containing only elements matching the given [predicate]
+ */
+@CheckResult
+@JvmSynthetic
+fun <T : Any> PagingData<T>.filter(
+ predicate: suspend (T) -> Boolean
+): PagingData<T> = transform { it.filter(predicate) }
+
+/**
+ * Returns a [PagingData] containing only elements matching the given [predicate].
+ *
+ * @see filter
+ */
+@CheckResult
+@JvmName("filter")
+fun <T : Any> PagingData<T>.filter(
+ executor: Executor,
+ predicate: (T) -> Boolean
+): PagingData<T> = transform { event ->
+ withContext(executor.asCoroutineDispatcher()) {
+ event.filter { predicate(it) }
+ }
+}
+
+/**
+ * Returns a [PagingData] containing each original element, with an optional separator
+ * generated by [generator], given the elements before and after (or null, in boundary
+ * conditions).
+ *
+ * Note that this transform is applied asynchronously, as pages are loaded. Potential
+ * separators between pages are only computed once both pages are loaded.
+ *
+ * @sample androidx.paging.samples.insertSeparatorsSample
+ * @sample androidx.paging.samples.insertSeparatorsUiModelSample
+ */
+@CheckResult
+@JvmSynthetic
+fun <T : R, R : Any> PagingData<T>.insertSeparators(
+ generator: suspend (T?, T?) -> R?
+): PagingData<R> {
+ // This function must be an extension method, as it indirectly imposes a constraint on
+ // the type of T (because T extends R). Ideally it would be declared not be an
+ // extension, to make this method discoverable for Java callers, but we need to support
+ // the common UI model pattern for separators:
+ // class UiModel
+ // class ItemModel: UiModel
+ // class SeparatorModel: UiModel
+ return PagingData(
+ flow = flow.insertEventSeparators(generator),
+ receiver = receiver
+ )
+}
+
+// NOTE: samples in the doc below are manually imported from Java code in the samples
+// project, since Java cannot be linked with @sample.
+// DO NOT CHANGE THE BELOW COMMENT WITHOUT MAKING THE CORRESPONDING CHANGE IN `samples/`
+/**
+ *
+ * Returns a [PagingData] containing each original element, with an optional separator
+ * generated by [generator], given the elements before and after (or null, in boundary
+ * conditions).
+ *
+ * Note that this transform is applied asynchronously, as pages are loaded. Potential
+ * separators between pages are only computed once both pages are loaded.
+ *
+ * **Kotlin callers should instead use the suspending extension function variant of
+ * insertSeparators**
+ *
+ * ```
+ * /*
+ * * Create letter separators in an alphabetically sorted list.
+ * *
+ * * For example, if the input is:
+ * * "apple", "apricot", "banana", "carrot"
+ * *
+ * * The operator would output:
+ * * "A", "apple", "apricot", "B", "banana", "C", "carrot"
+ * */
+ * pagingDataStream.map(pagingData ->
+ * // map outer stream, so we can perform transformations on each paging generation
+ * PagingDataTransforms.insertSeparators(pagingData, bgExecutor,
+ * (@Nullable String before, @Nullable String after) -> {
+ * if (after != null && (before == null
+ * || before.charAt(0) != after.charAt(0))) {
+ * // separator - after is first item that starts with its first
+ * // letter
+ * return Character.toString(
+ * Character.toUpperCase(after.charAt(0)));
+ * } else {
+ * // no separator - either end of list, or first
+ * // letters of items are the same
+ * return null;
+ * }
+ * }));
+ *
+ * /*
+ * * Create letter separators in an alphabetically sorted list of Items, with UiModel
+ * * objects.
+ * *
+ * * For example, if the input is (each an `Item`):
+ * * "apple", "apricot", "banana", "carrot"
+ * *
+ * * The operator would output a list of UiModels corresponding to:
+ * * "A", "apple", "apricot", "B", "banana", "C", "carrot"
+ * */
+ * pagingDataStream.map(itemPagingData -> {
+ * // map outer stream, so we can perform transformations on each paging generation
+ *
+ * // first convert items in stream to UiModel.Item
+ * PagingData<UiModel.ItemModel> itemModelPagingData = PagingDataTransforms.map(
+ * itemPagingData, bgExecutor, UiModel.ItemModel::new);
+ *
+ * // Now insert UiModel.Separators, which makes the PagingData of generic type UiModel
+ * return PagingDataTransforms.insertSeparators(
+ * itemModelPagingData, bgExecutor,
+ * (@Nullable UiModel.ItemModel before, @Nullable UiModel.ItemModel after) -> {
+ * if (after != null && (before == null
+ * || before.item.label.charAt(0) != after.item.label.charAt(0))) {
+ * // separator - after is first item that starts with its first letter
+ * return new UiModel.SeparatorModel(
+ * Character.toUpperCase(after.item.label.charAt(0)));
+ * } else {
+ * // no separator - either end of list, or first
+ * // letters of items are the same
+ * return null;
+ * }
+ * });
+ * });
+ *
+ * public class UiModel {
+ * static class ItemModel extends UiModel {
+ * public Item item;
+ * ItemModel(Item item) {
+ * this.item = item;
+ * }
+ * }
+ * static class SeparatorModel extends UiModel {
+ * public char character;
+ * SeparatorModel(char character) {
+ * this.character = character;
+ * }
+ * }
+ * }
+ *
+ *
+ * ```
+ */
+@CheckResult
+fun <R : Any, T : R> PagingData<T>.insertSeparators(
+ executor: Executor,
+ generator: (T?, T?) -> R?
+): PagingData<R> {
+ return insertSeparators { before, after ->
+ withContext(executor.asCoroutineDispatcher()) {
+ generator(before, after)
+ }
+ }
+}
+
+/**
+ * Returns a [PagingData] containing each original element, with the passed header [item] added
+ * to the start of the list.
+ *
+ * The header [item] is added to a loaded page which marks the end of the data stream in the
+ * prepend direction by returning null in [PagingSource.LoadResult.Page.prevKey]. It will be
+ * removed if the first page in the list is dropped, which can happen in the case of loaded
+ * pages exceeding [PagedList.Config.maxSize].
+ *
+ * Note: This operation is not idempotent, calling it multiple times will continually add
+ * more headers to the start of the list, which can be useful if multiple header items are
+ * required.
+ *
+ * @see [insertFooterItem]
+ */
+@CheckResult
+fun <T : Any> PagingData<T>.insertHeaderItem(item: T) = insertSeparators { before, _ ->
+ if (before == null) item else null
+}
+
+/**
+ * Returns a [PagingData] containing each original element, with the passed footer [item] added
+ * to the end of the list.
+ *
+ * The footer [item] is added to a loaded page which marks the end of the data stream in the
+ * append direction, either by returning null in [PagingSource.LoadResult.Page.nextKey]. It
+ * will be removed if the first page in the list is dropped, which can happen in the case of
+ * loaded* pages exceeding [PagedList.Config.maxSize].
+ *
+ * Note: This operation is not idempotent, calling it multiple times will continually add
+ * more footers to the end of the list, which can be useful if multiple footer items are
+ * required.
+ *
+ * @see [insertHeaderItem]
+ */
+@CheckResult
+fun <T : Any> PagingData<T>.insertFooterItem(item: T) = insertSeparators { _, after ->
+ if (after == null) item else null
+}
diff --git a/paging/common/src/main/kotlin/androidx/paging/UiReceiver.kt b/paging/common/src/main/kotlin/androidx/paging/UiReceiver.kt
new file mode 100644
index 0000000..f7690ef
--- /dev/null
+++ b/paging/common/src/main/kotlin/androidx/paging/UiReceiver.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.paging
+
+/**
+ * Fetcher-side callbacks for presenter-side events communicated through [PagingData].
+ */
+internal interface UiReceiver {
+ fun accessHint(viewportHint: ViewportHint)
+ fun retry()
+ fun refresh()
+}
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt
index ca57505..2cd36a9 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3/V3ViewModel.kt
@@ -22,6 +22,8 @@
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
+import androidx.paging.insertFooterItem
+import androidx.paging.insertHeaderItem
import androidx.paging.insertSeparators
import kotlinx.coroutines.flow.map
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt
index 8c84a91..c336fdb 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/v3room/V3RoomViewModel.kt
@@ -25,6 +25,8 @@
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
+import androidx.paging.insertFooterItem
+import androidx.paging.insertHeaderItem
import androidx.paging.insertSeparators
import androidx.paging.integration.testapp.room.Customer
import androidx.paging.integration.testapp.room.SampleDatabase
diff --git a/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaSample.java b/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaSample.java
index 47998ff..ba54d807 100644
--- a/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaSample.java
+++ b/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaSample.java
@@ -20,6 +20,9 @@
import androidx.annotation.Nullable;
import androidx.paging.PagingData;
+import androidx.paging.PagingDataTransforms;
+
+import java.util.concurrent.Executor;
import io.reactivex.Flowable;
import kotlin.NotImplementedError;
@@ -28,7 +31,7 @@
* NOTE - MANUALLY COPIED SAMPLE
*
* Since @sample from kdoc doesn't support Java, this code must manually kept in sync with
- * the @JvmStatic `PagingData.insertSeparators` method
+ * the `PagingDataTransforms.insertSeparators` method
*/
@SuppressWarnings({"unused", "WeakerAccess"})
class InsertSeparatorsJavaSample {
@@ -39,6 +42,8 @@
throw new NotImplementedError();
}
+ public Executor bgExecutor;
+
@SuppressLint("CheckResult")
@SuppressWarnings({"unused", "ResultOfMethodCallIgnored", "RxReturnValueIgnored"})
public void insertSeparatorsSample() {
@@ -51,14 +56,16 @@
* The operator would output:
* "A", "apple", "apricot", "B", "banana", "C", "carrot"
*/
- pagingDataStream.map((pagingData) ->
+ pagingDataStream.map(pagingData ->
// map outer stream, so we can perform transformations on each paging generation
- PagingData.insertSeparators(pagingData,
+ PagingDataTransforms.insertSeparators(pagingData, bgExecutor,
(@Nullable String before, @Nullable String after) -> {
if (after != null && (before == null
|| before.charAt(0) != after.charAt(0))) {
- // separator - after is first item that starts with its first letter
- return Character.toString(Character.toUpperCase(after.charAt(0)));
+ // separator - after is first item that starts with its first
+ // letter
+ return Character.toString(
+ Character.toUpperCase(after.charAt(0)));
} else {
// no separator - either end of list, or first
// letters of items are the same
diff --git a/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaUiModelSample.java b/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaUiModelSample.java
index 2aa1172..5bf43a5 100644
--- a/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaUiModelSample.java
+++ b/paging/samples/src/main/java/androidx/paging/samples/java/InsertSeparatorsJavaUiModelSample.java
@@ -20,6 +20,9 @@
import androidx.annotation.Nullable;
import androidx.paging.PagingData;
+import androidx.paging.PagingDataTransforms;
+
+import java.util.concurrent.Executor;
import io.reactivex.Flowable;
import kotlin.NotImplementedError;
@@ -28,7 +31,7 @@
* NOTE - MANUALLY COPIED SAMPLE
*
* Since @sample from kdoc doesn't support Java, this code must manually kept in sync with
- * the @JvmStatic `PagingData.insertSeparators` method
+ * the `PagingDataTransforms.insertSeparators` method
*/
@SuppressWarnings({"unused", "WeakerAccess"})
class InsertSeparatorsJavaUiModelSample {
@@ -38,12 +41,15 @@
throw new NotImplementedError();
}
+ public Executor bgExecutor;
+
@SuppressLint("CheckResult")
@SuppressWarnings({"unused", "ResultOfMethodCallIgnored", "RxReturnValueIgnored"})
public void insertSeparatorsSample() {
/*
- * Create letter separators in an alphabetically sorted list of Items, with UiModel objects.
+ * Create letter separators in an alphabetically sorted list of Items, with UiModel
+ * objects.
*
* For example, if the input is (each an `Item`):
* "apple", "apricot", "banana", "carrot"
@@ -55,12 +61,12 @@
// map outer stream, so we can perform transformations on each paging generation
// first convert items in stream to UiModel.Item
- PagingData<UiModel.ItemModel> itemModelPagingData =
- itemPagingData.map(UiModel.ItemModel::new);
+ PagingData<UiModel.ItemModel> itemModelPagingData = PagingDataTransforms.map(
+ itemPagingData, bgExecutor, UiModel.ItemModel::new);
// Now insert UiModel.Separators, which makes the PagingData of generic type UiModel
- return PagingData.insertSeparators(
- itemModelPagingData,
+ return PagingDataTransforms.insertSeparators(
+ itemModelPagingData, bgExecutor,
(@Nullable UiModel.ItemModel before, @Nullable UiModel.ItemModel after) -> {
if (after != null && (before == null
|| before.item.label.charAt(0) != after.item.label.charAt(0))) {
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/types/EnumColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/androidx/room/solver/types/EnumColumnTypeAdapter.kt
index 4527dd2..2f01519 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/types/EnumColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/types/EnumColumnTypeAdapter.kt
@@ -96,9 +96,10 @@
addStatement("case $L: return $S", enumConstant.name, enumConstant.name)
}
addStatement(
- "default: throw new $T($S)",
+ "default: throw new $T($S + $N)",
ILLEGAL_ARG_EXCEPTION,
- "Can't convert ${param.name} to string, unknown enum value."
+ "Can't convert enum to string, unknown enum value: ",
+ param
)
endControlFlow()
}
@@ -136,9 +137,10 @@
)
}
addStatement(
- "default: throw new $T($S)",
+ "default: throw new $T($S + $N)",
ILLEGAL_ARG_EXCEPTION,
- "Can't convert ${param.name} to enum, unknown value."
+ "Can't convert value to enum, unknown value: ",
+ param
)
endControlFlow()
}
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PhotoViewModel.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PhotoViewModel.java
index 0f1b5c5..9fe6a2b 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PhotoViewModel.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/PhotoViewModel.java
@@ -24,17 +24,22 @@
import androidx.paging.Pager;
import androidx.paging.PagingConfig;
import androidx.paging.PagingData;
+import androidx.paging.PagingDataTransforms;
import androidx.paging.PagingLiveData;
import com.example.android.leanback.room.Photo;
import com.example.android.leanback.room.PhotoDatabase;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
/**
* ViewModel for showing sample usage of PagedListAdapter
*/
public class PhotoViewModel extends AndroidViewModel {
private LiveData<PagingData<PhotoItem>> mPagingDataLiveData;
+ private Executor mExecutor = Executors.newSingleThreadExecutor();
public PhotoViewModel(Application application) {
super(application);
@@ -47,9 +52,10 @@
mPagingDataLiveData = Transformations.map(PagingLiveData.getLiveData(pager),
(Function<PagingData<Photo>, PagingData<PhotoItem>>) pagingData ->
- pagingData.map((photo) -> new PhotoItem(photo.getTitle(),
- photo.getImgResourceId(),
- photo.getId()))
+ PagingDataTransforms.map(pagingData, mExecutor,
+ (photo) -> new PhotoItem(photo.getTitle(),
+ photo.getImgResourceId(),
+ photo.getId()))
);