aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-08-05 14:49:47 -0700
committerGitHub <noreply@github.com>2017-08-05 14:49:47 -0700
commitc707d42b311f96cbabc1971f98598c8b8922ba16 (patch)
tree3c592c2a8bdd2fb759e3632adf038b5d7cecfabb /core
parentbafc1996d803862d30a2c7d0c402d30c79c4f647 (diff)
downloadkau-c707d42b311f96cbabc1971f98598c8b8922ba16.tar.gz
kau-c707d42b311f96cbabc1971f98598c8b8922ba16.tar.bz2
kau-c707d42b311f96cbabc1971f98598c8b8922ba16.zip
Swipe (#24)
* Test emulator * Update readme * Update fastadapter and about listing * Make faq parser asynchronous * Modularize about panels * Add basis for faq * Test and finalize the faq panel * Update readme * Update changelog * Remove emulator for now * Update sample * Change back to manual versioning to avoid suggestion errors * Add awesome-kt banner * Fix faq background color * Fix merge conflicts 2 * Add waffle badge * Update readme * Fix lint * Create FileUtils and NotificationUtils * Remove frost hardcode * Fix simple date * Update swipe to use weak references * Initializing test dependencies * Update to gradle 4.1 * Fix lint warnings * Drop back down and fix errors * Finalize swipe with example * Finalize weak reference and ordering * Update test code * Make loggers inline
Diffstat (limited to 'core')
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt17
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/logging/TimberLogger.kt16
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt7
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt37
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt50
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt18
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java2
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt10
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt33
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/NotificationUtils.kt11
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt1
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt2
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt2
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt42
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt2
15 files changed, 191 insertions, 59 deletions
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt
new file mode 100644
index 0000000..5dc44a8
--- /dev/null
+++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt
@@ -0,0 +1,17 @@
+package ca.allanwang.kau.kotlin
+
+/**
+ * Created by Allan Wang on 2017-08-05.
+ */
+
+/**
+ * Replica of [Vector.removeIf] in Java
+ * Since we don't have access to the internals of our extended class,
+ * We will simply iterate and remove when the filter returns {@code false}
+ */
+@Synchronized inline fun <T, C : MutableIterable<T>> C.kauRemoveIf(filter: (item: T) -> Boolean): C {
+ val iter = iterator()
+ while (iter.hasNext())
+ if (filter(iter.next())) iter.remove()
+ return this
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/ca/allanwang/kau/logging/TimberLogger.kt b/core/src/main/kotlin/ca/allanwang/kau/logging/TimberLogger.kt
index e0f6cae..4c6d655 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/logging/TimberLogger.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/logging/TimberLogger.kt
@@ -1,3 +1,5 @@
+@file:Suppress("NOTHING_TO_INLINE")
+
package ca.allanwang.kau.logging
import timber.log.Timber
@@ -9,11 +11,11 @@ import timber.log.Timber
* Timber extension that will embed the tag as part of the message for each log item
*/
open class TimberLogger(tag: String) {
- internal val TAG = "$tag: %s"
- fun e(s: String) = Timber.e(TAG, s)
- fun e(t: Throwable?, s: String = "error") = if (t == null) e(s) else Timber.e(t, TAG, s)
- fun d(s: String) = Timber.d(TAG, s)
- fun i(s: String) = Timber.i(TAG, s)
- fun v(s: String) = Timber.v(TAG, s)
- fun eThrow(s: String) = e(Throwable(s))
+ val TAG = "$tag: %s"
+ inline fun e(s: String) = Timber.e(TAG, s)
+ inline fun e(t: Throwable?, s: String = "error") = if (t == null) e(s) else Timber.e(t, TAG, s)
+ inline fun d(s: String) = Timber.d(TAG, s)
+ inline fun i(s: String) = Timber.i(TAG, s)
+ inline fun v(s: String) = Timber.v(TAG, s)
+ inline fun eThrow(s: String) = e(Throwable(s))
} \ No newline at end of file
diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt b/core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt
index 2ffb2ef..f14f5cf 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt
@@ -1,7 +1,5 @@
package ca.allanwang.kau.swipe
-import ca.allanwang.kau.kotlin.nonReadable
-
/**
* Created by Mr.Jude on 2015/8/26.
*
@@ -9,13 +7,12 @@ import ca.allanwang.kau.kotlin.nonReadable
*
* Helper class to give the previous activity an offset as the main page is pulled
*/
-class RelativeSlider(var curPage: SwipeBackPage) : SwipeListener {
+internal class RelativeSlider(var curPage: SwipeBackPage) : SwipeListener {
var offset = 0f
var enabled: Boolean
- @Deprecated(level = DeprecationLevel.ERROR, message = "Cannot use enabled as getter")
- get() = nonReadable()
+ get() = curPage.hasListener(this)
set(value) {
if (value) curPage.addListener(this)
else curPage.removeListener(this)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt
index 503f1fc..0859ac5 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt
@@ -2,27 +2,27 @@ package ca.allanwang.kau.swipe
import android.app.Activity
import ca.allanwang.kau.R
+import ca.allanwang.kau.kotlin.kauRemoveIf
+import ca.allanwang.kau.logging.KL
import ca.allanwang.kau.swipe.SwipeBackHelper.onDestroy
import java.util.*
-class SwipeBackException(message: String = "You Should call kauSwipeOnCreate() first") : RuntimeException(message)
+internal class SwipeBackException(message: String = "You Should call kauSwipeOnCreate() first") : RuntimeException(message)
/**
* Singleton to hold our swipe stack
* All activity pages held with strong references, so it is crucial to call
* [onDestroy] whenever an activity should be disposed
*/
-object SwipeBackHelper {
+internal object SwipeBackHelper {
private val pageStack = Stack<SwipeBackPage>()
- private operator fun get(activity: Activity): SwipeBackPage
- = pageStack.firstOrNull { it.activity === activity } ?: throw SwipeBackException()
-
- fun getCurrentPage(activity: Activity): SwipeBackPage = this[activity]
+ private operator fun get(activity: Activity): SwipeBackPage?
+ = pageStack.firstOrNull { it.activityRef.get() === activity }
fun onCreate(activity: Activity, builder: SwipeBackContract.() -> Unit = {}) {
- val page = pageStack.firstOrNull { it.activity === activity } ?: pageStack.push(SwipeBackPage(activity).apply { builder() })
+ val page = this[activity] ?: pageStack.push(SwipeBackPage(activity).apply { builder() })
val startAnimation: Int = when (page.edgeFlag) {
SWIPE_EDGE_LEFT -> R.anim.kau_slide_in_right
SWIPE_EDGE_RIGHT -> R.anim.kau_slide_in_left
@@ -30,23 +30,28 @@ object SwipeBackHelper {
else -> R.anim.kau_slide_in_top
}
activity.overridePendingTransition(startAnimation, 0)
+ KL.v("KauSwipe onCreate ${activity.localClassName}")
}
- fun onPostCreate(activity: Activity) = this[activity].onPostCreate()
+ fun onPostCreate(activity: Activity) {
+ this[activity]?.onPostCreate() ?: throw SwipeBackException()
+ KL.v("KauSwipe onPostCreate ${activity.localClassName}")
+ }
fun onDestroy(activity: Activity) {
- val page: SwipeBackPage = this[activity]
- pageStack.remove(page)
- page.activity = null
+ val page: SwipeBackPage? = this[activity]
+ pageStack.kauRemoveIf { it.activityRef.get() == null || it === page }
+ page?.activityRef?.clear()
+ KL.v("KauSwipe onDestroy ${activity.localClassName}")
}
- fun finish(activity: Activity) = this[activity].scrollToFinishActivity()
+ fun finish(activity: Activity) = this[activity]?.scrollToFinishActivity()
- internal fun getPrePage(activity: SwipeBackPage): SwipeBackPage? {
- val index = pageStack.indexOf(activity)
- return if (index > 0) pageStack[index - 1] else null
+ internal fun getPrePage(page: SwipeBackPage): SwipeBackPage? {
+ //clean invalid pages
+ pageStack.kauRemoveIf { it.activityRef.get() == null }
+ return pageStack.getOrNull(pageStack.indexOf(page) - 1)
}
-
}
/**
diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
index 1474c1a..51cd17f 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
@@ -10,6 +10,7 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import ca.allanwang.kau.logging.KL
import ca.allanwang.kau.utils.adjustAlpha
import ca.allanwang.kau.utils.navigationBarColor
import ca.allanwang.kau.utils.statusBarColor
@@ -22,8 +23,8 @@ import java.lang.ref.WeakReference
* If an edge detection occurs, this layout consumes all the touch events
* Use the [swipeEnabled] toggle if you need the scroll events on the same axis
*/
-class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
-) : FrameLayout(context, attrs, defStyle), SwipeBackContract {
+internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
+) : FrameLayout(context, attrs, defStyle), SwipeBackContract, SwipeBackContractInternal {
override val swipeBackLayout: SwipeBackLayout
get() = this
@@ -51,7 +52,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
override var disallowIntercept = false
- private var contentView: View? = null
+ private lateinit var contentViewRef: WeakReference<View>
private val dragHelper: ViewDragHelper
@@ -156,16 +157,6 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
addListener(chromeFadeListener)
}
-
- /**
- * Set up contentView which will be moved by user gesture
-
- * @param view
- */
- private fun setContentView(view: View) {
- contentView = view
- }
-
override fun setEdgeSizePercent(swipeEdgePercent: Float) {
edgeSize = ((if (horizontal) resources.displayMetrics.widthPixels else resources.displayMetrics.heightPixels) * swipeEdgePercent).toInt()
}
@@ -181,6 +172,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
/**
* Removes a listener from the set of listeners
+ * and scans our list for invalid ones
* @param listener
*/
@@ -194,10 +186,27 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
}
/**
+ * Checks if a listener exists in our list,
+ * and remove invalid ones at the same time
+ */
+ override fun hasListener(listener: SwipeListener): Boolean {
+ val iter = listeners.iterator()
+ while (iter.hasNext()) {
+ val l = iter.next().get()
+ if (l == null)
+ iter.remove()
+ else if (l == listener)
+ return true
+ }
+ return false
+ }
+
+ /**
* Scroll out contentView and finish the activity
*/
override fun scrollToFinishActivity() {
- val childWidth = contentView!!.width
+ val contentView = contentViewRef.get() ?: return KL.e("KauSwipe cannot scroll to finish as contentView is null. Is onPostCreate called?")
+ val childWidth = contentView.width
val top = 0
val left = childWidth + OVERSCROLL_DISTANCE
dragHelper.smoothSlideViewTo(contentView, left, top)
@@ -224,6 +233,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+ val contentView = contentViewRef.get() ?: return KL.e("KauSwipe cannot change layout as contentView is null. Is onPostCreate called?")
inLayout = true
val xOffset: Int
val yOffset: Int
@@ -234,7 +244,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
xOffset = 0
yOffset = contentOffset
}
- contentView?.layout(xOffset, yOffset, xOffset + contentView!!.measuredWidth, yOffset + contentView!!.measuredHeight)
+ contentView.layout(xOffset, yOffset, xOffset + contentView.measuredWidth, yOffset + contentView.measuredHeight)
inLayout = false
}
@@ -243,7 +253,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
}
override fun drawChild(canvas: Canvas, child: View, drawingTime: Long): Boolean {
- val drawContent = child === contentView
+ val drawContent = child === contentViewRef.get()
val ret = super.drawChild(canvas, child, drawingTime)
if (scrimOpacity > 0 && drawContent && dragHelper.viewDragState != ViewDragHelper.STATE_IDLE)
drawScrim(canvas, child)
@@ -272,7 +282,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
val contentChild = content.getChildAt(0)
content.removeView(contentChild)
addView(contentChild)
- setContentView(contentChild)
+ contentViewRef = WeakReference(contentChild)
content.addView(this)
}
@@ -286,6 +296,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
content.removeView(this)
removeView(contentChild)
content.addView(contentChild)
+ contentViewRef.clear()
}
override fun computeScroll() {
@@ -324,10 +335,11 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu
override fun onViewPositionChanged(changedView: View, left: Int, top: Int, dx: Int, dy: Int) {
super.onViewPositionChanged(changedView, left, top, dx, dy)
+ val contentView = contentViewRef.get() ?: return KL.e("KauSwipe cannot change view position as contentView is null; is onPostCreate called?")
//make sure that we are using the proper axis
scrollPercent = Math.abs(
- if (horizontal) left.toFloat() / contentView!!.width
- else (top.toFloat() / contentView!!.height))
+ if (horizontal) left.toFloat() / contentView.width
+ else (top.toFloat() / contentView.height))
contentOffset = if (horizontal) left else top
invalidate()
if (scrollPercent < scrollThreshold && !isScrollOverValid)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt
index 81ddb62..3132f8c 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt
@@ -4,15 +4,17 @@ import android.app.Activity
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.ViewGroup
+import ca.allanwang.kau.logging.KL
+import java.lang.ref.WeakReference
/**
* Created by Mr.Jude on 2015/8/3.
*
* Updated by Allan Wang on 2017/07/05
*/
-class SwipeBackPage(activity: Activity) : SwipeBackContract by SwipeBackLayout(activity) {
+internal class SwipeBackPage(activity: Activity) : SwipeBackContractInternal by SwipeBackLayout(activity) {
- var activity: Activity? = activity
+ var activityRef = WeakReference(activity)
var slider: RelativeSlider
/**
@@ -38,8 +40,9 @@ class SwipeBackPage(activity: Activity) : SwipeBackContract by SwipeBackLayout(a
}
private fun handleLayout() {
- if (swipeEnabled) swipeBackLayout.attachToActivity(activity!!)
- else swipeBackLayout.removeFromActivity(activity!!)
+ val activity = activityRef.get() ?: return KL.v("KauSwipe activity ref gone during handleLayout")
+ if (swipeEnabled) swipeBackLayout.attachToActivity(activity)
+ else swipeBackLayout.removeFromActivity(activity)
}
fun setClosePercent(percent: Float): SwipeBackPage {
@@ -49,6 +52,10 @@ class SwipeBackPage(activity: Activity) : SwipeBackContract by SwipeBackLayout(a
}
+internal interface SwipeBackContractInternal : SwipeBackContract {
+ val swipeBackLayout: SwipeBackLayout
+}
+
interface SwipeBackContract {
/**
* Toggle main touch intercept
@@ -59,7 +66,6 @@ interface SwipeBackContract {
* This dynamically fades as the page gets closer to exiting
*/
var scrimColor: Int
- val swipeBackLayout: SwipeBackLayout
var edgeSize: Int
/**
* Set the flag for which edge the page is scrolling from
@@ -92,7 +98,9 @@ interface SwipeBackContract {
* Sets edge size based on screen size
*/
fun setEdgeSizePercent(swipeEdgePercent: Float)
+
fun addListener(listener: SwipeListener)
fun removeListener(listener: SwipeListener)
+ fun hasListener(listener: SwipeListener): Boolean
fun scrollToFinishActivity()
} \ No newline at end of file
diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java b/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java
index 3368e10..566e9e5 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java
@@ -28,7 +28,7 @@ import static ca.allanwang.kau.swipe.SwipeBackHelperKt.SWIPE_EDGE_TOP;
* This is an extension of {@link android.support.v4.widget.ViewDragHelper}
* Along with additional methods defined in {@link ViewDragHelperExtras}
*/
-public class ViewDragHelper implements ViewDragHelperExtras {
+class ViewDragHelper implements ViewDragHelperExtras {
private static final String TAG = "ViewDragHelper";
/**
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt
index dad01f1..889f347 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt
@@ -1,14 +1,16 @@
package ca.allanwang.kau.utils
+import android.support.v4.widget.ViewDragHelper
+
/**
* Created by Allan Wang on 2017-06-08.
*/
const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"
-const val KAU_LEFT = 1
-const val KAU_TOP = 2
-const val KAU_RIGHT = 4
-const val KAU_BOTTOM = 8
+const val KAU_LEFT = ViewDragHelper.EDGE_LEFT
+const val KAU_RIGHT = ViewDragHelper.EDGE_RIGHT
+const val KAU_TOP = ViewDragHelper.EDGE_TOP
+const val KAU_BOTTOM = ViewDragHelper.EDGE_BOTTOM
const val KAU_HORIZONTAL = KAU_LEFT or KAU_RIGHT
const val KAU_VERTICAL = KAU_TOP or KAU_BOTTOM
const val KAU_ALL = KAU_HORIZONTAL or KAU_VERTICAL
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt
new file mode 100644
index 0000000..25e0519
--- /dev/null
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt
@@ -0,0 +1,33 @@
+package ca.allanwang.kau.utils
+
+import android.content.Context
+import android.os.Environment
+import java.io.File
+import java.io.IOException
+import java.io.InputStream
+import java.text.SimpleDateFormat
+import java.util.*
+
+/**
+ * Created by Allan Wang on 2017-08-04.
+ */
+@Throws(IOException::class)
+fun createMediaFile(prefix: String, extension: String): File {
+ val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
+ val imageFileName = "${prefix}_${timeStamp}_"
+ val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ val frostDir = File(storageDir, prefix)
+ if (!frostDir.exists()) frostDir.mkdirs()
+ return File.createTempFile(imageFileName, extension, frostDir)
+}
+
+@Throws(IOException::class)
+fun Context.createPrivateMediaFile(prefix: String, extension: String): File {
+ val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
+ val imageFileName = "${prefix}_${timeStamp}_"
+ val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
+ return File.createTempFile(imageFileName, extension, storageDir)
+}
+
+fun File.copyFromInputStream(inputStream: InputStream)
+ = inputStream.use { input -> outputStream().use { output -> input.copyTo(output) } } \ No newline at end of file
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/NotificationUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/NotificationUtils.kt
new file mode 100644
index 0000000..23a8370
--- /dev/null
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/NotificationUtils.kt
@@ -0,0 +1,11 @@
+package ca.allanwang.kau.utils
+
+import android.content.Context
+import android.support.v4.app.NotificationManagerCompat
+
+
+/**
+ * Created by Allan Wang on 2017-08-04.
+ */
+fun Context.cancelNotification(notifId: Int)
+ = NotificationManagerCompat.from(this).cancel(notifId) \ No newline at end of file
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt
index 42d150e..538208d 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt
@@ -1,6 +1,5 @@
package ca.allanwang.kau.utils
-import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt
index fa062f7..1f4536b 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt
@@ -6,9 +6,9 @@ import android.support.annotation.TransitionRes
import android.support.transition.AutoTransition
import android.support.transition.TransitionInflater
import android.support.transition.TransitionManager
-import android.support.transition.Transition as SupportTransition
import android.transition.Transition
import android.view.ViewGroup
+import android.support.transition.Transition as SupportTransition
/**
* Created by Allan Wang on 2017-06-24.
diff --git a/core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt b/core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt
index 1997bd1..2025422 100644
--- a/core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt
+++ b/core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt
@@ -7,6 +7,8 @@ import kotlin.test.assertNotEquals
/**
* Created by Allan Wang on 2017-07-29.
+ *
+ * Test code for [LazyResettable]
*/
class LazyResettableTest {
diff --git a/core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt b/core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt
new file mode 100644
index 0000000..1c40f57
--- /dev/null
+++ b/core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt
@@ -0,0 +1,42 @@
+package ca.allanwang.kau.kotlin
+
+import org.junit.Test
+import kotlin.test.assertEquals
+
+/**
+ * Created by Allan Wang on 2017-08-05.
+ *
+ * Test code for [kauRemoveIf]
+ */
+class StreamsTest {
+
+ @Test
+ fun basic() {
+ val items = mutableListOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+ items.kauRemoveIf { it % 2 == 0 }
+ assertEquals(listOf(1, 3, 5, 7, 9), items)
+ }
+
+ @Test
+ fun objectReference() {
+ data class Potato(val id: Int)
+
+ val thePotato = Potato(9)
+ val items = mutableListOf<Potato>()
+ val result = mutableListOf<Potato>()
+ for (i in 0..11) {
+ val potato = Potato(i)
+ items.add(potato)
+ result.add(potato)
+ }
+ items.add(3, thePotato)
+ assertEquals(result.size + 1, items.size, "Invalid list addition")
+ assertEquals(2, items.filter { it.id == 9 }.size, "Invalid number of potatoes with id 9")
+ items.kauRemoveIf { it === thePotato } //removal by reference
+ assertEquals(result.size, items.size, "Invalid list size after removal")
+ assertEquals(result, items)
+ items.kauRemoveIf { it == thePotato } //removal by equality
+ assertEquals(result.size - 1, items.size, "Invalid list removal based on equality")
+ }
+
+} \ No newline at end of file
diff --git a/core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt b/core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt
index 071ee9c..ce2b757 100644
--- a/core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt
+++ b/core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt
@@ -6,6 +6,8 @@ import kotlin.test.assertEquals
/**
* Created by Allan Wang on 2017-06-23.
+ *
+ * Misc test code
*/
class UtilsTest {