aboutsummaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2019-06-07 12:41:00 -0400
committerAllan Wang <me@allanwang.ca>2019-06-07 12:41:00 -0400
commit5d86d9089697b152192b2786fbe0c708dd8b5e2b (patch)
tree99b563b8c234330d2bbbc0145f086d8691ee9376 /core/src
parent572d470a2677eec0405a7b16ab9a2cfb954d6832 (diff)
parent879ac366074697dd0a7fbb2c3d99a48d7aeeb22d (diff)
downloadkau-5d86d9089697b152192b2786fbe0c708dd8b5e2b.tar.gz
kau-5d86d9089697b152192b2786fbe0c708dd8b5e2b.tar.bz2
kau-5d86d9089697b152192b2786fbe0c708dd8b5e2b.zip
Merge dev
Diffstat (limited to 'core/src')
-rw-r--r--core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt28
-rw-r--r--core/src/androidTest/kotlin/ca/allanwang/kau/utils/KotterknifeTest.kt25
-rw-r--r--core/src/androidTest/kotlin/ca/allanwang/kau/utils/UtilsAndroidTest.kt50
-rw-r--r--core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt53
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt60
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/internal/KauBaseActivity.kt47
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt16
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/FlyWeight.kt40
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt22
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt17
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt18
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/Utils.kt17
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kotlin/Zip.kt89
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt18
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt50
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt21
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt29
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/logging/KL.kt26
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/logging/KauLogger.kt49
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt91
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionResult.kt21
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt28
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt27
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt22
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt48
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt23
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeListener.kt17
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java4
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt28
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/ui/SimpleRippleDrawable.kt21
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt32
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt25
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/ui/views/RippleCanvas.kt49
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt88
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/AnimHolder.kt20
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/AnimUtils.kt66
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt115
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt117
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt19
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt119
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt75
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/DrawableUtils.kt21
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt18
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/FontUtils.kt23
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/FragmentUtils.kt22
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/IIconUtils.kt26
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt309
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/NetworkUtils.kt20
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/NotificationUtils.kt20
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt17
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt19
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt34
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt24
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt98
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/xml/Changelog.kt59
-rw-r--r--core/src/main/kotlin/ca/allanwang/kau/xml/FAQ.kt95
-rw-r--r--core/src/main/res-public/values-da-rDK/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-de-rDE/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-es-rES/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-fr-rFR/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-gl-rES/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-hu-rHU/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-in-rID/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-it-rIT/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-ko-rKR/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-nl-rNL/strings_commons.xml71
-rw-r--r--core/src/main/res-public/values-no-rNO/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-pl-rPL/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-pt-rBR/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-pt-rPT/strings_commons.xml71
-rw-r--r--core/src/main/res-public/values-sr-rSP/strings_commons.xml75
-rw-r--r--core/src/main/res-public/values-sv-rSE/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-th-rTH/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-tr-rTR/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-uk-rUA/strings_commons.xml28
-rw-r--r--core/src/main/res-public/values-vi-rVN/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-zh-rCN/strings_commons.xml4
-rw-r--r--core/src/main/res-public/values-zh-rTW/strings_commons.xml67
-rw-r--r--core/src/main/res/layout/kau_changelog_content.xml4
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/kotlin/CoroutineTest.kt73
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/kotlin/DebounceTest.kt18
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt18
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt18
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/kotlin/ZipTest.kt70
-rw-r--r--core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt35
85 files changed, 2234 insertions, 917 deletions
diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt
index 2a9263a..29f5af1 100644
--- a/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt
+++ b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt
@@ -1,9 +1,25 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kpref
import android.annotation.SuppressLint
-import android.support.test.InstrumentationRegistry
-import android.support.test.filters.MediumTest
-import android.support.test.runner.AndroidJUnit4
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -23,7 +39,7 @@ class KPrefTest {
class TestPref : KPref() {
init {
- initialize(InstrumentationRegistry.getTargetContext(), "kpref_test_${System.currentTimeMillis()}")
+ initialize(ApplicationProvider.getApplicationContext<Context>(), "kpref_test_${System.currentTimeMillis()}")
}
var one by kpref("one", 1)
@@ -83,11 +99,9 @@ class KPrefTest {
assertEquals(-1, pref.one, "Kpref did not refetch from shared prefs upon reset")
}
-
@Test
fun single() {
assertTrue(pref.oneShot)
assertFalse(pref.oneShot)
}
-
-} \ No newline at end of file
+}
diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/utils/KotterknifeTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/utils/KotterknifeTest.kt
index 1dac92f..96ebd3a 100644
--- a/core/src/androidTest/kotlin/ca/allanwang/kau/utils/KotterknifeTest.kt
+++ b/core/src/androidTest/kotlin/ca/allanwang/kau/utils/KotterknifeTest.kt
@@ -1,12 +1,27 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.content.Context
-import android.support.test.InstrumentationRegistry
-import android.support.test.filters.MediumTest
-import android.support.test.runner.AndroidJUnit4
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -25,7 +40,7 @@ class KotterknifeTest {
@Before
fun init() {
- context = InstrumentationRegistry.getContext()
+ context = InstrumentationRegistry.getInstrumentation().context
}
@Test
@@ -197,4 +212,4 @@ class KotterknifeTest {
view.id = id
return view
}
-} \ No newline at end of file
+}
diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/utils/UtilsAndroidTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/utils/UtilsAndroidTest.kt
new file mode 100644
index 0000000..665e0b2
--- /dev/null
+++ b/core/src/androidTest/kotlin/ca/allanwang/kau/utils/UtilsAndroidTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
+
+import android.graphics.Color
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+/**
+ * Created by Allan Wang on 2018-12-24.
+ *
+ * Misc test code that are dependent on android
+ */
+@RunWith(AndroidJUnit4::class)
+class UtilsAndroidTest {
+
+ @Test
+ fun colorBlend() {
+ assertEquals(0x22446688, 0x11335577.blendWith(0x33557799, 0.5f), "Failed to blend with 50% ratio")
+ assertEquals(0x11335577, 0x11335577.blendWith(0x33557799, 0.0f), "Failed to blend with 0% ratio")
+ assertEquals(0x33557799, 0x22446688.blendWith(0x33557799, 1.0f), "Failed to blend with 100% ratio")
+ }
+
+ @Test
+ fun lighten() {
+ assertEquals(Color.WHITE, Color.WHITE.lighten(0.35f), "Should not be able to further lighten white")
+ assertEquals(0xFFEEAAEA.toInt(), 0xFFDD55D5.toInt().lighten(0.5f), "Failed to lighten color by 50%")
+ }
+
+ @Test
+ fun darken() {
+ assertEquals(Color.BLACK, Color.BLACK.darken(0.35f), "Should not be able to further darken black")
+ assertEquals(0xFF224424.toInt(), 0xFF448848.toInt().darken(0.5f), "Failed to darken color by 50%")
+ }
+}
diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt
index f9ce24b..7ec2a41 100644
--- a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt
+++ b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt
@@ -1,8 +1,25 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.xml
-import android.support.test.InstrumentationRegistry
-import android.support.test.filters.MediumTest
-import android.support.test.runner.AndroidJUnit4
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import ca.allanwang.kau.test.R
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
@@ -14,26 +31,16 @@ import kotlin.test.assertEquals
@MediumTest
class FaqTest {
- @Test
- fun simpleTest() {
- InstrumentationRegistry.getTargetContext().kauParseFaq(R.xml.test_faq) { data ->
- assertEquals(2, data.size, "FAQ size is incorrect")
- assertEquals("1. This is a question", data.first().question.toString(), "First question does not match")
- assertEquals("This is an answer", data.first().answer.toString(), "First answer does not match")
- assertEquals("2. This is another question", data.last().question.toString(), "Second question does not match")
- assertEquals("This is another answer", data.last().answer.toString(), "Second answer does not match")
- }
- }
+ val context: Context
+ get() = ApplicationProvider.getApplicationContext<Context>()
@Test
- fun withoutNumbering() {
- InstrumentationRegistry.getTargetContext().kauParseFaq(R.xml.test_faq, false) { data ->
- assertEquals(2, data.size, "FAQ size is incorrect")
- assertEquals("This is a question", data.first().question.toString(), "First question does not match")
- assertEquals("This is an answer", data.first().answer.toString(), "First answer does not match")
- assertEquals("This is another question", data.last().question.toString(), "Second question does not match")
- assertEquals("This is another answer", data.last().answer.toString(), "Second answer does not match")
- }
+ fun simpleTest() {
+ val data = context.kauParseFaq(R.xml.test_faq, false)
+ assertEquals(2, data.size, "FAQ size is incorrect")
+ assertEquals("This is a question", data.first().question.toString(), "First question does not match")
+ assertEquals("This is an answer", data.first().answer.toString(), "First answer does not match")
+ assertEquals("This is another question", data.last().question.toString(), "Second question does not match")
+ assertEquals("This is another answer", data.last().answer.toString(), "Second answer does not match")
}
-
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt b/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt
index 2b9d91c..78661b1 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/email/EmailBuilder.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.email
import android.app.Activity
@@ -6,12 +21,15 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
-import android.support.annotation.StringRes
import android.util.DisplayMetrics
+import androidx.annotation.StringRes
import ca.allanwang.kau.R
import ca.allanwang.kau.logging.KL
-import ca.allanwang.kau.utils.*
-
+import ca.allanwang.kau.utils.boolean
+import ca.allanwang.kau.utils.installerPackageName
+import ca.allanwang.kau.utils.isAppInstalled
+import ca.allanwang.kau.utils.string
+import ca.allanwang.kau.utils.toast
/**
* Created by Allan Wang on 2017-06-20.
@@ -28,7 +46,7 @@ class EmailBuilder(val email: String, val subject: String) {
private var attachment: Uri? = null
fun checkPackage(packageName: String, appName: String) =
- packages.add(Package(packageName, appName))
+ packages.add(Package(packageName, appName))
fun addItem(key: String, value: String) = pairs.put(key, value)
@@ -45,24 +63,24 @@ class EmailBuilder(val email: String, val subject: String) {
fun getIntent(context: Context): Intent {
val intent = Intent(Intent.ACTION_SEND)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
- .putExtra(Intent.EXTRA_SUBJECT, subject)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
+ .putExtra(Intent.EXTRA_SUBJECT, subject)
val emailBuilder = StringBuilder()
emailBuilder.append(message).append("\n\n")
if (deviceDetails) {
- val deviceItems = linkedMapOf(
- "OS Version" to "${System.getProperty("os.version")} (${Build.VERSION.INCREMENTAL})",
- "OS SDK" to Build.VERSION.SDK_INT,
- "Device (Manufacturer)" to "${Build.DEVICE} (${Build.MANUFACTURER})",
- "Model (Product)" to "${Build.MODEL} (${Build.PRODUCT})",
- "Package Installer" to (context.installerPackageName ?: "None"),
- "Tablet" to context.boolean(R.bool.kau_is_tablet)
+ val deviceItems = mutableListOf(
+ "OS Version" to "${System.getProperty("os.version")} (${Build.VERSION.INCREMENTAL})",
+ "OS SDK" to Build.VERSION.SDK_INT,
+ "Device (Manufacturer)" to "${Build.DEVICE} (${Build.MANUFACTURER})",
+ "Model (Product)" to "${Build.MODEL} (${Build.PRODUCT})",
+ "Package Installer" to (context.installerPackageName ?: "None"),
+ "Tablet" to context.boolean(R.bool.kau_is_tablet)
)
if (context is Activity) {
val metric = DisplayMetrics()
context.windowManager.defaultDisplay.getMetrics(metric)
- deviceItems["Screen Dimensions"] = "${metric.widthPixels} x ${metric.heightPixels}"
+ deviceItems.add("Screen Dimensions" to "${metric.widthPixels} x ${metric.heightPixels}")
}
deviceItems.forEach { (k, v) -> emailBuilder.append("$k: $v\n") }
}
@@ -76,8 +94,8 @@ class EmailBuilder(val email: String, val subject: String) {
appInfo.versionCode.toString()
}
emailBuilder.append("\nApp: ").append(context.packageName)
- .append("\nApp Version Name: ").append(appInfo.versionName)
- .append("\nApp Version Code: ").append(versionCode).append("\n")
+ .append("\nApp Version Name: ").append(appInfo.versionName)
+ .append("\nApp Version Code: ").append(versionCode).append("\n")
} catch (e: PackageManager.NameNotFoundException) {
KL.e { "EmailBuilder packageInfo not found" }
}
@@ -112,7 +130,7 @@ class EmailBuilder(val email: String, val subject: String) {
val intent = getIntent(context)
intent.extras()
val packageName = intent.resolveActivity(context.packageManager)?.packageName
- ?: return context.toast(R.string.kau_error_no_email, log = true)
+ ?: return context.toast(R.string.kau_error_no_email, log = true)
val attachment = this.attachment
if (attachment != null) {
@@ -124,12 +142,12 @@ class EmailBuilder(val email: String, val subject: String) {
}
}
-fun Context.sendEmail(@StringRes emailId: Int, @StringRes subjectId: Int, builder: EmailBuilder.() -> Unit = {}) = sendEmail(string(emailId), string(subjectId), builder)
-
+fun Context.sendEmail(@StringRes emailId: Int, @StringRes subjectId: Int, builder: EmailBuilder.() -> Unit = {}) =
+ sendEmail(string(emailId), string(subjectId), builder)
fun Context.sendEmail(email: String, subject: String, builder: EmailBuilder.() -> Unit = {}) {
EmailBuilder(email, subject).apply {
builder()
execute(this@sendEmail)
}
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/internal/KauBaseActivity.kt b/core/src/main/kotlin/ca/allanwang/kau/internal/KauBaseActivity.kt
index 87d94ce..cb8f4bf 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/internal/KauBaseActivity.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/internal/KauBaseActivity.kt
@@ -1,7 +1,28 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.internal
-import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
import ca.allanwang.kau.permissions.kauOnRequestPermissionsResult
+import ca.allanwang.kau.utils.ContextHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
+import kotlin.coroutines.CoroutineContext
/**
* Created by Allan Wang on 2017-08-01.
@@ -11,11 +32,31 @@ import ca.allanwang.kau.permissions.kauOnRequestPermissionsResult
* Ensures that some singleton methods are called.
* This is simply a convenience class;
* you can always copy and paste this to your own class.
+ *
+ * This also implements [CoroutineScope] that adheres to the activity lifecycle.
+ * Note that by default, [SupervisorJob] is used, to avoid exceptions in one child from affecting that of another.
+ * The default job can be overridden within [defaultJob]
*/
-abstract class KauBaseActivity : AppCompatActivity() {
+abstract class KauBaseActivity : AppCompatActivity(), CoroutineScope {
+
+ open lateinit var job: Job
+ override val coroutineContext: CoroutineContext
+ get() = ContextHelper.dispatcher + job
+
+ open fun defaultJob(): Job = SupervisorJob()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ job = defaultJob()
+ }
+
+ override fun onDestroy() {
+ job.cancel()
+ super.onDestroy()
+ }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
kauOnRequestPermissionsResult(permissions, grantResults)
}
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt
index de5d148..ea13f73 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Debouncer.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
import ca.allanwang.kau.logging.KL
@@ -56,7 +71,6 @@ open class Debouncer(var interval: Long) {
task = null
}
}
-
}
/*
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/FlyWeight.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/FlyWeight.kt
deleted file mode 100644
index 03e98d2..0000000
--- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/FlyWeight.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package ca.allanwang.kau.kotlin
-
-/**
- * Created by Allan Wang on 26/12/17.
- *
- * Kotlin implementation of a flyweight design pattern
- * Values inside the map will be returned directly
- * Otherwise, it will be created with the supplier, saved, and returned
- * In the event a default is provided, the default takes precedence
- */
-fun <K : Any, V : Any> flyweight(creator: (K) -> V) = FlyWeight(creator)
-
-class FlyWeight<K : Any, V : Any>(private val creator: (key: K) -> V) : Map<K, V> {
-
- private val map = mutableMapOf<K, V>()
-
- override val entries: Set<Map.Entry<K, V>>
- get() = map.entries
- override val keys: Set<K>
- get() = map.keys
- override val size: Int
- get() = map.size
- override val values: Collection<V>
- get() = map.values
-
- override fun containsKey(key: K) = map.containsKey(key)
-
- override fun containsValue(value: V) = map.containsValue(value)
-
- override fun getOrDefault(key: K, defaultValue: V) = map.getOrDefault(key, defaultValue)
-
- override fun isEmpty() = map.isEmpty()
-
- override fun get(key: K): V {
- if (!map.containsKey(key))
- map.put(key, creator(key))
- return map[key]!!
- }
-
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt
index 0a45b65..e2a59d7 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyContext.kt
@@ -1,11 +1,26 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
import android.content.Context
-import android.support.annotation.AnimRes
-import android.support.annotation.InterpolatorRes
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.view.animation.Interpolator
+import androidx.annotation.AnimRes
+import androidx.annotation.InterpolatorRes
/**
* Created by Allan Wang on 2017-05-30.
@@ -47,5 +62,4 @@ class LazyContext<out T>(private val initializer: (context: Context) -> T, lock:
}
}
}
-
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt
index 979f7a7..ee38d48 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
import java.io.Serializable
@@ -80,4 +95,4 @@ class LazyResettableRegistry : ILazyResettableRegistry {
override fun invalidateAll() = lazyRegistry.forEach { it.invalidate() }
override fun clear() = lazyRegistry.clear()
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt
index 303153f..65d15a7 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Streams.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
/**
@@ -9,7 +24,6 @@ package ca.allanwang.kau.kotlin
* 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())
@@ -27,4 +41,4 @@ inline fun <T : Any> Iterator<T>.firstOrNull(predicate: (T) -> Boolean): T? {
if (predicate(data)) return data
}
return null
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Utils.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Utils.kt
index 1ba1de6..1e35ecf 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Utils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Utils.kt
@@ -1,6 +1,21 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
/**
* Created by Allan Wang on 07/04/18.
*/
-inline fun <reified T : Any> javaClass(): Class<T> = T::class.java \ No newline at end of file
+inline fun <reified T : Any> javaClass(): Class<T> = T::class.java
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Zip.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/Zip.kt
deleted file mode 100644
index 17ae5e5..0000000
--- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/Zip.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-package ca.allanwang.kau.kotlin
-
-import org.jetbrains.anko.doAsync
-import java.util.concurrent.atomic.AtomicInteger
-
-/**
- * Created by Allan Wang on 2017-08-06.
- *
- * Collection of zip methods that aim to replicate
- * <a href="http://reactivex.io/documentation/operators/zip.html">Reactive Zips</a>
- * For unit returning functions
- *
- * Typically, the functions will execute asynchronously and call their given callbacks when finished.
- * Once all callbacks are called, the final onFinish callback will be executed.
- *
- * There is also a helper zipper to wrap synchronous functions with Anko's doAsync to achieve the same results
- *
- * Note that not wrapping synchronous functions will render these methods useless,
- * as you can simply define an inline callback after all functions are finished
- */
-
-/**
- * Callback which will only execute the first time
- */
-open class ZipCallbackBase {
- var completed: Boolean = false
-
- inline operator fun invoke(callback: () -> Unit) {
- if (completed) return
- completed = true
- callback()
- }
-}
-
-class ZipCallback<T>(val onReceived: (T) -> Unit) : ZipCallbackBase() {
- operator fun invoke(result: T) = invoke { onReceived(result) }
-}
-
-class ZipEmptyCallback(val onReceived: () -> Unit) : ZipCallbackBase() {
- operator fun invoke() = invoke(onReceived)
-}
-
-/**
- * Given a default result, a series of tasks, and a finished callback,
- * this method will run all tasks and wait until all tasks emit a response
- * The response will then be sent back to the callback
- *
- * ALl tasks must invoke the task callback for [onFinished] to execute
- */
-inline fun <reified T> Collection<(ZipCallback<T>) -> Unit>.zip(
- defaultResult: T, crossinline onFinished: (results: Array<T>) -> Unit
-) {
- val result = Array(size) { defaultResult }
- val countDown = AtomicInteger(size)
- forEachIndexed { index, asyncFun ->
- asyncFun(ZipCallback {
- result[index] = it
- if (countDown.decrementAndGet() <= 0)
- onFinished(result)
- })
- }
-}
-
-/**
- * Simplified zip method with no finished callback arguments
- */
-inline fun Collection<(ZipEmptyCallback) -> Unit>.zip(crossinline onFinished: () -> Unit) {
- val countDown = AtomicInteger(size)
- forEach { asyncFun ->
- asyncFun(ZipEmptyCallback {
- if (countDown.decrementAndGet() <= 0)
- onFinished()
- })
- }
-}
-
-/**
- * Converts a collection of synchronous tasks to asynchronous tasks with a common callback
- */
-inline fun Collection<() -> Unit>.zipAsync(crossinline onFinished: () -> Unit) {
- map { synchronousFun ->
- { callback: ZipEmptyCallback ->
- doAsync {
- synchronousFun()
- callback()
- }; Unit
- }
- }.zip(onFinished)
-}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt
index 12f9606..7a6330f 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kpref
import android.content.Context
@@ -47,5 +62,4 @@ open class KPref {
operator fun get(key: String): ILazyResettable<*>? = prefMap[key]
open fun deleteKeys(): Array<String> = arrayOf()
-
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt
index b80479e..9813f24 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt
@@ -1,31 +1,47 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kpref
import ca.allanwang.kau.kotlin.ILazyResettable
-
fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit = {}) =
- KPrefDelegate(key, fallback, this, KPrefBooleanTransaction, postSetter)
+ KPrefDelegate(key, fallback, this, KPrefBooleanTransaction, postSetter)
fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit = {}) =
- KPrefDelegate(key, fallback, this, KPrefFloatTransaction, postSetter)
+ KPrefDelegate(key, fallback, this, KPrefFloatTransaction, postSetter)
-@Deprecated("Double is not supported in SharedPreferences; cast to float yourself",
- ReplaceWith("kpref(key, fallback.toFloat(), postSetter)"),
- DeprecationLevel.WARNING)
+@Deprecated(
+ "Double is not supported in SharedPreferences; cast to float yourself",
+ ReplaceWith("kpref(key, fallback.toFloat(), postSetter)"),
+ DeprecationLevel.WARNING
+)
fun KPref.kpref(key: String, fallback: Double, postSetter: (value: Float) -> Unit = {}) =
- kpref(key, fallback.toFloat(), postSetter)
+ kpref(key, fallback.toFloat(), postSetter)
fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit = {}) =
- KPrefDelegate(key, fallback, this, KPrefIntTransaction, postSetter)
+ KPrefDelegate(key, fallback, this, KPrefIntTransaction, postSetter)
fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit = {}) =
- KPrefDelegate(key, fallback, this, KPrefLongTransaction, postSetter)
+ KPrefDelegate(key, fallback, this, KPrefLongTransaction, postSetter)
fun KPref.kpref(key: String, fallback: Set<String>, postSetter: (value: Set<String>) -> Unit = {}) =
- KPrefDelegate(key, fallback, this, KPrefSetTransaction, postSetter)
+ KPrefDelegate(key, fallback, this, KPrefSetTransaction, postSetter)
fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit = {}) =
- KPrefDelegate(key, fallback, this, KPrefStringTransaction, postSetter)
+ KPrefDelegate(key, fallback, this, KPrefStringTransaction, postSetter)
/**
* Created by Allan Wang on 2017-06-07.
@@ -35,11 +51,11 @@ fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Un
* Also contains an optional mutable postSetter that will be called every time a new value is given
*/
class KPrefDelegate<T> internal constructor(
- private val key: String,
- private val fallback: T,
- private val pref: KPref,
- private val transaction: KPrefTransaction<T>,
- private var postSetter: (value: T) -> Unit = {}
+ private val key: String,
+ private val fallback: T,
+ private val pref: KPref,
+ private val transaction: KPrefTransaction<T>,
+ private var postSetter: (value: T) -> Unit = {}
) : ILazyResettable<T> {
private object UNINITIALIZED
@@ -91,4 +107,4 @@ class KPrefDelegate<T> internal constructor(
}
}
-class KPrefException(message: String) : IllegalAccessException(message) \ No newline at end of file
+class KPrefException(message: String) : IllegalAccessException(message)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt
index ed30a44..204e07e 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kpref
import ca.allanwang.kau.kotlin.ILazyResettable
@@ -12,7 +27,8 @@ fun KPref.kprefSingle(key: String) = KPrefSingleDelegate(key, this)
* All subsequent retrievals will be [false]
* This is useful for one time toggles such as showcasing items
*/
-class KPrefSingleDelegate internal constructor(private val key: String, private val pref: KPref, lock: Any? = null) : ILazyResettable<Boolean> {
+class KPrefSingleDelegate internal constructor(private val key: String, private val pref: KPref, lock: Any? = null) :
+ ILazyResettable<Boolean> {
@Volatile
private var _value: Boolean? = null
@@ -52,5 +68,4 @@ class KPrefSingleDelegate internal constructor(private val key: String, private
override fun isInitialized(): Boolean = _value != null
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet."
-
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt
index 773d208..1070e11 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kpref
import android.content.SharedPreferences
@@ -9,7 +24,7 @@ internal interface KPrefTransaction<T> {
internal object KPrefBooleanTransaction : KPrefTransaction<Boolean> {
override fun get(prefs: SharedPreferences, key: String, fallback: Boolean) =
- prefs.getBoolean(key, fallback)
+ prefs.getBoolean(key, fallback)
override fun set(editor: SharedPreferences.Editor, key: String, data: Boolean) {
editor.putBoolean(key, data)
@@ -18,7 +33,7 @@ internal object KPrefBooleanTransaction : KPrefTransaction<Boolean> {
internal object KPrefIntTransaction : KPrefTransaction<Int> {
override fun get(prefs: SharedPreferences, key: String, fallback: Int) =
- prefs.getInt(key, fallback)
+ prefs.getInt(key, fallback)
override fun set(editor: SharedPreferences.Editor, key: String, data: Int) {
editor.putInt(key, data)
@@ -27,7 +42,7 @@ internal object KPrefIntTransaction : KPrefTransaction<Int> {
internal object KPrefLongTransaction : KPrefTransaction<Long> {
override fun get(prefs: SharedPreferences, key: String, fallback: Long) =
- prefs.getLong(key, fallback)
+ prefs.getLong(key, fallback)
override fun set(editor: SharedPreferences.Editor, key: String, data: Long) {
editor.putLong(key, data)
@@ -36,7 +51,7 @@ internal object KPrefLongTransaction : KPrefTransaction<Long> {
internal object KPrefFloatTransaction : KPrefTransaction<Float> {
override fun get(prefs: SharedPreferences, key: String, fallback: Float) =
- prefs.getFloat(key, fallback)
+ prefs.getFloat(key, fallback)
override fun set(editor: SharedPreferences.Editor, key: String, data: Float) {
editor.putFloat(key, data)
@@ -45,7 +60,7 @@ internal object KPrefFloatTransaction : KPrefTransaction<Float> {
internal object KPrefStringTransaction : KPrefTransaction<String> {
override fun get(prefs: SharedPreferences, key: String, fallback: String) =
- prefs.getString(key, fallback)
+ prefs.getString(key, fallback)
override fun set(editor: SharedPreferences.Editor, key: String, data: String) {
editor.putString(key, data)
@@ -54,11 +69,9 @@ internal object KPrefStringTransaction : KPrefTransaction<String> {
internal object KPrefSetTransaction : KPrefTransaction<Set<String>> {
override fun get(prefs: SharedPreferences, key: String, fallback: Set<String>) =
- prefs.getStringSet(key, fallback)!!
+ prefs.getStringSet(key, fallback)!!
override fun set(editor: SharedPreferences.Editor, key: String, data: Set<String>) {
editor.putStringSet(key, data)
}
}
-
-
diff --git a/core/src/main/kotlin/ca/allanwang/kau/logging/KL.kt b/core/src/main/kotlin/ca/allanwang/kau/logging/KL.kt
index 9f48ab5..9fbc070 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/logging/KL.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/logging/KL.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.logging
import ca.allanwang.kau.BuildConfig
@@ -7,4 +22,13 @@ import ca.allanwang.kau.BuildConfig
*
* Internal KAU logger
*/
-object KL : KauLogger("KAU", { BuildConfig.DEBUG }) \ No newline at end of file
+object KL : KauLogger("KAU", { BuildConfig.DEBUG }) {
+
+ /**
+ * Logger with searchable tag and thread info
+ */
+ inline fun test(message: () -> Any?) {
+ if (BuildConfig.DEBUG)
+ d { "Test1234 ${Thread.currentThread().name} ${message()}" }
+ }
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/logging/KauLogger.kt b/core/src/main/kotlin/ca/allanwang/kau/logging/KauLogger.kt
index 799d32f..4562b00 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/logging/KauLogger.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/logging/KauLogger.kt
@@ -1,9 +1,24 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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:Suppress("NOTHING_TO_INLINE")
package ca.allanwang.kau.logging
-import android.os.Looper
import android.util.Log
+import ca.allanwang.kau.utils.kauIsMainThread
/**
* Created by Allan Wang on 2017-05-28.
@@ -25,15 +40,15 @@ import android.util.Log
* for production builds
*/
open class KauLogger(
- /**
- * Tag to be used for each log
- */
- val tag: String,
- /**
- * Toggle to dictate whether a message should be logged
- */
- var shouldLog: (priority: Int) -> Boolean = { true }) {
-
+ /**
+ * Tag to be used for each log
+ */
+ val tag: String,
+ /**
+ * Toggle to dictate whether a message should be logged
+ */
+ var shouldLog: (priority: Int) -> Boolean = { true }
+) {
inline fun v(message: () -> Any?) = log(Log.VERBOSE, message)
@@ -67,7 +82,7 @@ open class KauLogger(
inline fun checkThread(id: Int) {
d {
val name = Thread.currentThread().name
- val status = if (Looper.myLooper() == Looper.getMainLooper()) "is" else "is not"
+ val status = if (kauIsMainThread) "is" else "is not"
"$id $status in the main thread - thread name: $name"
}
}
@@ -96,16 +111,16 @@ class KauLoggerExtension(val tag: String, val logger: KauLogger) {
}
inline fun log(priority: Int, message: () -> Any?, t: Throwable? = null) =
- logger.log(priority, {
- val msg = message()?.toString()
- if (msg == null) null
- else "$tag: $msg"
- }, t)
+ logger.log(priority, {
+ val msg = message()?.toString()
+ if (msg == null) null
+ else "$tag: $msg"
+ }, t)
inline fun checkThread(id: Int) {
d {
val name = Thread.currentThread().name
- val status = if (Looper.myLooper() == Looper.getMainLooper()) "is" else "is not"
+ val status = if (kauIsMainThread) "is" else "is not"
"$id $status in the main thread - thread name: $name"
}
}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt b/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt
index 36456ec..96adfa3 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt
@@ -1,9 +1,25 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.permissions
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
-import android.support.v4.app.ActivityCompat
+import androidx.core.app.ActivityCompat
+import ca.allanwang.kau.kotlin.kauRemoveIf
import ca.allanwang.kau.kotlin.lazyContext
import ca.allanwang.kau.logging.KL
import ca.allanwang.kau.utils.KauException
@@ -12,43 +28,55 @@ import ca.allanwang.kau.utils.hasPermission
import ca.allanwang.kau.utils.toast
import java.lang.ref.WeakReference
-
/**
* Created by Allan Wang on 2017-07-03.
*
- * Permission manager that is decoupled from activities
- * Keeps track of pending requests, and warns about invalid requests
+ * Permission manager that is decoupled from activities.
+ * Keeps track of pending requests, and warns about invalid requests.
*/
internal object PermissionManager {
- private var requestInProgress = false
- private val pendingResults: MutableList<WeakReference<PermissionResult>> by lazy { mutableListOf<WeakReference<PermissionResult>>() }
+ private val pendingResults = mutableListOf<WeakReference<PermissionResult>>()
/**
* Retrieve permissions requested in our manifest
*/
- private val manifestPermission = lazyContext<Array<String>> {
+ private val manifestPermission = lazyContext<Set<String>> {
try {
- it.packageManager.getPackageInfo(it.packageName, PackageManager.GET_PERMISSIONS)?.requestedPermissions
- ?: emptyArray()
+ it.packageManager.getPackageInfo(
+ it.packageName,
+ PackageManager.GET_PERMISSIONS
+ )?.requestedPermissions?.toSet()
+ ?: emptySet()
} catch (e: Exception) {
- emptyArray()
+ emptySet()
}
}
- operator fun invoke(context: Context, permissions: Array<out String>, callback: (granted: Boolean, deniedPerm: String?) -> Unit) {
+ /**
+ * Registers a new permission request.
+ * It is expected that the callback will be called eventually, unless the parent activity is destroyed.
+ */
+ operator fun invoke(
+ context: Context,
+ permissions: Array<out String>,
+ callback: (granted: Boolean, deniedPerm: String?) -> Unit
+ ) {
KL.d { "Permission manager for: ${permissions.contentToString()}" }
if (!buildIsMarshmallowAndUp) return callback(true, null)
val missingPermissions = permissions.filter { !context.hasPermission(it) }
if (missingPermissions.isEmpty()) return callback(true, null)
pendingResults.add(WeakReference(PermissionResult(permissions, callback = callback)))
- if (!requestInProgress) {
- requestInProgress = true
+ if (pendingResults.size == 1) {
requestPermissions(context, missingPermissions.toTypedArray())
- } else KL.d { "Request is postponed since another one is still in progress; did you remember to override onRequestPermissionsResult?" }
+ } else {
+ KL.d { "Request is postponed since another one is still in progress; did you remember to override onRequestPermissionsResult?" }
+ }
}
- @Synchronized
+ /**
+ * Checks that the listed permissions can be requested, and submits the request to the provided activity
+ */
private fun requestPermissions(context: Context, permissions: Array<out String>) {
permissions.forEach {
if (!manifestPermission(context).contains(it)) {
@@ -58,36 +86,27 @@ internal object PermissionManager {
}
}
val activity = (context as? Activity)
- ?: throw KauException("Context is not an instance of an activity; cannot request permissions")
+ ?: throw KauException("Context is not an instance of an activity; cannot request permissions")
KL.i { "Requesting permissions ${permissions.contentToString()}" }
ActivityCompat.requestPermissions(activity, permissions, 1)
}
/**
- * Handles permission result by allowing accepted permissions for all pending requests
- * Also cleans up destroyed or completed pending requests
+ * Handles permission result by allowing accepted permissions for all pending requests.
+ * Also cleans up destroyed or completed pending requests.
*/
fun onRequestPermissionsResult(context: Context, permissions: Array<out String>, grantResults: IntArray) {
KL.i { "On permission result: pending ${pendingResults.size}" }
val count = Math.min(permissions.size, grantResults.size)
- val iter = pendingResults.iterator()
- while (iter.hasNext()) {
- val action = iter.next().get()
- if ((0 until count).any { action?.onResult(permissions[it], grantResults[it]) != false })
- iter.remove()
+ pendingResults.kauRemoveIf {
+ val action = it.get()
+ action == null || (0 until count).any { i -> action.onResult(permissions[i], grantResults[i]) }
}
- if (pendingResults.isEmpty())
- requestInProgress = false
- else {
- val action = pendingResults.map { it.get() }.firstOrNull { it != null }
- if (action == null) { //actions have been unlinked from their weak references
- pendingResults.clear()
- requestInProgress = false
- return
- }
- requestPermissions(context, action.permissions.toTypedArray())
+ val action = pendingResults.asSequence().map { it.get() }.firstOrNull { it != null }
+ if (action == null) { // actions have been unlinked from their weak references
+ pendingResults.clear()
+ return
}
- KL.i { "Post on permission result: pending ${pendingResults.size}" }
+ requestPermissions(context, action.permissions.toTypedArray())
}
-
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionResult.kt b/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionResult.kt
index ba3e6dd..599f6e8 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionResult.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionResult.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.permissions
import android.content.pm.PackageManager
@@ -21,8 +36,10 @@ class PermissionResult(permissions: Array<out String>, val callback: (granted: B
return true
}
permissions.remove(permission)
- if (permissions.isNotEmpty()) return false
+ if (permissions.isNotEmpty()) {
+ return false
+ }
callback(true, null)
return true
}
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt b/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt
index 248e484..3c90b05 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/permissions/Permissions.kt
@@ -1,11 +1,25 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.permissions
import android.Manifest
import android.app.Activity
import android.content.Context
import android.os.Build
-import android.support.annotation.RequiresApi
-
+import androidx.annotation.RequiresApi
/**
* Created by Allan Wang on 2017-07-02.
@@ -22,7 +36,8 @@ import android.support.annotation.RequiresApi
/**
* Hook that should be added inside all [Activity.onRequestPermissionsResult] so that the Permission manager can handle the responses
*/
-fun Activity.kauOnRequestPermissionsResult(permissions: Array<out String>, grantResults: IntArray) = PermissionManager.onRequestPermissionsResult(this, permissions, grantResults)
+fun Activity.kauOnRequestPermissionsResult(permissions: Array<out String>, grantResults: IntArray) =
+ PermissionManager.onRequestPermissionsResult(this, permissions, grantResults)
/**
* Request a permission with a callback
@@ -31,7 +46,10 @@ fun Activity.kauOnRequestPermissionsResult(permissions: Array<out String>, grant
* The [callback] returns [granted], which is true if all permissions are granted
* [deniedPerm] is the first denied permission, if granted is false
*/
-fun Context.kauRequestPermissions(vararg permissions: String, callback: (granted: Boolean, deniedPerm: String?) -> Unit) = PermissionManager(this, permissions, callback)
+fun Context.kauRequestPermissions(
+ vararg permissions: String,
+ callback: (granted: Boolean, deniedPerm: String?) -> Unit
+) = PermissionManager(this, permissions, callback)
/**
* See http://developer.android.com/guide/topics/security/permissions.html#normal-dangerous for a
@@ -72,4 +90,4 @@ const val PERMISSION_RECEIVE_MMS = Manifest.permission.RECEIVE_MMS
const val PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE
const val PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE
-const val PERMISSION_SYSTEM_ALERT_WINDOW = Manifest.permission.SYSTEM_ALERT_WINDOW \ No newline at end of file
+const val PERMISSION_SYSTEM_ALERT_WINDOW = Manifest.permission.SYSTEM_ALERT_WINDOW
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 f14f5cf..0b1dd88 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/RelativeSlider.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.swipe
/**
@@ -30,10 +45,14 @@ internal class RelativeSlider(var curPage: SwipeBackPage) : SwipeListener {
return
}
when (edgeFlag) {
- SWIPE_EDGE_LEFT -> page.swipeBackLayout.x = Math.min(-offset * Math.max(1 - percent, 0f) + DEFAULT_OFFSET, 0f)
- SWIPE_EDGE_RIGHT -> page.swipeBackLayout.x = Math.min(offset * Math.max(1 - percent, 0f) - DEFAULT_OFFSET, 0f)
- SWIPE_EDGE_TOP -> page.swipeBackLayout.y = Math.min(-offset * Math.max(1 - percent, 0f) + DEFAULT_OFFSET, 0f)
- SWIPE_EDGE_BOTTOM -> page.swipeBackLayout.y = Math.min(offset * Math.max(1 - percent, 0f) - DEFAULT_OFFSET, 0f)
+ SWIPE_EDGE_LEFT -> page.swipeBackLayout.x =
+ Math.min(-offset * Math.max(1 - percent, 0f) + DEFAULT_OFFSET, 0f)
+ SWIPE_EDGE_RIGHT -> page.swipeBackLayout.x =
+ Math.min(offset * Math.max(1 - percent, 0f) - DEFAULT_OFFSET, 0f)
+ SWIPE_EDGE_TOP -> page.swipeBackLayout.y =
+ Math.min(-offset * Math.max(1 - percent, 0f) + DEFAULT_OFFSET, 0f)
+ SWIPE_EDGE_BOTTOM -> page.swipeBackLayout.y =
+ Math.min(offset * Math.max(1 - percent, 0f) - DEFAULT_OFFSET, 0f)
}
}
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 018d7c7..1c6de12 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackHelper.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.swipe
import android.app.Activity
@@ -5,7 +20,7 @@ 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.*
+import java.util.Stack
/**
* Singleton to hold our swipe stack
@@ -16,7 +31,8 @@ internal object SwipeBackHelper {
private val pageStack = Stack<SwipeBackPage>()
- private operator fun get(activity: Activity): SwipeBackPage? = pageStack.firstOrNull { it.activityRef.get() === activity }
+ private operator fun get(activity: Activity): SwipeBackPage? =
+ pageStack.firstOrNull { it.activityRef.get() === activity }
fun onCreate(activity: Activity, builder: SwipeBackContract.() -> Unit = {}) {
val page = this[activity] ?: pageStack.push(SwipeBackPage(activity).apply { builder() })
@@ -93,4 +109,4 @@ const val SWIPE_EDGE_RIGHT = ViewDragHelper.EDGE_RIGHT
const val SWIPE_EDGE_TOP = ViewDragHelper.EDGE_TOP
-const val SWIPE_EDGE_BOTTOM = ViewDragHelper.EDGE_BOTTOM \ No newline at end of file
+const val SWIPE_EDGE_BOTTOM = ViewDragHelper.EDGE_BOTTOM
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 a323e6c..1f564ce 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt
@@ -1,15 +1,30 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.swipe
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.Canvas
-import android.support.v4.view.ViewCompat
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
+import androidx.core.view.ViewCompat
import ca.allanwang.kau.logging.KL
import ca.allanwang.kau.utils.adjustAlpha
import ca.allanwang.kau.utils.navigationBarColor
@@ -23,7 +38,10 @@ 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
*/
-internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0
+internal class SwipeBackLayout @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyle: Int = 0
) : FrameLayout(context, attrs, defStyle), SwipeBackContract, SwipeBackContractInternal {
override val swipeBackLayout: SwipeBackLayout
@@ -96,11 +114,9 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs
override fun onEdgeTouch() {}
override fun onScrollToClose(edgeFlag: Int) {}
-
}
}
-
private var inLayout: Boolean = false
override var edgeSize: Int
@@ -158,7 +174,8 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs
}
override fun setEdgeSizePercent(swipeEdgePercent: Float) {
- edgeSize = ((if (horizontal) resources.displayMetrics.widthPixels else resources.displayMetrics.heightPixels) * swipeEdgePercent).toInt()
+ edgeSize =
+ ((if (horizontal) resources.displayMetrics.widthPixels else resources.displayMetrics.heightPixels) * swipeEdgePercent).toInt()
}
/**
@@ -206,7 +223,7 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs
*/
override fun scrollToFinishActivity() {
val contentView = contentViewRef.get()
- ?: return KL.e { "KauSwipe cannot scroll to finish as contentView is null. Is onPostCreate called?" }
+ ?: return KL.e { "KauSwipe cannot scroll to finish as contentView is null. Is onPostCreate called?" }
val swipeWidth = contentView.width + OVERSCROLL_DISTANCE
val swipeHeight = contentView.height + OVERSCROLL_DISTANCE
var top = 0
@@ -243,7 +260,7 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs
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?" }
+ ?: return KL.e { "KauSwipe cannot change layout as contentView is null. Is onPostCreate called?" }
inLayout = true
val xOffset: Int
val yOffset: Int
@@ -346,11 +363,12 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs
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?" }
+ ?: 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)
@@ -375,10 +393,11 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs
var result = Pair(0, 0)
if (scrollPercent <= scrollThreshold) {
//threshold not met; check velocities
- if ((edgeFlag == SWIPE_EDGE_LEFT && xvel > MIN_FLING_VELOCITY)
- || (edgeFlag == SWIPE_EDGE_RIGHT && xvel < -MIN_FLING_VELOCITY)
- || (edgeFlag == SWIPE_EDGE_TOP && yvel > MIN_FLING_VELOCITY)
- || (edgeFlag == SWIPE_EDGE_BOTTOM && yvel < -MIN_FLING_VELOCITY))
+ if ((edgeFlag == SWIPE_EDGE_LEFT && xvel > MIN_FLING_VELOCITY) ||
+ (edgeFlag == SWIPE_EDGE_RIGHT && xvel < -MIN_FLING_VELOCITY) ||
+ (edgeFlag == SWIPE_EDGE_TOP && yvel > MIN_FLING_VELOCITY) ||
+ (edgeFlag == SWIPE_EDGE_BOTTOM && yvel < -MIN_FLING_VELOCITY)
+ )
result = exitCaptureOffsets(edgeFlag, releasedChild)
} else {
//threshold met; fling to designated side
@@ -431,6 +450,5 @@ internal class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs
const val DEFAULT_SCROLL_THRESHOLD = 0.3f
const val OVERSCROLL_DISTANCE = 10
-
}
}
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 4dba622..bc5b459 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackPage.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.swipe
import android.app.Activity
@@ -24,7 +39,8 @@ internal class SwipeBackPage(activity: Activity) : SwipeBackContractInternal by
init {
activity.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
activity.window.decorView.setBackgroundColor(Color.TRANSPARENT)
- swipeBackLayout.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ swipeBackLayout.layoutParams =
+ ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
slider = RelativeSlider(this)
}
@@ -41,7 +57,7 @@ internal class SwipeBackPage(activity: Activity) : SwipeBackContractInternal by
private fun handleLayout() {
val activity = activityRef.get()
- ?: return KL.v { "KauSwipe activity ref gone during handleLayout" }
+ ?: return KL.v { "KauSwipe activity ref gone during handleLayout" }
if (swipeEnabled) swipeBackLayout.attachToActivity(activity)
else swipeBackLayout.removeFromActivity(activity)
}
@@ -50,7 +66,6 @@ internal class SwipeBackPage(activity: Activity) : SwipeBackContractInternal by
swipeBackLayout.scrollThreshold = percent
return this
}
-
}
internal interface SwipeBackContractInternal : SwipeBackContract {
@@ -104,4 +119,4 @@ interface SwipeBackContract {
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/SwipeListener.kt b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeListener.kt
index 3ea62b5..07f8eb8 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeListener.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeListener.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.swipe
interface SwipeListener {
@@ -16,4 +31,4 @@ interface SwipeListener {
* Invoked when scroll percent over the threshold for the first time
*/
fun onScrollToClose(edgeFlag: Int)
-} \ 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 566e9e5..ac7fb7e 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java
+++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java
@@ -1,7 +1,7 @@
package ca.allanwang.kau.swipe;
import android.content.Context;
-import android.support.v4.view.ViewCompat;
+import androidx.core.view.ViewCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -25,7 +25,7 @@ import static ca.allanwang.kau.swipe.SwipeBackHelperKt.SWIPE_EDGE_TOP;
* of useful operations and state tracking for allowing a user to drag and reposition
* views within their parent ViewGroup.
* <p>
- * This is an extension of {@link android.support.v4.widget.ViewDragHelper}
+ * This is an extension of {@link androidx.core.widget.ViewDragHelper}
* Along with additional methods defined in {@link ViewDragHelperExtras}
*/
class ViewDragHelper implements ViewDragHelperExtras {
diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt
index b98a47e..a46e6c5 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/ui/ProgressAnimator.kt
@@ -1,9 +1,24 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.ui
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
-import android.support.annotation.VisibleForTesting
+import androidx.annotation.VisibleForTesting
import ca.allanwang.kau.kotlin.kauRemoveIf
/**
@@ -37,8 +52,7 @@ class ProgressAnimator private constructor() : ValueAnimator() {
isCancelled = false
}
})
- apply(builder)
- }
+ }.apply(builder)
/**
* Gets output of a linear function starting at [start] when [progress] is 0 and [end] when [progress] is 1 at point [progress].
@@ -54,7 +68,6 @@ class ProgressAnimator private constructor() : ValueAnimator() {
start + (end - start) * trueProgress
}
}
-
}
private val animators: MutableList<ProgressDisposableAction> = mutableListOf()
@@ -69,7 +82,6 @@ class ProgressAnimator private constructor() : ValueAnimator() {
val animatorCount get() = animators.size
-
/**
* Converts an action to a disposable action
*/
@@ -95,13 +107,13 @@ class ProgressAnimator private constructor() : ValueAnimator() {
}
fun withAnimator(action: ProgressAction) =
- withDisposableAnimator(action.asDisposable())
+ withDisposableAnimator(action.asDisposable())
/**
* Range animator. Multiples the range by the current float progress before emission
*/
fun withAnimator(from: Float, to: Float, action: ProgressAction) =
- withDisposableAnimator(from, to, action.asDisposable())
+ withDisposableAnimator(from, to, action.asDisposable())
fun withDisposableAnimator(action: ProgressDisposableAction) = animators.add(action)
@@ -170,4 +182,4 @@ class ProgressAnimator private constructor() : ValueAnimator() {
private typealias ProgressAction = (Float) -> Unit
private typealias ProgressDisposableAction = (Float) -> Boolean
private typealias ProgressRunnable = () -> Unit
-private typealias ProgressDisposableRunnable = () -> Boolean \ No newline at end of file
+private typealias ProgressDisposableRunnable = () -> Boolean
diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/SimpleRippleDrawable.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/SimpleRippleDrawable.kt
index b92b222..684a11c 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/ui/SimpleRippleDrawable.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/ui/SimpleRippleDrawable.kt
@@ -1,11 +1,26 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.ui
import android.content.res.ColorStateList
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.RippleDrawable
import android.os.Build
-import android.support.annotation.ColorInt
-import android.support.annotation.RequiresApi
+import androidx.annotation.ColorInt
+import androidx.annotation.RequiresApi
import ca.allanwang.kau.utils.adjustAlpha
/**
@@ -19,4 +34,4 @@ fun createSimpleRippleDrawable(@ColorInt foregroundColor: Int, @ColorInt backgro
val content = ColorDrawable(backgroundColor)
val mask = ColorDrawable(foregroundColor.adjustAlpha(0.16f))
return RippleDrawable(states, content, mask)
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt
index 8923775..b2a0d27 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/ui/views/CollapsibleViewDelegate.kt
@@ -1,8 +1,27 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.ui.views
import android.animation.ValueAnimator
import android.view.View
-import ca.allanwang.kau.utils.*
+import ca.allanwang.kau.utils.KAU_COLLAPSED
+import ca.allanwang.kau.utils.KAU_COLLAPSING
+import ca.allanwang.kau.utils.KAU_EXPANDED
+import ca.allanwang.kau.utils.KAU_EXPANDING
+import ca.allanwang.kau.utils.goneIf
import java.lang.ref.WeakReference
/**
@@ -48,10 +67,10 @@ class CollapsibleViewDelegate : CollapsibleView {
if (v > 1) v = 1f
else if (v < 0) v = 0f
stateHolder =
- if (v == 0f) KAU_COLLAPSED
- else if (v == 1f) KAU_EXPANDED
- else if (v - field < 0) KAU_COLLAPSING
- else KAU_EXPANDING
+ if (v == 0f) KAU_COLLAPSED
+ else if (v == 1f) KAU_EXPANDED
+ else if (v - field < 0) KAU_COLLAPSING
+ else KAU_EXPANDING
field = v
view?.goneIf(state == KAU_COLLAPSED)
view?.requestLayout()
@@ -101,5 +120,4 @@ class CollapsibleViewDelegate : CollapsibleView {
val target = if (expand) 1f else 0f
if (animate) animateSize(target) else expansion = target
}
-
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt
index 716fd71..6481306 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/ui/views/MeasureSpecDelegate.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.ui.views
import android.content.Context
@@ -84,10 +99,13 @@ class MeasureSpecDelegate : MeasureSpecContract {
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MeasureSpecDelegate)
relativeWidth = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeWidth, relativeWidth)
relativeHeight = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeHeight, relativeHeight)
- relativeWidthToParent = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeWidthToParent, relativeWidthToParent)
- relativeHeightToParent = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeHeightToParent, relativeHeightToParent)
+ relativeWidthToParent =
+ styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeWidthToParent, relativeWidthToParent)
+ relativeHeightToParent =
+ styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_relativeHeightToParent, relativeHeightToParent)
postRelativeWidth = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_postRelativeWidth, postRelativeWidth)
- postRelativeHeight = styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_postRelativeHeight, postRelativeHeight)
+ postRelativeHeight =
+ styledAttrs.getFloat(R.styleable.MeasureSpecDelegate_postRelativeHeight, postRelativeHeight)
styledAttrs.recycle()
}
@@ -115,5 +133,4 @@ class MeasureSpecDelegate : MeasureSpecContract {
private val Float.measureSpec: Int
get() = View.MeasureSpec.makeMeasureSpec(this.toInt(), View.MeasureSpec.EXACTLY)
-
}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/ui/views/RippleCanvas.kt b/core/src/main/kotlin/ca/allanwang/kau/ui/views/RippleCanvas.kt
index 3d86419..176b9ea 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/ui/views/RippleCanvas.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/ui/views/RippleCanvas.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.ui.views
import android.animation.Animator
@@ -5,7 +20,11 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.content.Context
-import android.graphics.*
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
import android.util.AttributeSet
import android.view.View
@@ -17,7 +36,9 @@ import android.view.View
* Supports multiple ripples from varying locations
*/
class RippleCanvas @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint: Paint = Paint().apply {
isAntiAlias = true
@@ -53,11 +74,13 @@ class RippleCanvas @JvmOverloads constructor(
/**
* Creates a ripple effect from the given starting values
*/
- fun ripple(color: Int,
- startX: Float = 0f,
- startY: Float = 0f,
- duration: Long = 600L,
- callback: (() -> Unit)? = null) {
+ fun ripple(
+ color: Int,
+ startX: Float = 0f,
+ startY: Float = 0f,
+ duration: Long = 600L,
+ callback: (() -> Unit)? = null
+ ) {
val w = width.toFloat()
val h = height.toFloat()
val x = when (startX) {
@@ -112,11 +135,13 @@ class RippleCanvas @JvmOverloads constructor(
animator.start()
}
- internal class Ripple(val color: Int,
- val x: Float,
- val y: Float,
- var radius: Float,
- val maxRadius: Float)
+ internal class Ripple(
+ val color: Int,
+ val x: Float,
+ val y: Float,
+ var radius: Float,
+ val maxRadius: Float
+ )
companion object {
const val MIDDLE = -1.0f
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt
index ab0e59f..21141f1 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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:Suppress("NOTHING_TO_INLINE")
package ca.allanwang.kau.utils
@@ -11,15 +26,15 @@ import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
-import android.support.annotation.ColorInt
-import android.support.annotation.RequiresApi
-import android.support.annotation.StringRes
-import android.support.design.widget.Snackbar
import android.view.Menu
import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.ColorInt
+import androidx.annotation.RequiresApi
+import androidx.annotation.StringRes
import ca.allanwang.kau.R
+import com.google.android.material.snackbar.Snackbar
import com.mikepenz.iconics.typeface.IIcon
-import org.jetbrains.anko.contentView
/**
* Created by Allan Wang on 2017-06-21.
@@ -36,19 +51,22 @@ annotation class KauActivity
*/
@Suppress("DEPRECATION")
inline fun <reified T : Activity> Activity.startActivityForResult(
- requestCode: Int,
- bundleBuilder: Bundle.() -> Unit = {},
- intentBuilder: Intent.() -> Unit = {}
+ requestCode: Int,
+ bundleBuilder: Bundle.() -> Unit = {},
+ intentBuilder: Intent.() -> Unit = {}
) = startActivityForResult(T::class.java, requestCode, bundleBuilder, intentBuilder)
-@Deprecated("Use reified generic instead of passing class",
- ReplaceWith("startActivityForResult<T>(requestCode, bundleBuilder, intentBuilder)"),
- DeprecationLevel.WARNING)
+@Deprecated(
+ "Use reified generic instead of passing class",
+ ReplaceWith("startActivityForResult<T>(requestCode, bundleBuilder, intentBuilder)"),
+ DeprecationLevel.WARNING
+)
inline fun <T : Activity> Activity.startActivityForResult(
- clazz: Class<T>,
- requestCode: Int,
- bundleBuilder: Bundle.() -> Unit = {},
- intentBuilder: Intent.() -> Unit = {}) {
+ clazz: Class<T>,
+ requestCode: Int,
+ bundleBuilder: Bundle.() -> Unit = {},
+ intentBuilder: Intent.() -> Unit = {}
+) {
val intent = Intent(this, clazz)
intent.intentBuilder()
val bundle = Bundle()
@@ -72,13 +90,12 @@ inline fun Activity.restart(intentBuilder: Intent.() -> Unit = {}) {
overridePendingTransition(R.anim.kau_fade_in, R.anim.kau_fade_out)
}
-
/**
* Force restart an entire application
*/
@RequiresApi(Build.VERSION_CODES.M)
inline fun Activity.restartApplication() {
- val intent = packageManager.getLaunchIntentForPackage(packageName)
+ val intent = packageManager.getLaunchIntentForPackage(packageName)!!
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
val pending = PendingIntent.getActivity(this, 666, intent, PendingIntent.FLAG_CANCEL_CURRENT)
val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager
@@ -119,8 +136,8 @@ inline var Activity.statusBarLight: Boolean
if (buildIsMarshmallowAndUp) {
val flags = window.decorView.systemUiVisibility
window.decorView.systemUiVisibility =
- if (value) flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
- else flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
+ if (value) flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ else flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
}
@@ -135,10 +152,33 @@ fun Context.setMenuIcons(menu: Menu, @ColorInt color: Int = Color.WHITE, vararg
}
}
-inline fun Activity.hideKeyboard() = currentFocus.hideKeyboard()
-
-inline fun Activity.showKeyboard() = currentFocus.showKeyboard()
+inline fun Activity.hideKeyboard() {
+ currentFocus?.hideKeyboard()
+}
-inline fun Activity.snackbar(text: String, duration: Int = Snackbar.LENGTH_LONG, noinline builder: Snackbar.() -> Unit = {}) = contentView!!.snackbar(text, duration, builder)
+inline fun Activity.showKeyboard() {
+ currentFocus?.showKeyboard()
+}
-inline fun Activity.snackbar(@StringRes textId: Int, duration: Int = Snackbar.LENGTH_LONG, noinline builder: Snackbar.() -> Unit = {}) = contentView!!.snackbar(textId, duration, builder) \ No newline at end of file
+/**
+ * Gets the view set by [Activity.setContentView] if it exists.
+ *
+ * Taken courtesy of <a href="https://github.com/Kotlin/anko">Anko</a>
+ *
+ * Previously, Anko was a dependency in KAU, but has been removed on 12/24/2018
+ * as most of the methods weren't used
+ */
+inline val Activity.contentView: View?
+ get() = (findViewById(android.R.id.content) as? ViewGroup)?.getChildAt(0)
+
+inline fun Activity.snackbar(
+ text: String,
+ duration: Int = Snackbar.LENGTH_LONG,
+ noinline builder: Snackbar.() -> Unit = {}
+) = contentView!!.snackbar(text, duration, builder)
+
+inline fun Activity.snackbar(
+ @StringRes textId: Int,
+ duration: Int = Snackbar.LENGTH_LONG,
+ noinline builder: Snackbar.() -> Unit = {}
+) = contentView!!.snackbar(textId, duration, builder)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/AnimHolder.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/AnimHolder.kt
index 2767f04..0062361 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/AnimHolder.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/AnimHolder.kt
@@ -1,7 +1,22 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.os.Build
-import android.support.annotation.RequiresApi
+import androidx.annotation.RequiresApi
import ca.allanwang.kau.kotlin.lazyInterpolator
/**
@@ -14,5 +29,4 @@ object AnimHolder {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
val fastOutSlowInInterpolator = lazyInterpolator(android.R.interpolator.fast_out_linear_in)
val decelerateInterpolator = lazyInterpolator(android.R.interpolator.decelerate_cubic)
-
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/AnimUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/AnimUtils.kt
index a287cf2..0a548ce 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/AnimUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/AnimUtils.kt
@@ -1,15 +1,30 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.annotation.SuppressLint
-import android.support.annotation.StringRes
import android.view.View
import android.view.ViewAnimationUtils
import android.view.ViewPropertyAnimator
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.TextView
+import androidx.annotation.StringRes
/**
* Created by Allan Wang on 2017-06-01.
@@ -19,7 +34,15 @@ import android.widget.TextView
@SuppressLint("NewApi")
@KauUtils
-fun View.circularReveal(x: Int = 0, y: Int = 0, offset: Long = 0L, radius: Float = -1.0f, duration: Long = 500L, onStart: (() -> Unit)? = null, onFinish: (() -> Unit)? = null) {
+fun View.circularReveal(
+ x: Int = 0,
+ y: Int = 0,
+ offset: Long = 0L,
+ radius: Float = -1.0f,
+ duration: Long = 500L,
+ onStart: (() -> Unit)? = null,
+ onFinish: (() -> Unit)? = null
+) {
if (!isAttachedToWindow) {
onStart?.invoke()
visible()
@@ -29,7 +52,10 @@ fun View.circularReveal(x: Int = 0, y: Int = 0, offset: Long = 0L, radius: Float
if (!buildIsLollipopAndUp) return fadeIn(offset, duration, onStart, onFinish)
val r = if (radius >= 0) radius
- else Math.max(Math.hypot(x.toDouble(), y.toDouble()), Math.hypot((width - x.toDouble()), (height - y.toDouble()))).toFloat()
+ else Math.max(
+ Math.hypot(x.toDouble(), y.toDouble()),
+ Math.hypot((width - x.toDouble()), (height - y.toDouble()))
+ ).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(this, x, y, 0f, r).setDuration(duration)
anim.startDelay = offset
@@ -47,7 +73,15 @@ fun View.circularReveal(x: Int = 0, y: Int = 0, offset: Long = 0L, radius: Float
@SuppressLint("NewApi")
@KauUtils
-fun View.circularHide(x: Int = 0, y: Int = 0, offset: Long = 0L, radius: Float = -1.0f, duration: Long = 500L, onStart: (() -> Unit)? = null, onFinish: (() -> Unit)? = null) {
+fun View.circularHide(
+ x: Int = 0,
+ y: Int = 0,
+ offset: Long = 0L,
+ radius: Float = -1.0f,
+ duration: Long = 500L,
+ onStart: (() -> Unit)? = null,
+ onFinish: (() -> Unit)? = null
+) {
if (!isAttachedToWindow) {
onStart?.invoke()
invisible()
@@ -57,7 +91,10 @@ fun View.circularHide(x: Int = 0, y: Int = 0, offset: Long = 0L, radius: Float =
if (!buildIsLollipopAndUp) return fadeOut(offset, duration, onStart, onFinish)
val r = if (radius >= 0) radius
- else Math.max(Math.hypot(x.toDouble(), y.toDouble()), Math.hypot((width - x.toDouble()), (height - y.toDouble()))).toFloat()
+ else Math.max(
+ Math.hypot(x.toDouble(), y.toDouble()),
+ Math.hypot((width - x.toDouble()), (height - y.toDouble()))
+ ).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(this, x, y, r, 0f).setDuration(duration)
anim.startDelay = offset
@@ -75,7 +112,12 @@ fun View.circularHide(x: Int = 0, y: Int = 0, offset: Long = 0L, radius: Float =
}
@KauUtils
-fun View.fadeIn(offset: Long = 0L, duration: Long = 200L, onStart: (() -> Unit)? = null, onFinish: (() -> Unit)? = null) {
+fun View.fadeIn(
+ offset: Long = 0L,
+ duration: Long = 200L,
+ onStart: (() -> Unit)? = null,
+ onFinish: (() -> Unit)? = null
+) {
if (!isAttachedToWindow) {
onStart?.invoke()
visible()
@@ -97,7 +139,12 @@ fun View.fadeIn(offset: Long = 0L, duration: Long = 200L, onStart: (() -> Unit)?
}
@KauUtils
-fun View.fadeOut(offset: Long = 0L, duration: Long = 200L, onStart: (() -> Unit)? = null, onFinish: (() -> Unit)? = null) {
+fun View.fadeOut(
+ offset: Long = 0L,
+ duration: Long = 200L,
+ onStart: (() -> Unit)? = null,
+ onFinish: (() -> Unit)? = null
+) {
if (!isAttachedToWindow) {
onStart?.invoke()
invisible()
@@ -130,7 +177,8 @@ fun TextView.setTextWithFade(text: String, duration: Long = 200, onFinish: (() -
}
@KauUtils
-fun TextView.setTextWithFade(@StringRes textId: Int, duration: Long = 200, onFinish: (() -> Unit)? = null) = setTextWithFade(context.getString(textId), duration, onFinish)
+fun TextView.setTextWithFade(@StringRes textId: Int, duration: Long = 200, onFinish: (() -> Unit)? = null) =
+ setTextWithFade(context.getString(textId), duration, onFinish)
@KauUtils
-fun ViewPropertyAnimator.scaleXY(value: Float) = scaleX(value).scaleY(value) \ No newline at end of file
+fun ViewPropertyAnimator.scaleXY(value: Float) = scaleX(value).scaleY(value)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt
index 82cd577..40c1c72 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.annotation.SuppressLint
@@ -5,10 +20,12 @@ import android.app.Activity
import android.app.ActivityOptions
import android.content.Context
import android.os.Bundle
-import android.support.annotation.AnimRes
+import android.os.Parcelable
import android.util.Pair
import android.view.View
+import androidx.annotation.AnimRes
import ca.allanwang.kau.R
+import java.io.Serializable
/**
* Created by Allan Wang on 10/12/17.
@@ -22,6 +39,56 @@ infix fun Bundle.with(bundle: Bundle?): Bundle {
}
/**
+ * Saves all bundle args based on their respective types.
+ *
+ * Taken courtesy of <a href="https://github.com/Kotlin/anko">Anko</a>
+ *
+ * Previously, Anko was a dependency in KAU, but has been removed on 12/24/2018
+ * as most of the methods weren't used
+ */
+fun bundleOf(vararg params: kotlin.Pair<String, Any?>): Bundle {
+ val b = Bundle()
+ for (p in params) {
+ val (k, v) = p
+ when (v) {
+ null -> b.putSerializable(k, null)
+ is Boolean -> b.putBoolean(k, v)
+ is Byte -> b.putByte(k, v)
+ is Char -> b.putChar(k, v)
+ is Short -> b.putShort(k, v)
+ is Int -> b.putInt(k, v)
+ is Long -> b.putLong(k, v)
+ is Float -> b.putFloat(k, v)
+ is Double -> b.putDouble(k, v)
+ is String -> b.putString(k, v)
+ is CharSequence -> b.putCharSequence(k, v)
+ is Parcelable -> b.putParcelable(k, v)
+ is Serializable -> b.putSerializable(k, v)
+ is BooleanArray -> b.putBooleanArray(k, v)
+ is ByteArray -> b.putByteArray(k, v)
+ is CharArray -> b.putCharArray(k, v)
+ is DoubleArray -> b.putDoubleArray(k, v)
+ is FloatArray -> b.putFloatArray(k, v)
+ is IntArray -> b.putIntArray(k, v)
+ is LongArray -> b.putLongArray(k, v)
+ is Array<*> -> {
+ @Suppress("UNCHECKED_CAST")
+ when {
+ v.isArrayOf<Parcelable>() -> b.putParcelableArray(k, v as Array<out Parcelable>)
+ v.isArrayOf<CharSequence>() -> b.putCharSequenceArray(k, v as Array<out CharSequence>)
+ v.isArrayOf<String>() -> b.putStringArray(k, v as Array<out String>)
+ else -> throw KauException("Unsupported bundle component (${v.javaClass})")
+ }
+ }
+ is ShortArray -> b.putShortArray(k, v)
+ is Bundle -> b.putBundle(k, v)
+ else -> throw KauException("Unsupported bundle component (${v.javaClass})")
+ }
+ }
+ return b
+}
+
+/**
* Adds transition bundle if context is activity and build is lollipop+
*/
@SuppressLint("NewApi")
@@ -36,34 +103,46 @@ fun Bundle.withSceneTransitionAnimation(context: Context) {
* create a scene transition animation
*/
fun Bundle.withSceneTransitionAnimation(parent: View, data: Map<Int, String>) =
- withSceneTransitionAnimation(parent.context, data.mapKeys { (id, _) ->
- parent.findViewById<View>(id)
- })
+ withSceneTransitionAnimation(parent.context, data.mapKeys { (id, _) ->
+ parent.findViewById<View>(id)
+ })
/**
* Given a mapping of views to tags,
* create a scene transition animation
*/
@SuppressLint("NewApi")
-fun Bundle.withSceneTransitionAnimation(context: Context, data: Map<View, String>) {
+fun Bundle.withSceneTransitionAnimation(context: Context, data: Map<out View, String>) {
if (context !is Activity || !buildIsLollipopAndUp) return
- val options = ActivityOptions.makeSceneTransitionAnimation(context,
- *data.map { (view, tag) -> Pair(view, tag) }.toTypedArray())
+ val options = ActivityOptions.makeSceneTransitionAnimation(
+ context,
+ *data.map { (view, tag) -> Pair(view, tag) }.toTypedArray()
+ )
putAll(options.toBundle())
}
-fun Bundle.withCustomAnimation(context: Context,
- @AnimRes enterResId: Int,
- @AnimRes exitResId: Int) {
- this with ActivityOptions.makeCustomAnimation(context,
- enterResId, exitResId).toBundle()
+fun Bundle.withCustomAnimation(
+ context: Context,
+ @AnimRes enterResId: Int,
+ @AnimRes exitResId: Int
+) {
+ this with ActivityOptions.makeCustomAnimation(
+ context,
+ enterResId, exitResId
+ ).toBundle()
}
-fun Bundle.withSlideIn(context: Context) = withCustomAnimation(context,
- R.anim.kau_slide_in_right, R.anim.kau_fade_out)
+fun Bundle.withSlideIn(context: Context) = withCustomAnimation(
+ context,
+ R.anim.kau_slide_in_right, R.anim.kau_fade_out
+)
-fun Bundle.withSlideOut(context: Context) = withCustomAnimation(context,
- R.anim.kau_fade_in, R.anim.kau_slide_out_right_top)
+fun Bundle.withSlideOut(context: Context) = withCustomAnimation(
+ context,
+ R.anim.kau_fade_in, R.anim.kau_slide_out_right_top
+)
-fun Bundle.withFade(context: Context) = withCustomAnimation(context,
- android.R.anim.fade_in, android.R.anim.fade_out) \ No newline at end of file
+fun Bundle.withFade(context: Context) = withCustomAnimation(
+ context,
+ android.R.anim.fade_in, android.R.anim.fade_out
+)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt
index 236f2ca..bbb8953 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.annotation.SuppressLint
@@ -7,15 +22,21 @@ import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.os.Build
-import android.support.annotation.ColorInt
-import android.support.annotation.FloatRange
-import android.support.annotation.IntRange
-import android.support.v4.graphics.drawable.DrawableCompat
-import android.support.v7.widget.AppCompatEditText
-import android.support.v7.widget.Toolbar
-import android.widget.*
+import android.widget.CheckBox
+import android.widget.EditText
+import android.widget.ImageButton
+import android.widget.ProgressBar
+import android.widget.RadioButton
+import android.widget.SeekBar
+import android.widget.TextView
+import androidx.annotation.ColorInt
+import androidx.annotation.FloatRange
+import androidx.annotation.IntRange
+import androidx.appcompat.widget.AppCompatEditText
+import androidx.appcompat.widget.Toolbar
+import androidx.core.graphics.drawable.DrawableCompat
import com.afollestad.materialdialogs.R
-import java.util.*
+import java.util.Random
/**
* Created by Allan Wang on 2017-06-08.
@@ -38,7 +59,7 @@ inline val Int.isColorDark: Boolean
get() = isColorDark(0.5f)
fun Int.isColorDark(minDarkness: Float): Boolean =
- ((0.299 * Color.red(this) + 0.587 * Color.green(this) + 0.114 * Color.blue(this)) / 255.0) < minDarkness
+ ((0.299 * Color.red(this) + 0.587 * Color.green(this) + 0.114 * Color.blue(this)) / 255.0) < minDarkness
fun Int.toHexString(withAlpha: Boolean = false, withHexPrefix: Boolean = true): String {
val hex = if (withAlpha) String.format("#%08X", this)
@@ -46,7 +67,8 @@ fun Int.toHexString(withAlpha: Boolean = false, withHexPrefix: Boolean = true):
return if (withHexPrefix) hex else hex.substring(1)
}
-fun Int.toRgbaString(): String = "rgba(${Color.red(this)}, ${Color.green(this)}, ${Color.blue(this)}, ${(Color.alpha(this) / 255f).round(3)})"
+fun Int.toRgbaString(): String =
+ "rgba(${Color.red(this)}, ${Color.green(this)}, ${Color.blue(this)}, ${(Color.alpha(this) / 255f).round(3)})"
fun Int.toHSV(): FloatArray {
val hsv = FloatArray(3)
@@ -59,13 +81,15 @@ inline val Int.isColorOpaque: Boolean
fun FloatArray.toColor(): Int = Color.HSVToColor(this)
-fun Int.isColorVisibleOn(@ColorInt color: Int, @IntRange(from = 0L, to = 255L) delta: Int = 25,
- @IntRange(from = 0L, to = 255L) minAlpha: Int = 50): Boolean =
- if (Color.alpha(this) < minAlpha) false
- else !(Math.abs(Color.red(this) - Color.red(color)) < delta
- && Math.abs(Color.green(this) - Color.green(color)) < delta
- && Math.abs(Color.blue(this) - Color.blue(color)) < delta)
-
+fun Int.isColorVisibleOn(
+ @ColorInt color: Int,
+ @IntRange(from = 0L, to = 255L) delta: Int = 25,
+ @IntRange(from = 0L, to = 255L) minAlpha: Int = 50
+): Boolean =
+ if (Color.alpha(this) < minAlpha) false
+ else !(Math.abs(Color.red(this) - Color.red(color)) < delta &&
+ Math.abs(Color.green(this) - Color.green(color)) < delta &&
+ Math.abs(Color.blue(this) - Color.blue(color)) < delta)
@ColorInt
fun Context.getDisabledColor(): Int {
@@ -94,49 +118,58 @@ fun Int.blendWith(@ColorInt color: Int, @FloatRange(from = 0.0, to = 1.0) ratio:
}
@ColorInt
-fun Int.withAlpha(@IntRange(from = 0L, to = 255L) alpha: Int): Int = Color.argb(alpha, Color.red(this), Color.green(this), Color.blue(this))
+fun Int.withAlpha(@IntRange(from = 0, to = 0xFF) alpha: Int): Int =
+ this and 0x00FFFFFF or (alpha shl 24)
@ColorInt
-fun Int.withMinAlpha(@IntRange(from = 0L, to = 255L) alpha: Int): Int = Color.argb(Math.max(alpha, Color.alpha(this)), Color.red(this), Color.green(this), Color.blue(this))
+fun Int.withMinAlpha(@IntRange(from = 0, to = 0xFF) alpha: Int): Int =
+ withAlpha(Math.max(alpha, this ushr 24))
@ColorInt
-fun Int.lighten(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int {
+private inline fun Int.colorFactor(rgbFactor: (Int) -> Float): Int {
val (red, green, blue) = intArrayOf(Color.red(this), Color.green(this), Color.blue(this))
- .map { (it * (1f - factor) + 255f * factor).toInt() }
+ .map { rgbFactor(it).toInt() }
return Color.argb(Color.alpha(this), red, green, blue)
}
@ColorInt
-fun Int.darken(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int {
- val (red, green, blue) = intArrayOf(Color.red(this), Color.green(this), Color.blue(this))
- .map { (it * (1f - factor)).toInt() }
- return Color.argb(Color.alpha(this), red, green, blue)
+fun Int.lighten(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int = colorFactor {
+ (it * (1f - factor) + 255f * factor)
}
@ColorInt
-fun Int.colorToBackground(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int = if (isColorDark) darken(factor) else lighten(factor)
+fun Int.darken(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int = colorFactor {
+ it * (1f - factor)
+}
+
+@ColorInt
+fun Int.colorToBackground(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int =
+ if (isColorDark) darken(factor) else lighten(factor)
@ColorInt
-fun Int.colorToForeground(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int = if (isColorDark) lighten(factor) else darken(factor)
+fun Int.colorToForeground(@FloatRange(from = 0.0, to = 1.0) factor: Float = 0.1f): Int =
+ if (isColorDark) lighten(factor) else darken(factor)
-@Throws(IllegalArgumentException::class)
fun String.toColor(): Int {
- val toParse: String
- if (startsWith("#") && length == 4)
- toParse = "#${this[1]}${this[1]}${this[2]}${this[2]}${this[3]}${this[3]}"
+ val toParse: String = if (startsWith("#") && length == 4)
+ "#${this[1]}${this[1]}${this[2]}${this[2]}${this[3]}${this[3]}"
else
- toParse = this
+ this
return Color.parseColor(toParse)
}
//Get ColorStateList
fun Context.colorStateList(@ColorInt color: Int): ColorStateList {
val disabledColor = color.adjustAlpha(0.3f)
- return ColorStateList(arrayOf(intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
+ return ColorStateList(
+ arrayOf(
+ intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked),
intArrayOf(-android.R.attr.state_enabled, -android.R.attr.state_checked),
- intArrayOf(-android.R.attr.state_enabled, android.R.attr.state_checked)),
- intArrayOf(color.adjustAlpha(0.8f), color, disabledColor, disabledColor))
+ intArrayOf(-android.R.attr.state_enabled, android.R.attr.state_checked)
+ ),
+ intArrayOf(color.adjustAlpha(0.8f), color, disabledColor, disabledColor)
+ )
}
/*
@@ -203,14 +236,14 @@ fun ProgressBar.tint(@ColorInt color: Int, skipIndeterminate: Boolean = false) {
fun Context.textColorStateList(@ColorInt color: Int): ColorStateList {
val states = arrayOf(
- intArrayOf(-android.R.attr.state_enabled),
- intArrayOf(-android.R.attr.state_pressed, -android.R.attr.state_focused),
- intArrayOf()
+ intArrayOf(-android.R.attr.state_enabled),
+ intArrayOf(-android.R.attr.state_pressed, -android.R.attr.state_focused),
+ intArrayOf()
)
val colors = intArrayOf(
- resolveColor(R.attr.colorControlNormal),
- resolveColor(R.attr.colorControlNormal),
- color
+ resolveColor(R.attr.colorControlNormal),
+ resolveColor(R.attr.colorControlNormal),
+ color
)
return ColorStateList(states, colors)
}
@@ -254,4 +287,4 @@ fun Toolbar.tint(@ColorInt color: Int, tintTitle: Boolean = true) {
setSubtitleTextColor(color)
}
(0 until childCount).asSequence().forEach { (getChildAt(it) as? ImageButton)?.setColorFilter(color) }
-} \ No newline at end of file
+}
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 1eeac1a..9dca16c 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt
@@ -1,6 +1,21 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
-import android.support.v4.widget.ViewDragHelper
+import androidx.customview.widget.ViewDragHelper
/**
* Created by Allan Wang on 2017-06-08.
@@ -20,4 +35,4 @@ const val KAU_COLLAPSING = 1
const val KAU_EXPANDING = 2
const val KAU_EXPANDED = 3
-const val KAU_ELLIPSIS = '\u2026' \ No newline at end of file
+const val KAU_ELLIPSIS = '\u2026'
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt
index 6568bf2..82d5608 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2017 Allan Wang
+ *
+ * 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:Suppress("NOTHING_TO_INLINE")
package ca.allanwang.kau.utils
@@ -11,20 +26,35 @@ import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
-import android.support.annotation.*
-import android.support.v4.content.ContextCompat
+import android.os.Looper
import android.util.TypedValue
import android.view.View
import android.view.animation.AnimationUtils
import android.widget.Toast
+import androidx.annotation.AnimRes
+import androidx.annotation.AttrRes
+import androidx.annotation.BoolRes
+import androidx.annotation.ColorInt
+import androidx.annotation.ColorRes
+import androidx.annotation.DimenRes
+import androidx.annotation.DrawableRes
+import androidx.annotation.IntegerRes
+import androidx.annotation.InterpolatorRes
+import androidx.annotation.PluralsRes
+import androidx.annotation.StringRes
+import androidx.core.content.ContextCompat
import ca.allanwang.kau.R
import ca.allanwang.kau.logging.KL
+import com.afollestad.materialdialogs.DialogBehavior
import com.afollestad.materialdialogs.MaterialDialog
-
+import com.afollestad.materialdialogs.ModalDialog
/**
* Created by Allan Wang on 2017-06-03.
*/
+fun Context.runOnUiThread(f: Context.() -> Unit) {
+ if (ContextHelper.looper === Looper.myLooper()) f() else ContextHelper.handler.post { f() }
+}
/**
* Helper class to launch an activity from a context
@@ -33,19 +63,22 @@ import com.afollestad.materialdialogs.MaterialDialog
*/
@Suppress("DEPRECATION")
inline fun <reified T : Activity> Context.startActivity(
- clearStack: Boolean = false,
- bundleBuilder: Bundle.() -> Unit = {},
- intentBuilder: Intent.() -> Unit = {}
+ clearStack: Boolean = false,
+ bundleBuilder: Bundle.() -> Unit = {},
+ intentBuilder: Intent.() -> Unit = {}
) = startActivity(T::class.java, clearStack, bundleBuilder, intentBuilder)
-@Deprecated("Use reified generic instead of passing class",
- ReplaceWith("startActivity<T>(clearStack, bundleBuilder, intentBuilder)"),
- DeprecationLevel.WARNING)
+@Deprecated(
+ "Use reified generic instead of passing class",
+ ReplaceWith("startActivity<T>(clearStack, bundleBuilder, intentBuilder)"),
+ DeprecationLevel.WARNING
+)
inline fun <T : Activity> Context.startActivity(
- clazz: Class<T>,
- clearStack: Boolean = false,
- bundleBuilder: Bundle.() -> Unit = {},
- intentBuilder: Intent.() -> Unit = {}) {
+ clazz: Class<T>,
+ clearStack: Boolean = false,
+ bundleBuilder: Bundle.() -> Unit = {},
+ intentBuilder: Intent.() -> Unit = {}
+) {
val intent = Intent(this, clazz)
if (clearStack) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
intent.intentBuilder()
@@ -55,7 +88,6 @@ inline fun <T : Activity> Context.startActivity(
if (clearStack && this is Activity) finish()
}
-
fun Context.startPlayStoreLink(@StringRes packageIdRes: Int) = startPlayStoreLink(string(packageIdRes))
fun Context.startPlayStoreLink(packageId: String) {
@@ -82,11 +114,14 @@ fun Context.startLink(vararg url: String?) {
fun Context.startLink(@StringRes url: Int) = startLink(string(url))
//Toast helpers
-inline fun View.toast(@StringRes id: Int, duration: Int = Toast.LENGTH_LONG, log: Boolean = false) = context.toast(id, duration, log)
+inline fun View.toast(@StringRes id: Int, duration: Int = Toast.LENGTH_LONG, log: Boolean = false) =
+ context.toast(id, duration, log)
-inline fun Context.toast(@StringRes id: Int, duration: Int = Toast.LENGTH_LONG, log: Boolean = false) = toast(this.string(id), duration, log)
+inline fun Context.toast(@StringRes id: Int, duration: Int = Toast.LENGTH_LONG, log: Boolean = false) =
+ toast(this.string(id), duration, log)
-inline fun View.toast(text: String, duration: Int = Toast.LENGTH_LONG, log: Boolean = false) = context.toast(text, duration, log)
+inline fun View.toast(text: String, duration: Int = Toast.LENGTH_LONG, log: Boolean = false) =
+ context.toast(text, duration, log)
inline fun Context.toast(text: String, duration: Int = Toast.LENGTH_LONG, log: Boolean = false) {
Toast.makeText(this, text, duration).show()
@@ -98,24 +133,33 @@ const val INVALID_ID = 0
//Resource retrievers
inline fun Context.string(@StringRes id: Int): String = getString(id)
-inline fun Context.string(@StringRes id: Int, fallback: String?): String? = if (id != INVALID_ID) string(id) else fallback
-inline fun Context.string(@StringRes id: Int, fallback: () -> String?): String? = if (id != INVALID_ID) string(id) else fallback()
+inline fun Context.string(@StringRes id: Int, fallback: String?): String? =
+ if (id != INVALID_ID) string(id) else fallback
+
+inline fun Context.string(@StringRes id: Int, fallback: () -> String?): String? =
+ if (id != INVALID_ID) string(id) else fallback()
+
inline fun Context.color(@ColorRes id: Int): Int = ContextCompat.getColor(this, id)
inline fun Context.boolean(@BoolRes id: Int): Boolean = resources.getBoolean(id)
inline fun Context.integer(@IntegerRes id: Int): Int = resources.getInteger(id)
inline fun Context.dimen(@DimenRes id: Int): Float = resources.getDimension(id)
inline fun Context.dimenPixelSize(@DimenRes id: Int): Int = resources.getDimensionPixelSize(id)
inline fun Context.drawable(@DrawableRes id: Int): Drawable = ContextCompat.getDrawable(this, id)
- ?: throw KauException("Drawable with id $id not found")
+ ?: throw KauException("Drawable with id $id not found")
+
+inline fun Context.drawable(@DrawableRes id: Int, fallback: Drawable?): Drawable? =
+ if (id != INVALID_ID) drawable(id) else fallback
+
+inline fun Context.drawable(@DrawableRes id: Int, fallback: () -> Drawable?): Drawable? =
+ if (id != INVALID_ID) drawable(id) else fallback()
-inline fun Context.drawable(@DrawableRes id: Int, fallback: Drawable?): Drawable? = if (id != INVALID_ID) drawable(id) else fallback
-inline fun Context.drawable(@DrawableRes id: Int, fallback: () -> Drawable?): Drawable? = if (id != INVALID_ID) drawable(id) else fallback()
inline fun Context.interpolator(@InterpolatorRes id: Int) = AnimationUtils.loadInterpolator(this, id)!!
inline fun Context.animation(@AnimRes id: Int) = AnimationUtils.loadAnimation(this, id)!!
/**
* Returns plural form of res. The quantity is also passed to the formatter as an int
*/
-inline fun Context.plural(@PluralsRes id: Int, quantity: Number) = resources.getQuantityString(id, quantity.toInt(), quantity.toInt())!!
+inline fun Context.plural(@PluralsRes id: Int, quantity: Number) =
+ resources.getQuantityString(id, quantity.toInt(), quantity.toInt())
//Attr retrievers
fun Context.resolveColor(@AttrRes attr: Int, @ColorInt fallback: Int = 0): Int {
@@ -151,20 +195,24 @@ fun Context.resolveString(@AttrRes attr: Int, fallback: String = ""): String {
}
/**
- * Wrapper function for the MaterialDialog adapterBuilder
- * There is no need to call build() or show() as those are done by default
+ * Wrapper function for MaterialDialog
+ *
+ * Mainly handles invalid creations, such as showing a dialog when an activity is finishing
+ * See https://github.com/afollestad/material-dialogs/issues/1778
*/
-inline fun Context.materialDialog(action: MaterialDialog.Builder.() -> Unit): MaterialDialog {
- val builder = MaterialDialog.Builder(this)
- builder.action()
+inline fun Context.materialDialog(
+ dialogBehavior: DialogBehavior = ModalDialog,
+ action: MaterialDialog.() -> Unit
+) {
+ val dialog = MaterialDialog(this, dialogBehavior)
if (isFinishing) {
- KL.d { "Material Dialog triggered from finishing context; did not show" }
- return builder.build()
+ return KL.d { "Material Dialog triggered from finishing context; did not show" }
}
- return builder.show()
+ dialog.show(action)
}
-fun Context.getDip(value: Float): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, resources.displayMetrics)
+fun Context.getDip(value: Float): Float =
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, resources.displayMetrics)
inline val Context.isRtl: Boolean
get() = resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
@@ -181,7 +229,10 @@ inline val Context.isNavBarOnBottom: Boolean
return !canMove || dm.widthPixels < dm.heightPixels
}
-fun Context.hasPermission(permissions: String) = !buildIsMarshmallowAndUp || ContextCompat.checkSelfPermission(this, permissions) == PackageManager.PERMISSION_GRANTED
+fun Context.hasPermission(permissions: String) = !buildIsMarshmallowAndUp || ContextCompat.checkSelfPermission(
+ this,
+ permissions
+) == PackageManager.PERMISSION_GRANTED
fun Context.copyToClipboard(text: String?, label: String = "Copied Text", showToast: Boolean = true) {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@@ -207,4 +258,4 @@ fun Context.shareText(text: String?) {
* As of now, it is only checked when tied to an activity
*/
inline val Context.isFinishing: Boolean
- get() = (this as? Activity)?.isFinishing ?: false \ No newline at end of file
+ get() = (this as? Activity)?.isFinishing ?: false
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt
new file mode 100644
index 0000000..57a9921
--- /dev/null
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.android.asCoroutineDispatcher
+import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+
+object ContextHelper : CoroutineScope {
+
+ val looper = Looper.getMainLooper()
+
+ val handler = Handler(looper)
+
+ /**
+ * Creating dispatcher from main handler to avoid IO
+ * See https://github.com/Kotlin/kotlinx.coroutines/issues/878
+ */
+ val dispatcher = handler.asCoroutineDispatcher("kau-main")
+
+ override val coroutineContext: CoroutineContext get() = dispatcher
+}
+
+/**
+ * Most context items implement [CoroutineScope] by default.
+ * We will add a fallback just in case.
+ * It is expected that the scope returned always has the Android main dispatcher as part of the context.
+ */
+internal inline val Context.ctxCoroutine: CoroutineScope
+ get() = this as? CoroutineScope ?: ContextHelper
+
+/**
+ * Calls [launch] with an explicit dispatcher for Android's main thread
+ */
+fun CoroutineScope.launchMain(
+ context: CoroutineContext = EmptyCoroutineContext,
+ start: CoroutineStart = CoroutineStart.DEFAULT,
+ block: suspend CoroutineScope.() -> Unit
+) = launch(ContextHelper.dispatcher + context, start, block)
+
+/**
+ * Calls [async] with an explicit dispatcher for Android's main thread
+ */
+fun CoroutineScope.asyncMain(
+ context: CoroutineContext = EmptyCoroutineContext,
+ start: CoroutineStart = CoroutineStart.DEFAULT,
+ block: suspend CoroutineScope.() -> Unit
+) = async(ContextHelper.dispatcher + context, start, block)
+
+/**
+ * Calls [withContext] with an explicit dispatcher for Android's main thread
+ */
+suspend fun <T> withMainContext(block: suspend CoroutineScope.() -> T) =
+ withContext(ContextHelper.dispatcher, block)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/DrawableUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/DrawableUtils.kt
index dae3bff..6950f2f 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/DrawableUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/DrawableUtils.kt
@@ -1,9 +1,24 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.content.res.ColorStateList
import android.graphics.drawable.Drawable
-import android.support.annotation.ColorInt
-import android.support.v4.graphics.drawable.DrawableCompat
+import androidx.annotation.ColorInt
+import androidx.core.graphics.drawable.DrawableCompat
/**
* Wrap the color into a state and tint the drawable
@@ -17,4 +32,4 @@ fun Drawable.tint(state: ColorStateList): Drawable {
val drawable = DrawableCompat.wrap(mutate())
DrawableCompat.setTintList(drawable, state)
return drawable
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt
index bfbc009..1d27bfc 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/FileUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import java.io.File
@@ -6,4 +21,5 @@ import java.io.InputStream
/**
* Created by Allan Wang on 2017-08-04.
*/
-fun File.copyFromInputStream(inputStream: InputStream) = inputStream.use { input -> outputStream().use { output -> input.copyTo(output) } } \ No newline at end of file
+fun File.copyFromInputStream(inputStream: InputStream) =
+ inputStream.use { input -> outputStream().use { output -> input.copyTo(output) } }
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/FontUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/FontUtils.kt
index 1db7694..064d70b 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/FontUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/FontUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.content.Context
@@ -14,17 +29,17 @@ object FontUtils {
synchronized(sTypefaceCache) {
if (!sTypefaceCache.containsKey(font)) {
val tf = Typeface.createFromAsset(
- context.applicationContext.assets, "fonts/$font.ttf")
+ context.applicationContext.assets, "fonts/$font.ttf"
+ )
sTypefaceCache.put(font, tf)
}
return sTypefaceCache.get(font)
- ?: throw IllegalArgumentException("Font error; typeface does not exist at assets/fonts$font.ttf")
+ ?: throw IllegalArgumentException("Font error; typeface does not exist at assets/fonts$font.ttf")
}
}
fun getName(typeface: Typeface): String? = sTypefaceCache.entries.firstOrNull { it.value == typeface }?.key
-
}
fun Context.getFont(font: String) = FontUtils.get(this, font)
-fun Context.getFontName(typeface: Typeface) = FontUtils.getName(typeface) \ No newline at end of file
+fun Context.getFontName(typeface: Typeface) = FontUtils.getName(typeface)
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/FragmentUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/FragmentUtils.kt
index acc71f2..75dc1c1 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/FragmentUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/FragmentUtils.kt
@@ -1,12 +1,26 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
-import android.support.v4.app.Fragment
-import org.jetbrains.anko.bundleOf
+import androidx.fragment.app.Fragment
/**
* Created by Allan Wang on 2017-07-02.
*/
-fun <T : Fragment> T.withArguments(vararg params: Pair<String, Any>): T {
+fun <T : Fragment> T.withArguments(vararg params: Pair<String, Any?>): T {
arguments = bundleOf(*params)
return this
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/IIconUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/IIconUtils.kt
index 51691af..8b40352 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/IIconUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/IIconUtils.kt
@@ -1,10 +1,25 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.Drawable
-import android.support.annotation.ColorInt
+import androidx.annotation.ColorInt
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.IIcon
@@ -12,10 +27,15 @@ import com.mikepenz.iconics.typeface.IIcon
* Created by Allan Wang on 2017-05-29.
*/
@KauUtils
-fun IIcon.toDrawable(c: Context, sizeDp: Int = 24, @ColorInt color: Int = Color.WHITE, builder: IconicsDrawable.() -> Unit = {}): Drawable {
+fun IIcon.toDrawable(
+ c: Context,
+ sizeDp: Int = 24,
+ @ColorInt color: Int = Color.WHITE,
+ builder: IconicsDrawable.() -> Unit = {}
+): Drawable {
val state = ColorStateList.valueOf(color)
val icon = IconicsDrawable(c).icon(this).color(state)
if (sizeDp > 0) icon.sizeDp(sizeDp)
icon.builder()
return icon
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt
index 8c7c039..8765c69 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Kotterknife.kt
@@ -1,4 +1,19 @@
-@file:Suppress("UNCHECKED_CAST")
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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:Suppress("UNCHECKED_CAST", "DEPRECATION")
package ca.allanwang.kau.utils
@@ -8,148 +23,89 @@ package ca.allanwang.kau.utils
* Courtesy of Jake Wharton
*
* https://github.com/JakeWharton/kotterknife/blob/master/src/main/kotlin/kotterknife/ButterKnife.kt
+ *
+ * Note that while this is useful for binding ids, there also exists other alternatives, such as
+ * `kotlin-android-extensions`.
+ *
+ * For fragments, make sure that the views are reset after the fragment lifecycle.
*/
import android.app.Activity
import android.app.Dialog
import android.app.DialogFragment
import android.app.Fragment
-import android.support.v7.widget.RecyclerView.ViewHolder
import android.view.View
-import java.util.*
+import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
+import java.util.Collections
+import java.util.WeakHashMap
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
-import android.support.v4.app.DialogFragment as SupportDialogFragment
-import android.support.v4.app.Fragment as SupportFragment
-
-private const val DEPRECATION_MESSAGE = "Kotterknife will be removed in favour of the kotlin_android_extensions plugin"
+import androidx.fragment.app.DialogFragment as SupportDialogFragment
+import androidx.fragment.app.Fragment as SupportFragment
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindView(id: Int)
- : ReadOnlyProperty<View, V> = required(id, viewFinder)
+fun <V : View> View.bindView(id: Int): ReadOnlyProperty<View, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindView(id: Int)
- : ReadOnlyProperty<Activity, V> = required(id, viewFinder)
+fun <V : View> Activity.bindView(id: Int): ReadOnlyProperty<Activity, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindView(id: Int)
- : ReadOnlyProperty<Dialog, V> = required(id, viewFinder)
+fun <V : View> Dialog.bindView(id: Int): ReadOnlyProperty<Dialog, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindView(id: Int)
- : ReadOnlyProperty<DialogFragment, V> = required(id, viewFinder)
+fun <V : View> DialogFragment.bindView(id: Int): ReadOnlyProperty<DialogFragment, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindView(id: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, V> = required(id, viewFinder)
+fun <V : View> SupportDialogFragment.bindView(id: Int): ReadOnlyProperty<SupportDialogFragment, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindView(id: Int)
- : ReadOnlyProperty<Fragment, V> = required(id, viewFinder)
+fun <V : View> Fragment.bindView(id: Int): ReadOnlyProperty<Fragment, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindView(id: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, V> = required(id, viewFinder)
+fun <V : View> SupportFragment.bindView(id: Int): ReadOnlyProperty<SupportFragment, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindView(id: Int)
- : ReadOnlyProperty<ViewHolder, V> = required(id, viewFinder)
+fun <V : View> RecyclerView.ViewHolder.bindView(id: Int): ReadOnlyProperty<RecyclerView.ViewHolder, V> = required(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindOptionalView(id: Int)
- : ReadOnlyProperty<View, V?> = optional(id, viewFinder)
+fun <V : View> View.bindOptionalView(id: Int): ReadOnlyProperty<View, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindOptionalView(id: Int)
- : ReadOnlyProperty<Activity, V?> = optional(id, viewFinder)
+fun <V : View> Activity.bindOptionalView(id: Int): ReadOnlyProperty<Activity, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindOptionalView(id: Int)
- : ReadOnlyProperty<Dialog, V?> = optional(id, viewFinder)
+fun <V : View> Dialog.bindOptionalView(id: Int): ReadOnlyProperty<Dialog, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindOptionalView(id: Int)
- : ReadOnlyProperty<DialogFragment, V?> = optional(id, viewFinder)
+fun <V : View> DialogFragment.bindOptionalView(id: Int): ReadOnlyProperty<DialogFragment, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindOptionalView(id: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, V?> = optional(id, viewFinder)
+fun <V : View> SupportDialogFragment.bindOptionalView(id: Int): ReadOnlyProperty<SupportDialogFragment, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindOptionalView(id: Int)
- : ReadOnlyProperty<Fragment, V?> = optional(id, viewFinder)
+fun <V : View> Fragment.bindOptionalView(id: Int): ReadOnlyProperty<Fragment, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindOptionalView(id: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, V?> = optional(id, viewFinder)
+fun <V : View> SupportFragment.bindOptionalView(id: Int): ReadOnlyProperty<SupportFragment, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindOptionalView(id: Int)
- : ReadOnlyProperty<ViewHolder, V?> = optional(id, viewFinder)
+fun <V : View> RecyclerView.ViewHolder.bindOptionalView(id: Int): ReadOnlyProperty<RecyclerView.ViewHolder, V?> = optional(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindViews(vararg ids: Int)
- : ReadOnlyProperty<View, List<V>> = required(ids, viewFinder)
+fun <V : View> View.bindViews(vararg ids: Int): ReadOnlyProperty<View, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindViews(vararg ids: Int)
- : ReadOnlyProperty<Activity, List<V>> = required(ids, viewFinder)
+fun <V : View> Activity.bindViews(vararg ids: Int): ReadOnlyProperty<Activity, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindViews(vararg ids: Int)
- : ReadOnlyProperty<Dialog, List<V>> = required(ids, viewFinder)
+fun <V : View> Dialog.bindViews(vararg ids: Int): ReadOnlyProperty<Dialog, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindViews(vararg ids: Int)
- : ReadOnlyProperty<DialogFragment, List<V>> = required(ids, viewFinder)
+fun <V : View> DialogFragment.bindViews(vararg ids: Int): ReadOnlyProperty<DialogFragment, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindViews(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, List<V>> = required(ids, viewFinder)
+fun <V : View> SupportDialogFragment.bindViews(vararg ids: Int): ReadOnlyProperty<SupportDialogFragment, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindViews(vararg ids: Int)
- : ReadOnlyProperty<Fragment, List<V>> = required(ids, viewFinder)
+fun <V : View> Fragment.bindViews(vararg ids: Int): ReadOnlyProperty<Fragment, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindViews(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, List<V>> = required(ids, viewFinder)
+fun <V : View> SupportFragment.bindViews(vararg ids: Int): ReadOnlyProperty<SupportFragment, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindViews(vararg ids: Int)
- : ReadOnlyProperty<ViewHolder, List<V>> = required(ids, viewFinder)
+fun <V : View> ViewHolder.bindViews(vararg ids: Int): ReadOnlyProperty<ViewHolder, List<V>> = required(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<View, List<V>> = optional(ids, viewFinder)
+fun <V : View> View.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<View, List<V>> = optional(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<Activity, List<V>> = optional(ids, viewFinder)
+fun <V : View> Activity.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<Activity, List<V>> = optional(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<Dialog, List<V>> = optional(ids, viewFinder)
+fun <V : View> Dialog.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<Dialog, List<V>> = optional(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<DialogFragment, List<V>> = optional(ids, viewFinder)
+fun <V : View> DialogFragment.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<DialogFragment, List<V>> = optional(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, List<V>> = optional(ids, viewFinder)
+fun <V : View> SupportDialogFragment.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<SupportDialogFragment, List<V>> = optional(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<Fragment, List<V>> = optional(ids, viewFinder)
+fun <V : View> Fragment.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<Fragment, List<V>> = optional(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, List<V>> = optional(ids, viewFinder)
+fun <V : View> SupportFragment.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<SupportFragment, List<V>> = optional(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindOptionalViews(vararg ids: Int)
- : ReadOnlyProperty<ViewHolder, List<V>> = optional(ids, viewFinder)
+fun <V : View> ViewHolder.bindOptionalViews(vararg ids: Int): ReadOnlyProperty<ViewHolder, List<V>> = optional(ids, viewFinder)
private inline val View.viewFinder: View.(Int) -> View?
get() = { findViewById(it) }
@@ -162,14 +118,14 @@ private inline val DialogFragment.viewFinder: DialogFragment.(Int) -> View?
private inline val SupportDialogFragment.viewFinder: SupportDialogFragment.(Int) -> View?
get() = { dialog.findViewById(it) }
private inline val Fragment.viewFinder: Fragment.(Int) -> View?
- get() = { view.findViewById(it) }
+ get() = { view!!.findViewById(it) }
private inline val SupportFragment.viewFinder: SupportFragment.(Int) -> View?
get() = { view!!.findViewById(it) }
private inline val ViewHolder.viewFinder: ViewHolder.(Int) -> View?
get() = { itemView.findViewById(it) }
private fun viewNotFound(id: Int, desc: KProperty<*>): Nothing =
- throw IllegalStateException("View ID $id for '${desc.name}' not found.")
+ throw IllegalStateException("View ID $id for '${desc.name}' not found.")
private fun <T, V : View> required(id: Int, finder: T.(Int) -> View?) = Lazy { t: T, desc ->
(t.finder(id) as V?)?.apply { } ?: viewNotFound(id, desc)
@@ -183,7 +139,8 @@ private fun <T, V : View> required(ids: IntArray, finder: T.(Int) -> View?) = La
}
}
-private fun <T, V : View> optional(ids: IntArray, finder: T.(Int) -> View?) = Lazy { t: T, _ -> ids.map { t.finder(it) as V? }.filterNotNull() }
+private fun <T, V : View> optional(ids: IntArray, finder: T.(Int) -> View?) =
+ Lazy { t: T, _ -> ids.map { t.finder(it) as V? }.filterNotNull() }
// Like Kotlin's lazy delegate but the initializer gets the target and metadata passed to it
private open class Lazy<in T, out V>(private val initializer: (T, KProperty<*>) -> V) : ReadOnlyProperty<T, V> {
@@ -209,139 +166,76 @@ private open class Lazy<in T, out V>(private val initializer: (T, KProperty<*>)
* Credits to <a href="https://github.com/MichaelRocks">MichaelRocks</a>
*/
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindViewResettable(id: Int)
- : ReadOnlyProperty<View, V> = requiredResettable(id, viewFinder)
+fun <V : View> View.bindViewResettable(id: Int): ReadOnlyProperty<View, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindViewResettable(id: Int)
- : ReadOnlyProperty<Activity, V> = requiredResettable(id, viewFinder)
+fun <V : View> Activity.bindViewResettable(id: Int): ReadOnlyProperty<Activity, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindViewResettable(id: Int)
- : ReadOnlyProperty<Dialog, V> = requiredResettable(id, viewFinder)
+fun <V : View> Dialog.bindViewResettable(id: Int): ReadOnlyProperty<Dialog, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindViewResettable(id: Int)
- : ReadOnlyProperty<DialogFragment, V> = requiredResettable(id, viewFinder)
+fun <V : View> DialogFragment.bindViewResettable(id: Int): ReadOnlyProperty<DialogFragment, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindViewResettable(id: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, V> = requiredResettable(id, viewFinder)
+fun <V : View> SupportDialogFragment.bindViewResettable(id: Int): ReadOnlyProperty<SupportDialogFragment, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindViewResettable(id: Int)
- : ReadOnlyProperty<Fragment, V> = requiredResettable(id, viewFinder)
+fun <V : View> Fragment.bindViewResettable(id: Int): ReadOnlyProperty<Fragment, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindViewResettable(id: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, V> = requiredResettable(id, viewFinder)
+fun <V : View> SupportFragment.bindViewResettable(id: Int): ReadOnlyProperty<SupportFragment, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindViewResettable(id: Int)
- : ReadOnlyProperty<ViewHolder, V> = requiredResettable(id, viewFinder)
+fun <V : View> ViewHolder.bindViewResettable(id: Int): ReadOnlyProperty<ViewHolder, V> = requiredResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<View, V?> = optionalResettable(id, viewFinder)
+fun <V : View> View.bindOptionalViewResettable(id: Int): ReadOnlyProperty<View, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<Activity, V?> = optionalResettable(id, viewFinder)
+fun <V : View> Activity.bindOptionalViewResettable(id: Int): ReadOnlyProperty<Activity, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<Dialog, V?> = optionalResettable(id, viewFinder)
+fun <V : View> Dialog.bindOptionalViewResettable(id: Int): ReadOnlyProperty<Dialog, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<DialogFragment, V?> = optionalResettable(id, viewFinder)
+fun <V : View> DialogFragment.bindOptionalViewResettable(id: Int): ReadOnlyProperty<DialogFragment, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, V?> = optionalResettable(id, viewFinder)
+fun <V : View> SupportDialogFragment.bindOptionalViewResettable(id: Int): ReadOnlyProperty<SupportDialogFragment, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<Fragment, V?> = optionalResettable(id, viewFinder)
+fun <V : View> Fragment.bindOptionalViewResettable(id: Int): ReadOnlyProperty<Fragment, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, V?> = optionalResettable(id, viewFinder)
+fun <V : View> SupportFragment.bindOptionalViewResettable(id: Int): ReadOnlyProperty<SupportFragment, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindOptionalViewResettable(id: Int)
- : ReadOnlyProperty<ViewHolder, V?> = optionalResettable(id, viewFinder)
+fun <V : View> ViewHolder.bindOptionalViewResettable(id: Int): ReadOnlyProperty<ViewHolder, V?> = optionalResettable(id, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<View, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> View.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<View, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<Activity, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> Activity.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<Activity, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<Dialog, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> Dialog.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<Dialog, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<DialogFragment, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> DialogFragment.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<DialogFragment, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> SupportDialogFragment.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<SupportDialogFragment, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<Fragment, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> Fragment.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<Fragment, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> SupportFragment.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<SupportFragment, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<ViewHolder, List<V>> = requiredResettable(ids, viewFinder)
+fun <V : View> ViewHolder.bindViewsResettable(vararg ids: Int): ReadOnlyProperty<ViewHolder, List<V>> = requiredResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> View.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<View, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> View.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<View, List<V>> = optionalResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Activity.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<Activity, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> Activity.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<Activity, List<V>> = optionalResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Dialog.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<Dialog, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> Dialog.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<Dialog, List<V>> = optionalResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> DialogFragment.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<DialogFragment, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> DialogFragment.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<DialogFragment, List<V>> = optionalResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportDialogFragment.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.DialogFragment, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> SupportDialogFragment.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<SupportDialogFragment, List<V>> = optionalResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> Fragment.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<Fragment, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> Fragment.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<Fragment, List<V>> = optionalResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> SupportFragment.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<android.support.v4.app.Fragment, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> SupportFragment.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<SupportFragment, List<V>> = optionalResettable(ids, viewFinder)
-@Deprecated(DEPRECATION_MESSAGE)
-fun <V : View> ViewHolder.bindOptionalViewsResettable(vararg ids: Int)
- : ReadOnlyProperty<ViewHolder, List<V>> = optionalResettable(ids, viewFinder)
+fun <V : View> ViewHolder.bindOptionalViewsResettable(vararg ids: Int): ReadOnlyProperty<RecyclerView.ViewHolder, List<V>> = optionalResettable(ids, viewFinder)
private fun <T, V : View> requiredResettable(id: Int, finder: T.(Int) -> View?) = LazyResettable { t: T, desc ->
(t.finder(id) as V?)?.apply { } ?: viewNotFound(id, desc)
}
-private fun <T, V : View> optionalResettable(id: Int, finder: T.(Int) -> View?) = LazyResettable { t: T, _ -> t.finder(id) as V? }
+private fun <T, V : View> optionalResettable(id: Int, finder: T.(Int) -> View?) =
+ LazyResettable { t: T, _ -> t.finder(id) as V? }
private fun <T, V : View> requiredResettable(ids: IntArray, finder: T.(Int) -> View?) = LazyResettable { t: T, desc ->
ids.map {
@@ -349,7 +243,8 @@ private fun <T, V : View> requiredResettable(ids: IntArray, finder: T.(Int) -> V
}
}
-private fun <T, V : View> optionalResettable(ids: IntArray, finder: T.(Int) -> View?) = LazyResettable { t: T, _ -> ids.map { t.finder(it) as V? }.filterNotNull() }
+private fun <T, V : View> optionalResettable(ids: IntArray, finder: T.(Int) -> View?) =
+ LazyResettable { t: T, _ -> ids.map { t.finder(it) as V? }.filterNotNull() }
//Like Kotterknife's lazy delegate but is resettable
private class LazyResettable<in T, out V>(initializer: (T, KProperty<*>) -> V) : Lazy<T, V>(initializer) {
@@ -363,7 +258,6 @@ private class LazyResettable<in T, out V>(initializer: (T, KProperty<*>) -> V) :
}
}
-@Deprecated(DEPRECATION_MESSAGE)
object Kotterknife {
fun reset(target: Any) {
KotterknifeRegistry.reset(target)
@@ -373,7 +267,8 @@ object Kotterknife {
private object KotterknifeRegistry {
private val lazyMap = WeakHashMap<Any, MutableCollection<LazyResettable<*, *>>>()
- fun register(target: Any, lazy: LazyResettable<*, *>) = lazyMap.getOrPut(target, { Collections.newSetFromMap(WeakHashMap()) }).add(lazy)
+ fun register(target: Any, lazy: LazyResettable<*, *>) =
+ lazyMap.getOrPut(target, { Collections.newSetFromMap(WeakHashMap()) }).add(lazy)
fun reset(target: Any) = lazyMap[target]?.forEach(LazyResettable<*, *>::reset)
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/NetworkUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/NetworkUtils.kt
index 2271c16..32cf084 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/NetworkUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/NetworkUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.annotation.SuppressLint
@@ -7,6 +22,7 @@ import android.net.ConnectivityManager
/**
* Created by Allan Wang on 2017-07-07.
*/
+@Deprecated("Applications should make use of network callbacks instead of individual queries")
inline val Context.isNetworkAvailable: Boolean
@SuppressLint("MissingPermission")
get() {
@@ -15,6 +31,7 @@ inline val Context.isNetworkAvailable: Boolean
return activeNetworkInfo?.isConnectedOrConnecting ?: false
}
+@Deprecated("Applications should make use of network callbacks instead of individual queries")
inline val Context.isWifiConnected: Boolean
@SuppressLint("MissingPermission")
get() {
@@ -23,10 +40,11 @@ inline val Context.isWifiConnected: Boolean
return (activeNetworkInfo?.type ?: -1) == ConnectivityManager.TYPE_WIFI
}
+@Deprecated("Applications should make use of network callbacks instead of individual queries")
inline val Context.isMobileDataConnected: Boolean
@SuppressLint("MissingPermission")
get() {
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetworkInfo = connectivityManager.activeNetworkInfo
return (activeNetworkInfo?.type ?: -1) == ConnectivityManager.TYPE_MOBILE
- } \ 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
index 1eb0076..126b133 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/NotificationUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/NotificationUtils.kt
@@ -1,10 +1,24 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.content.Context
-import android.support.v4.app.NotificationManagerCompat
-
+import androidx.core.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
+fun Context.cancelNotification(notifId: Int) = NotificationManagerCompat.from(this).cancel(notifId)
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 77750d3..4055847 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.content.ActivityNotFoundException
@@ -70,4 +85,4 @@ inline val Context.isFromGooglePlay: Boolean
get() {
val installer = installerPackageName
return arrayOf(INSTALLER_GOOGLE_PLAY_FEEDBACK, INSTALLER_GOOGLE_PLAY_VENDING).any { it == installer }
- } \ No newline at end of file
+ }
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt
index 3a34db5..11494b3 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/RecyclerUtils.kt
@@ -1,8 +1,23 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.graphics.Rect
-import android.support.v7.widget.RecyclerView
import android.view.View
+import androidx.recyclerview.widget.RecyclerView
/**
* Created by Allan Wang on 2017-07-11.
@@ -22,4 +37,4 @@ class MarginItemDecoration(sizeDp: Int, val edgeFlags: Int) : RecyclerView.ItemD
if (edgeFlags and KAU_RIGHT > 0) outRect.right += sizePx
if (edgeFlags and KAU_BOTTOM > 0) outRect.bottom += sizePx
}
-} \ No newline at end of file
+}
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 ec206ee..523a586 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt
@@ -1,14 +1,29 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.os.Build
-import android.support.annotation.RequiresApi
-import android.support.annotation.TransitionRes
-import android.support.transition.AutoTransition
-import android.support.transition.TransitionInflater
-import android.support.transition.TransitionManager
import android.transition.Transition
import android.view.ViewGroup
-import android.support.transition.Transition as SupportTransition
+import androidx.annotation.RequiresApi
+import androidx.annotation.TransitionRes
+import androidx.transition.AutoTransition
+import androidx.transition.TransitionInflater
+import androidx.transition.TransitionManager
+import androidx.transition.Transition as SupportTransition
/**
* Created by Allan Wang on 2017-06-24.
@@ -29,7 +44,8 @@ fun Transition.addEndListener(onEnd: (transition: Transition) -> Unit) {
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
-class SupportTransitionEndListener(val onEnd: (transition: SupportTransition) -> Unit) : SupportTransition.TransitionListener {
+class SupportTransitionEndListener(val onEnd: (transition: SupportTransition) -> Unit) :
+ SupportTransition.TransitionListener {
override fun onTransitionEnd(transition: SupportTransition) = onEnd(transition)
override fun onTransitionResume(transition: SupportTransition) {}
override fun onTransitionPause(transition: SupportTransition) {}
@@ -52,9 +68,9 @@ fun ViewGroup.transitionAuto(builder: AutoTransition.() -> Unit = {}) {
}
@KauUtils
-fun ViewGroup.transitionDelayed(@TransitionRes id: Int, builder: android.support.transition.Transition.() -> Unit = {}) {
+fun ViewGroup.transitionDelayed(@TransitionRes id: Int, builder: androidx.transition.Transition.() -> Unit = {}) {
if (!buildIsLollipopAndUp) return
val transition = TransitionInflater.from(context).inflateTransition(id)
transition.builder()
TransitionManager.beginDelayedTransition(this, transition)
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt
index 46e29b2..48a2028 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Utils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.content.Context
@@ -8,12 +23,11 @@ import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Handler
import android.os.Looper
-import android.support.annotation.IntRange
+import androidx.annotation.IntRange
import ca.allanwang.kau.R
import java.math.RoundingMode
import java.text.DecimalFormat
-
/**
* Created by Allan Wang on 2017-05-28.
*/
@@ -127,10 +141,10 @@ fun postDelayed(delay: Long, action: () -> Unit) {
}
inline val kauIsMainThread: Boolean
- get() = Looper.myLooper() == Looper.getMainLooper()
+ get() = Looper.myLooper() == ContextHelper.looper
class KauException(message: String) : RuntimeException(message)
fun String.withMaxLength(n: Int): String =
- if (length <= n) this
- else substring(0, n - 1) + KAU_ELLIPSIS \ No newline at end of file
+ if (length <= n) this
+ else substring(0, n - 1) + KAU_ELLIPSIS
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt
index 4e020bc..186d125 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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:Suppress("NOTHING_TO_INLINE")
package ca.allanwang.kau.utils
@@ -7,15 +22,6 @@ import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.os.Build
-import android.support.annotation.ColorInt
-import android.support.annotation.ColorRes
-import android.support.annotation.RequiresApi
-import android.support.annotation.StringRes
-import android.support.design.widget.FloatingActionButton
-import android.support.design.widget.Snackbar
-import android.support.design.widget.TextInputEditText
-import android.support.v7.widget.LinearLayoutManager
-import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -23,11 +29,19 @@ import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ImageView
+import androidx.annotation.ColorInt
+import androidx.annotation.ColorRes
+import androidx.annotation.RequiresApi
+import androidx.annotation.StringRes
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
import ca.allanwang.kau.ui.createSimpleRippleDrawable
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.google.android.material.snackbar.Snackbar
+import com.google.android.material.textfield.TextInputEditText
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.IIcon
-
/**
* Created by Allan Wang on 2017-05-31.
*/
@@ -81,10 +95,16 @@ fun View.snackbar(text: String, duration: Int = Snackbar.LENGTH_LONG, builder: S
return snackbar
}
-fun View.snackbar(@StringRes textId: Int, duration: Int = Snackbar.LENGTH_LONG, builder: Snackbar.() -> Unit = {}) = snackbar(context.string(textId), duration, builder)
+fun View.snackbar(@StringRes textId: Int, duration: Int = Snackbar.LENGTH_LONG, builder: Snackbar.() -> Unit = {}) =
+ snackbar(context.string(textId), duration, builder)
@KauUtils
-fun ImageView.setIcon(icon: IIcon?, sizeDp: Int = 24, @ColorInt color: Int = Color.WHITE, builder: IconicsDrawable.() -> Unit = {}) {
+fun ImageView.setIcon(
+ icon: IIcon?,
+ sizeDp: Int = 24,
+ @ColorInt color: Int = Color.WHITE,
+ builder: IconicsDrawable.() -> Unit = {}
+) {
if (icon == null) return
setImageDrawable(icon.toDrawable(context, sizeDp = sizeDp, color = color, builder = builder))
}
@@ -98,7 +118,8 @@ fun FloatingActionButton.showIf(show: Boolean) = if (show) show() else hide()
fun FloatingActionButton.hideIf(hide: Boolean) = if (hide) hide() else show()
@KauUtils
-fun ViewGroup.inflate(layoutId: Int, attachToRoot: Boolean = false): View = LayoutInflater.from(context).inflate(layoutId, this, attachToRoot)
+fun ViewGroup.inflate(layoutId: Int, attachToRoot: Boolean = false): View =
+ LayoutInflater.from(context).inflate(layoutId, this, attachToRoot)
/**
* Set left margin to a value in px
@@ -150,10 +171,10 @@ fun View.setMargin(margin: Int) = setMargins(margin, KAU_ALL)
private fun View.setMargins(margin: Int, flag: Int): Boolean {
val p = (layoutParams as? ViewGroup.MarginLayoutParams) ?: return false
p.setMargins(
- if (flag and KAU_LEFT > 0) margin else p.leftMargin,
- if (flag and KAU_TOP > 0) margin else p.topMargin,
- if (flag and KAU_RIGHT > 0) margin else p.rightMargin,
- if (flag and KAU_BOTTOM > 0) margin else p.bottomMargin
+ if (flag and KAU_LEFT > 0) margin else p.leftMargin,
+ if (flag and KAU_TOP > 0) margin else p.topMargin,
+ if (flag and KAU_RIGHT > 0) margin else p.rightMargin,
+ if (flag and KAU_BOTTOM > 0) margin else p.bottomMargin
)
return true
}
@@ -206,26 +227,31 @@ fun View.setPadding(padding: Int) = setPadding(padding, KAU_ALL)
@KauUtils
private fun View.setPadding(padding: Int, flag: Int) {
setPadding(
- if (flag and KAU_LEFT > 0) padding else paddingLeft,
- if (flag and KAU_TOP > 0) padding else paddingTop,
- if (flag and KAU_RIGHT > 0) padding else paddingRight,
- if (flag and KAU_BOTTOM > 0) padding else paddingBottom
+ if (flag and KAU_LEFT > 0) padding else paddingLeft,
+ if (flag and KAU_TOP > 0) padding else paddingTop,
+ if (flag and KAU_RIGHT > 0) padding else paddingRight,
+ if (flag and KAU_BOTTOM > 0) padding else paddingBottom
)
}
@KauUtils
fun View.hideKeyboard() {
clearFocus()
- (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(windowToken, 0)
+ (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(
+ windowToken,
+ 0
+ )
}
@KauUtils
fun View.showKeyboard() {
requestFocus()
- (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
+ (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(
+ this,
+ InputMethodManager.SHOW_IMPLICIT
+ )
}
-
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
@KauUtils
fun View.setRippleBackground(@ColorInt foregroundColor: Int, @ColorInt backgroundColor: Int) {
@@ -243,12 +269,14 @@ inline val TextInputEditText.value: String get() = text.toString().trim()
/**
* Generates a recycler view with match parent and a linearlayoutmanager, since it's so commonly used
*/
-fun Context.fullLinearRecycler(rvAdapter: RecyclerView.Adapter<*>? = null, configs: RecyclerView.() -> Unit = {}) = RecyclerView(this).apply {
- layoutManager = LinearLayoutManager(this@fullLinearRecycler)
- layoutParams = RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT)
- if (rvAdapter != null) adapter = rvAdapter
- configs()
-}
+fun Context.fullLinearRecycler(rvAdapter: RecyclerView.Adapter<*>? = null, configs: RecyclerView.() -> Unit = {}) =
+ RecyclerView(this).apply {
+ layoutManager = LinearLayoutManager(this@fullLinearRecycler)
+ layoutParams =
+ RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT)
+ if (rvAdapter != null) adapter = rvAdapter
+ configs()
+ }
/**
* Sets a linear layout manager along with an adapter
@@ -263,7 +291,11 @@ fun RecyclerView.withLinearAdapter(rvAdapter: RecyclerView.Adapter<*>) = apply {
* If it is not shown, the action will be invoked directly and no further actions will be made
* If it is already shown, scaling and alpha animations will be added to the action
*/
-inline fun <T : ImageView> T.fadeScaleTransition(duration: Long = 500L, minScale: Float = 0.7f, crossinline action: T.() -> Unit) {
+inline fun <T : ImageView> T.fadeScaleTransition(
+ duration: Long = 500L,
+ minScale: Float = 0.7f,
+ crossinline action: T.() -> Unit
+) {
if (!isVisible) action()
else {
var transitioned = false
@@ -291,7 +323,7 @@ fun FloatingActionButton.hideOnDownwardsScroll(recycler: RecyclerView) {
recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
- if (newState == android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE && !isShown) show()
+ if (newState == RecyclerView.SCROLL_STATE_IDLE && !isShown) show()
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
@@ -324,4 +356,4 @@ inline fun View.setOnSingleTapListener(crossinline onSingleTap: (v: View, event:
else -> false
}
}
-} \ No newline at end of file
+}
diff --git a/core/src/main/kotlin/ca/allanwang/kau/xml/Changelog.kt b/core/src/main/kotlin/ca/allanwang/kau/xml/Changelog.kt
index 28d51a4..2e66a97 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/xml/Changelog.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/xml/Changelog.kt
@@ -1,39 +1,54 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.xml
import android.content.Context
import android.content.res.XmlResourceParser
-import android.support.annotation.ColorInt
-import android.support.annotation.LayoutRes
-import android.support.annotation.XmlRes
-import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
+import androidx.annotation.ColorInt
+import androidx.annotation.LayoutRes
+import androidx.annotation.XmlRes
+import androidx.recyclerview.widget.RecyclerView
import ca.allanwang.kau.R
+import ca.allanwang.kau.utils.ctxCoroutine
import ca.allanwang.kau.utils.materialDialog
import ca.allanwang.kau.utils.use
import com.afollestad.materialdialogs.MaterialDialog
-import org.jetbrains.anko.doAsync
-import org.jetbrains.anko.uiThread
+import com.afollestad.materialdialogs.list.customListAdapter
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.xmlpull.v1.XmlPullParser
-
/**
* Created by Allan Wang on 2017-05-28.
*
* Easy changelog loader
*/
-fun Context.showChangelog(@XmlRes xmlRes: Int, @ColorInt textColor: Int? = null, customize: MaterialDialog.Builder.() -> Unit = {}) {
- doAsync {
- val items = parse(this@showChangelog, xmlRes)
- uiThread {
- materialDialog {
- title(R.string.kau_changelog)
- positiveText(R.string.kau_great)
- adapter(ChangelogAdapter(items, textColor), null)
- customize()
- }
+fun Context.showChangelog(@XmlRes xmlRes: Int, @ColorInt textColor: Int? = null, customize: MaterialDialog.() -> Unit = {}) {
+ ctxCoroutine.launch {
+ val items = withContext(Dispatchers.Default) { parse(this@showChangelog, xmlRes) }
+ materialDialog {
+ title(R.string.kau_changelog)
+ positiveButton(R.string.kau_great)
+ customListAdapter(ChangelogAdapter(items, textColor), null)
+ customize()
}
}
}
@@ -42,10 +57,13 @@ fun Context.showChangelog(@XmlRes xmlRes: Int, @ColorInt textColor: Int? = null,
* Internals of the changelog dialog
* Contains an mainAdapter for each item, as well as the tags to parse
*/
-internal class ChangelogAdapter(val items: List<Pair<String, ChangelogType>>, @ColorInt val textColor: Int? = null) : RecyclerView.Adapter<ChangelogAdapter.ChangelogVH>() {
+internal class ChangelogAdapter(val items: List<Pair<String, ChangelogType>>, @ColorInt val textColor: Int? = null) :
+ RecyclerView.Adapter<ChangelogAdapter.ChangelogVH>() {
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ChangelogVH(LayoutInflater.from(parent.context)
- .inflate(items[viewType].second.layout, parent, false))
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ChangelogVH(
+ LayoutInflater.from(parent.context)
+ .inflate(items[viewType].second.layout, parent, false)
+ )
override fun onBindViewHolder(holder: ChangelogVH, position: Int) {
holder.text.text = items[position].first
@@ -98,4 +116,3 @@ internal enum class ChangelogType(val tag: String, val attr: String, @LayoutRes
return true
}
}
-
diff --git a/core/src/main/kotlin/ca/allanwang/kau/xml/FAQ.kt b/core/src/main/kotlin/ca/allanwang/kau/xml/FAQ.kt
index 7caf5d6..73d7d6c 100644
--- a/core/src/main/kotlin/ca/allanwang/kau/xml/FAQ.kt
+++ b/core/src/main/kotlin/ca/allanwang/kau/xml/FAQ.kt
@@ -1,13 +1,26 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.xml
import android.content.Context
import android.content.res.XmlResourceParser
-import android.support.annotation.XmlRes
import android.text.Html
import android.text.Spanned
+import androidx.annotation.XmlRes
import ca.allanwang.kau.utils.use
-import org.jetbrains.anko.doAsync
-import org.jetbrains.anko.uiThread
import org.xmlpull.v1.XmlPullParser
/**
@@ -15,51 +28,53 @@ import org.xmlpull.v1.XmlPullParser
*/
/**
- * Parse an xml asynchronously with two tags, <question>Text</question> and <answer>Text</answer>,
- * and invoke the [callback] on the ui thread
+ * Parse an xml asynchronously with two tags, <question>Text</question> and <answer>Text</answer>.
+ * Note that this should executed in a background thread.
*/
@Suppress("DEPRECATION")
fun Context.kauParseFaq(
- @XmlRes xmlRes: Int,
- /**
- * If \n is used, it will automatically be converted to </br>
- */
- parseNewLine: Boolean = true,
- callback: (items: List<FaqItem>) -> Unit) {
- doAsync {
- val items = mutableListOf<FaqItem>()
- resources.getXml(xmlRes).use { parser: XmlResourceParser ->
- var eventType = parser.eventType
- var question: Spanned? = null
- var flag = -1 //-1, 0, 1 -> invalid, question, answer
- while (eventType != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlPullParser.START_TAG) {
- flag = when (parser.name) {
- "question" -> 0
- "answer" -> 1
- else -> -1
+ @XmlRes xmlRes: Int,
+ /**
+ * If \n is used, it will automatically be converted to </br>
+ */
+ parseNewLine: Boolean = true
+): List<FaqItem> {
+ val items = mutableListOf<FaqItem>()
+ resources.getXml(xmlRes).use { parser: XmlResourceParser ->
+ var eventType = parser.eventType
+ var question: Spanned? = null
+ var flag = -1 //-1, 0, 1 -> invalid, question, answer
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ flag = when (parser.name) {
+ "question" -> 0
+ "answer" -> 1
+ else -> -1
+ }
+ } else if (eventType == XmlPullParser.TEXT) {
+ when (flag) {
+ 0 -> {
+ question = Html.fromHtml(parser.text.replace("\n", if (parseNewLine) "<br/>" else ""))
+ flag = -1
}
- } else if (eventType == XmlPullParser.TEXT) {
- when (flag) {
- 0 -> {
- question = Html.fromHtml(parser.text.replace("\n", if (parseNewLine) "<br/>" else ""))
- flag = -1
- }
- 1 -> {
- items.add(FaqItem(items.size + 1,
- question
- ?: throw IllegalArgumentException("KAU FAQ answer found without a question"),
- Html.fromHtml(parser.text.replace("\n", if (parseNewLine) "<br/>" else ""))))
- question = null
- flag = -1
- }
+ 1 -> {
+ items.add(
+ FaqItem(
+ items.size + 1,
+ question
+ ?: throw IllegalArgumentException("KAU FAQ answer found without a question"),
+ Html.fromHtml(parser.text.replace("\n", if (parseNewLine) "<br/>" else ""))
+ )
+ )
+ question = null
+ flag = -1
}
}
- eventType = parser.next()
}
+ eventType = parser.next()
}
- uiThread { callback(items) }
}
+ return items
}
-data class FaqItem(val number: Int, val question: Spanned, val answer: Spanned) \ No newline at end of file
+data class FaqItem(val number: Int, val question: Spanned, val answer: Spanned)
diff --git a/core/src/main/res-public/values-da-rDK/strings_commons.xml b/core/src/main/res-public/values-da-rDK/strings_commons.xml
index 5be1277..745418a 100644
--- a/core/src/main/res-public/values-da-rDK/strings_commons.xml
+++ b/core/src/main/res-public/values-da-rDK/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-de-rDE/strings_commons.xml b/core/src/main/res-public/values-de-rDE/strings_commons.xml
index 015b612..e67292c 100644
--- a/core/src/main/res-public/values-de-rDE/strings_commons.xml
+++ b/core/src/main/res-public/values-de-rDE/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-es-rES/strings_commons.xml b/core/src/main/res-public/values-es-rES/strings_commons.xml
index 7cab287..34e4aa7 100644
--- a/core/src/main/res-public/values-es-rES/strings_commons.xml
+++ b/core/src/main/res-public/values-es-rES/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-fr-rFR/strings_commons.xml b/core/src/main/res-public/values-fr-rFR/strings_commons.xml
index 2d681ff..89a9a99 100644
--- a/core/src/main/res-public/values-fr-rFR/strings_commons.xml
+++ b/core/src/main/res-public/values-fr-rFR/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-gl-rES/strings_commons.xml b/core/src/main/res-public/values-gl-rES/strings_commons.xml
index b9a5564..8b4d1b4 100644
--- a/core/src/main/res-public/values-gl-rES/strings_commons.xml
+++ b/core/src/main/res-public/values-gl-rES/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-hu-rHU/strings_commons.xml b/core/src/main/res-public/values-hu-rHU/strings_commons.xml
index 5488f1d..bae6c1e 100644
--- a/core/src/main/res-public/values-hu-rHU/strings_commons.xml
+++ b/core/src/main/res-public/values-hu-rHU/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-in-rID/strings_commons.xml b/core/src/main/res-public/values-in-rID/strings_commons.xml
index b734377..5532b67 100644
--- a/core/src/main/res-public/values-in-rID/strings_commons.xml
+++ b/core/src/main/res-public/values-in-rID/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-it-rIT/strings_commons.xml b/core/src/main/res-public/values-it-rIT/strings_commons.xml
index 821191e..c2d513a 100644
--- a/core/src/main/res-public/values-it-rIT/strings_commons.xml
+++ b/core/src/main/res-public/values-it-rIT/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-ko-rKR/strings_commons.xml b/core/src/main/res-public/values-ko-rKR/strings_commons.xml
index 112e8d5..48153cb 100644
--- a/core/src/main/res-public/values-ko-rKR/strings_commons.xml
+++ b/core/src/main/res-public/values-ko-rKR/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-nl-rNL/strings_commons.xml b/core/src/main/res-public/values-nl-rNL/strings_commons.xml
new file mode 100644
index 0000000..a3967ff
--- /dev/null
+++ b/core/src/main/res-public/values-nl-rNL/strings_commons.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
+A collection of common string values
+Most resources are verbatim and x represents a formatted item
+-->
+<resources>
+ <string name="kau_about_app">Over de app</string>
+ <string name="kau_about_x">Over %s</string>
+ <string name="kau_add_account">Account toevoegen</string>
+ <string name="kau_back">Terug</string>
+ <string name="kau_cancel">Annuleren</string>
+ <string name="kau_changelog">Veranderingen</string>
+ <string name="kau_close">Sluiten</string>
+ <string name="kau_contact_us">Contact opnemen</string>
+ <string name="kau_copy">Kopiëren</string>
+ <string name="kau_custom">Aangepast</string>
+ <string name="kau_dark">Donker</string>
+ <string name="kau_default">Standaard</string>
+ <string name="kau_do_not_show_again">Niet opnieuw tonen</string>
+ <string name="kau_done">Gereed</string>
+ <string name="kau_error">Fout</string>
+ <string name="kau_exit">Afsluiten</string>
+ <string name="kau_exit_confirmation">Afsluiten?</string>
+ <string name="kau_exit_confirmation_x">%s afsluiten?</string>
+ <string name="kau_glass">Glas</string>
+ <string name="kau_got_it">Begrepen</string>
+ <string name="kau_great">Geweldig</string>
+ <string name="kau_hide">Verbergen</string>
+ <string name="kau_light">Licht</string>
+ <string name="kau_login">Aanmelden</string>
+ <string name="kau_logout">Afmelden</string>
+ <string name="kau_logout_confirm_as_x">%s uitloggen?</string>
+ <string name="kau_manage_account">Account beheren</string>
+ <string name="kau_maybe">Misschien</string>
+ <string name="kau_menu">Menu</string>
+ <string name="kau_no">Nee</string>
+ <string name="kau_no_results_found">Geen resultaten</string>
+ <string name="kau_none">Geen</string>
+ <string name="kau_ok">OK</string>
+ <string name="kau_play_store">Play Store</string>
+ <string name="kau_rate">Beoordelen</string>
+ <string name="kau_report_bug">Een fout melden</string>
+ <string name="kau_search">Zoeken</string>
+ <string name="kau_send_feedback">Feedback geven</string>
+ <string name="kau_send_via">Verzenden via</string>
+ <string name="kau_settings">Instellingen</string>
+ <string name="kau_share">Delen</string>
+ <string name="kau_text_copied">Tekst naar klembord gekopieerd.</string>
+ <string name="kau_thank_you">Bedankt</string>
+ <string name="kau_uh_oh">Oeps</string>
+ <string name="kau_warning">Waarschuwing</string>
+ <plurals name="kau_x_days">
+ <item quantity="one">%d dag</item>
+ <item quantity="other">%d dagen</item>
+ </plurals>
+ <plurals name="kau_x_hours">
+ <item quantity="one">%d uur</item>
+ <item quantity="other">%d uren</item>
+ </plurals>
+ <plurals name="kau_x_minutes">
+ <item quantity="one">%d minuut</item>
+ <item quantity="other">%d minuten</item>
+ </plurals>
+ <plurals name="kau_x_seconds">
+ <item quantity="one">%d seconde</item>
+ <item quantity="other">%d seconden</item>
+ </plurals>
+ <string name="kau_yes">Ja</string>
+ <string name="kau_permission_denied">Toestemming geweigerd</string>
+</resources>
diff --git a/core/src/main/res-public/values-no-rNO/strings_commons.xml b/core/src/main/res-public/values-no-rNO/strings_commons.xml
index c18b439..e27f20d 100644
--- a/core/src/main/res-public/values-no-rNO/strings_commons.xml
+++ b/core/src/main/res-public/values-no-rNO/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-pl-rPL/strings_commons.xml b/core/src/main/res-public/values-pl-rPL/strings_commons.xml
index 248e409..323a0ff 100644
--- a/core/src/main/res-public/values-pl-rPL/strings_commons.xml
+++ b/core/src/main/res-public/values-pl-rPL/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-pt-rBR/strings_commons.xml b/core/src/main/res-public/values-pt-rBR/strings_commons.xml
index 716e373..4eaea6c 100644
--- a/core/src/main/res-public/values-pt-rBR/strings_commons.xml
+++ b/core/src/main/res-public/values-pt-rBR/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-pt-rPT/strings_commons.xml b/core/src/main/res-public/values-pt-rPT/strings_commons.xml
new file mode 100644
index 0000000..863b8b7
--- /dev/null
+++ b/core/src/main/res-public/values-pt-rPT/strings_commons.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
+A collection of common string values
+Most resources are verbatim and x represents a formatted item
+-->
+<resources>
+ <string name="kau_about_app">Acerca</string>
+ <string name="kau_about_x">Acerca de %s</string>
+ <string name="kau_add_account">Adicionar conta</string>
+ <string name="kau_back">Voltar</string>
+ <string name="kau_cancel">Cancelar</string>
+ <string name="kau_changelog">Registo de alterações</string>
+ <string name="kau_close">Fechar</string>
+ <string name="kau_contact_us">Contacte-nos</string>
+ <string name="kau_copy">Copiar</string>
+ <string name="kau_custom">Personalizada</string>
+ <string name="kau_dark">Escuro</string>
+ <string name="kau_default">Padrão</string>
+ <string name="kau_do_not_show_again">Não mostrar novamente</string>
+ <string name="kau_done">Feito</string>
+ <string name="kau_error">Erro</string>
+ <string name="kau_exit">Sair</string>
+ <string name="kau_exit_confirmation">Tem a certeza de que deseja sair?</string>
+ <string name="kau_exit_confirmation_x">Tem a certeza de que deseja sair de %s?</string>
+ <string name="kau_glass">Vidro</string>
+ <string name="kau_got_it">Percebi</string>
+ <string name="kau_great">Excelente</string>
+ <string name="kau_hide">Ocultar</string>
+ <string name="kau_light">Claro</string>
+ <string name="kau_login">Iniciar sessão</string>
+ <string name="kau_logout">Sair</string>
+ <string name="kau_logout_confirm_as_x">Tem a certeza de que deseja sair como %s?</string>
+ <string name="kau_manage_account">Gerir conta</string>
+ <string name="kau_maybe">Talvez</string>
+ <string name="kau_menu">Menu</string>
+ <string name="kau_no">Não</string>
+ <string name="kau_no_results_found">Não existem resultados</string>
+ <string name="kau_none">Nenhum</string>
+ <string name="kau_ok">OK</string>
+ <string name="kau_play_store">Play Store</string>
+ <string name="kau_rate">Avaliar</string>
+ <string name="kau_report_bug">Comunicar um erro</string>
+ <string name="kau_search">Procurar</string>
+ <string name="kau_send_feedback">Enviar comentários</string>
+ <string name="kau_send_via">Enviar via</string>
+ <string name="kau_settings">Definições</string>
+ <string name="kau_share">Partilhar</string>
+ <string name="kau_text_copied">Texto copiado para a área de transferência.</string>
+ <string name="kau_thank_you">Obrigado</string>
+ <string name="kau_uh_oh">Bolas</string>
+ <string name="kau_warning">Aviso</string>
+ <plurals name="kau_x_days">
+ <item quantity="one">%d dia</item>
+ <item quantity="other">%d dias</item>
+ </plurals>
+ <plurals name="kau_x_hours">
+ <item quantity="one">%d hora</item>
+ <item quantity="other">%d horas</item>
+ </plurals>
+ <plurals name="kau_x_minutes">
+ <item quantity="one">%d minuto</item>
+ <item quantity="other">%d minutos</item>
+ </plurals>
+ <plurals name="kau_x_seconds">
+ <item quantity="one">%d segundo</item>
+ <item quantity="other">%d segundos</item>
+ </plurals>
+ <string name="kau_yes">Sim</string>
+ <string name="kau_permission_denied">Permissão negada</string>
+</resources>
diff --git a/core/src/main/res-public/values-sr-rSP/strings_commons.xml b/core/src/main/res-public/values-sr-rSP/strings_commons.xml
new file mode 100644
index 0000000..213d876
--- /dev/null
+++ b/core/src/main/res-public/values-sr-rSP/strings_commons.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
+A collection of common string values
+Most resources are verbatim and x represents a formatted item
+-->
+<resources>
+ <string name="kau_about_app">О апликацији</string>
+ <string name="kau_about_x">О %s</string>
+ <string name="kau_add_account">Додајте налог</string>
+ <string name="kau_back">Назад</string>
+ <string name="kau_cancel">Откажи</string>
+ <string name="kau_changelog">Евиденција измена</string>
+ <string name="kau_close">Затвори</string>
+ <string name="kau_contact_us">Контактирајте нас</string>
+ <string name="kau_copy">Копирај</string>
+ <string name="kau_custom">Прилагођено</string>
+ <string name="kau_dark">Тамно</string>
+ <string name="kau_default">Подразумевано</string>
+ <string name="kau_do_not_show_again">Не приказуј поново</string>
+ <string name="kau_done">Готово</string>
+ <string name="kau_error">Грешка</string>
+ <string name="kau_exit">Изађи</string>
+ <string name="kau_exit_confirmation">Да ли сте сигурни да желите да изађете?</string>
+ <string name="kau_exit_confirmation_x">Да ли сте сигурно желите да напустите %s?</string>
+ <string name="kau_glass">Стакло</string>
+ <string name="kau_got_it">Разумем</string>
+ <string name="kau_great">Одлично</string>
+ <string name="kau_hide">Сакриј</string>
+ <string name="kau_light">Светло</string>
+ <string name="kau_login">Пријава</string>
+ <string name="kau_logout">Одјави се</string>
+ <string name="kau_logout_confirm_as_x">Заиста желите да се одјавите са %s?</string>
+ <string name="kau_manage_account">Управљај налозима</string>
+ <string name="kau_maybe">Можда</string>
+ <string name="kau_menu">Мени</string>
+ <string name="kau_no">Не</string>
+ <string name="kau_no_results_found">Нема резултата</string>
+ <string name="kau_none">Ниједно</string>
+ <string name="kau_ok">ОК</string>
+ <string name="kau_play_store">Плеј продавница</string>
+ <string name="kau_rate">Оцени</string>
+ <string name="kau_report_bug">Пријави грешку</string>
+ <string name="kau_search">Претражи</string>
+ <string name="kau_send_feedback">Пошаљите повратне информације</string>
+ <string name="kau_send_via">Пошаљи преко</string>
+ <string name="kau_settings">Подешавања</string>
+ <string name="kau_share">Подели</string>
+ <string name="kau_text_copied">Текст је копиран у привремену меморију.</string>
+ <string name="kau_thank_you">Хвала</string>
+ <string name="kau_uh_oh">Јао не</string>
+ <string name="kau_warning">Упозорење</string>
+ <plurals name="kau_x_days">
+ <item quantity="one">%d дан</item>
+ <item quantity="few">%d дана</item>
+ <item quantity="other">%d дана</item>
+ </plurals>
+ <plurals name="kau_x_hours">
+ <item quantity="one">%d сат</item>
+ <item quantity="few">%d сати</item>
+ <item quantity="other">%d сати</item>
+ </plurals>
+ <plurals name="kau_x_minutes">
+ <item quantity="one">%d минут</item>
+ <item quantity="few">%d минута</item>
+ <item quantity="other">%d минута</item>
+ </plurals>
+ <plurals name="kau_x_seconds">
+ <item quantity="one">%d секунду</item>
+ <item quantity="few">%d сек</item>
+ <item quantity="other">%d секунди</item>
+ </plurals>
+ <string name="kau_yes">Да</string>
+ <string name="kau_permission_denied">Немате овлашћења</string>
+</resources>
diff --git a/core/src/main/res-public/values-sv-rSE/strings_commons.xml b/core/src/main/res-public/values-sv-rSE/strings_commons.xml
index 6cc2bb3..8d4362b 100644
--- a/core/src/main/res-public/values-sv-rSE/strings_commons.xml
+++ b/core/src/main/res-public/values-sv-rSE/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-th-rTH/strings_commons.xml b/core/src/main/res-public/values-th-rTH/strings_commons.xml
index 2f4bdec..e47273d 100644
--- a/core/src/main/res-public/values-th-rTH/strings_commons.xml
+++ b/core/src/main/res-public/values-th-rTH/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-tr-rTR/strings_commons.xml b/core/src/main/res-public/values-tr-rTR/strings_commons.xml
index 1e8395e..b36ca43 100644
--- a/core/src/main/res-public/values-tr-rTR/strings_commons.xml
+++ b/core/src/main/res-public/values-tr-rTR/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-uk-rUA/strings_commons.xml b/core/src/main/res-public/values-uk-rUA/strings_commons.xml
index 60ca520..0f62c6a 100644
--- a/core/src/main/res-public/values-uk-rUA/strings_commons.xml
+++ b/core/src/main/res-public/values-uk-rUA/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
@@ -48,6 +50,30 @@ Most resources are verbatim and x represents a formatted item
<string name="kau_thank_you">Дякуємо Вам</string>
<string name="kau_uh_oh">Ой-ой</string>
<string name="kau_warning">Увага</string>
+ <plurals name="kau_x_days">
+ <item quantity="one">%d день</item>
+ <item quantity="few">%d днів</item>
+ <item quantity="many">%d днів</item>
+ <item quantity="other">%d днів</item>
+ </plurals>
+ <plurals name="kau_x_hours">
+ <item quantity="one">%d годину</item>
+ <item quantity="few">%d годин</item>
+ <item quantity="many">%d годин</item>
+ <item quantity="other">%d годин</item>
+ </plurals>
+ <plurals name="kau_x_minutes">
+ <item quantity="one">%d хвилини</item>
+ <item quantity="few">%d хвилин</item>
+ <item quantity="many">%d хвилин</item>
+ <item quantity="other">%d хвилин</item>
+ </plurals>
+ <plurals name="kau_x_seconds">
+ <item quantity="one">%d секунди</item>
+ <item quantity="few">%d секунд</item>
+ <item quantity="many">%d секунд</item>
+ <item quantity="other">%d секунд</item>
+ </plurals>
<string name="kau_yes">Так</string>
<string name="kau_permission_denied">У доступі відмовлено</string>
</resources>
diff --git a/core/src/main/res-public/values-vi-rVN/strings_commons.xml b/core/src/main/res-public/values-vi-rVN/strings_commons.xml
index 767e628..a444dc2 100644
--- a/core/src/main/res-public/values-vi-rVN/strings_commons.xml
+++ b/core/src/main/res-public/values-vi-rVN/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-zh-rCN/strings_commons.xml b/core/src/main/res-public/values-zh-rCN/strings_commons.xml
index 47ddbda..66a7423 100644
--- a/core/src/main/res-public/values-zh-rCN/strings_commons.xml
+++ b/core/src/main/res-public/values-zh-rCN/strings_commons.xml
@@ -1,4 +1,6 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?><!--Generated by crowdin.com--><!--
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
A collection of common string values
Most resources are verbatim and x represents a formatted item
-->
diff --git a/core/src/main/res-public/values-zh-rTW/strings_commons.xml b/core/src/main/res-public/values-zh-rTW/strings_commons.xml
new file mode 100644
index 0000000..bf9f59b
--- /dev/null
+++ b/core/src/main/res-public/values-zh-rTW/strings_commons.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--Generated by crowdin.com-->
+<!--
+A collection of common string values
+Most resources are verbatim and x represents a formatted item
+-->
+<resources>
+ <string name="kau_about_app">關於此程式</string>
+ <string name="kau_about_x">關於 %s</string>
+ <string name="kau_add_account">新增帳號</string>
+ <string name="kau_back">回上頁</string>
+ <string name="kau_cancel">取消</string>
+ <string name="kau_changelog">更新資訊</string>
+ <string name="kau_close">關閉</string>
+ <string name="kau_contact_us">與我們聯繫</string>
+ <string name="kau_copy">複製</string>
+ <string name="kau_custom">自訂</string>
+ <string name="kau_dark">黑色主題</string>
+ <string name="kau_default">默認</string>
+ <string name="kau_do_not_show_again">不要再顯示</string>
+ <string name="kau_done">完成</string>
+ <string name="kau_error">錯誤</string>
+ <string name="kau_exit">結束</string>
+ <string name="kau_exit_confirmation">您確定要離開嗎?</string>
+ <string name="kau_exit_confirmation_x">您確定要離開%s嗎?</string>
+ <string name="kau_glass">玻璃</string>
+ <string name="kau_got_it">知道了</string>
+ <string name="kau_great">讚</string>
+ <string name="kau_hide">隱藏</string>
+ <string name="kau_light">亮色調</string>
+ <string name="kau_login">登入</string>
+ <string name="kau_logout">登出</string>
+ <string name="kau_logout_confirm_as_x">您確定要登出%s嗎?</string>
+ <string name="kau_manage_account">帳戶管理</string>
+ <string name="kau_maybe">可能</string>
+ <string name="kau_menu">選單</string>
+ <string name="kau_no">不</string>
+ <string name="kau_no_results_found">找不到相符的結果</string>
+ <string name="kau_none">無</string>
+ <string name="kau_ok">確定</string>
+ <string name="kau_play_store">Play商店</string>
+ <string name="kau_rate">評分</string>
+ <string name="kau_report_bug">回報程式錯誤</string>
+ <string name="kau_search">搜尋</string>
+ <string name="kau_send_feedback">回饋意見</string>
+ <string name="kau_send_via">來發送</string>
+ <string name="kau_settings">設定</string>
+ <string name="kau_share">分享</string>
+ <string name="kau_text_copied">文字已複製到剪貼簿</string>
+ <string name="kau_thank_you">感謝</string>
+ <string name="kau_uh_oh">噢!</string>
+ <string name="kau_warning">警告</string>
+ <plurals name="kau_x_days">
+ <item quantity="other">%d 天</item>
+ </plurals>
+ <plurals name="kau_x_hours">
+ <item quantity="other">%d 小時</item>
+ </plurals>
+ <plurals name="kau_x_minutes">
+ <item quantity="other">%d 分鐘</item>
+ </plurals>
+ <plurals name="kau_x_seconds">
+ <item quantity="other">%d 秒</item>
+ </plurals>
+ <string name="kau_yes">是</string>
+ <string name="kau_permission_denied">權限不足</string>
+</resources>
diff --git a/core/src/main/res/layout/kau_changelog_content.xml b/core/src/main/res/layout/kau_changelog_content.xml
index 5c463aa..ab94956 100644
--- a/core/src/main/res/layout/kau_changelog_content.xml
+++ b/core/src/main/res/layout/kau_changelog_content.xml
@@ -3,9 +3,9 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingBottom="8.4sp"
android:paddingLeft="@dimen/kau_dialog_margin"
- android:paddingRight="@dimen/kau_dialog_margin">
+ android:paddingRight="@dimen/kau_dialog_margin"
+ android:paddingBottom="8.4sp">
<!--padding bottom is 14sp * 0.6-->
diff --git a/core/src/test/kotlin/ca/allanwang/kau/kotlin/CoroutineTest.kt b/core/src/test/kotlin/ca/allanwang/kau/kotlin/CoroutineTest.kt
new file mode 100644
index 0000000..1e86305
--- /dev/null
+++ b/core/src/test/kotlin/ca/allanwang/kau/kotlin/CoroutineTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
+
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import org.junit.Test
+import kotlin.test.assertEquals
+import kotlin.test.fail
+
+/**
+ * Tests geared towards coroutines
+ */
+class CoroutineTest {
+
+ /**
+ * If a job is cancelled, then a switch to a new context will not run
+ */
+ @Test
+ fun implicitCancellationBefore() {
+ val job = Job()
+ var id = 0
+ try {
+ runBlocking(job) {
+ id++
+ job.cancel()
+ withContext(Dispatchers.IO) {
+ fail("Context switch should not be reached")
+ }
+ }
+ } catch (ignore: CancellationException) {
+ } finally {
+ assertEquals(1, id, "Launcher never executed")
+ }
+ }
+
+ /**
+ * If a job is cancelled, then a switch from a new context will not run
+ */
+ @Test
+ fun implicitCancellationAfter() {
+ val job = Job()
+ var id = 0
+ try {
+ runBlocking(job) {
+ withContext(Dispatchers.IO) {
+ id++
+ job.cancel()
+ }
+ fail("Post context switch should not be reached")
+ }
+ } catch (ignore: CancellationException) {
+ } finally {
+ assertEquals(1, id, "Context switch never executed")
+ }
+ }
+}
diff --git a/core/src/test/kotlin/ca/allanwang/kau/kotlin/DebounceTest.kt b/core/src/test/kotlin/ca/allanwang/kau/kotlin/DebounceTest.kt
index 8ccdab3..c406901 100644
--- a/core/src/test/kotlin/ca/allanwang/kau/kotlin/DebounceTest.kt
+++ b/core/src/test/kotlin/ca/allanwang/kau/kotlin/DebounceTest.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
import org.junit.Test
@@ -48,5 +63,4 @@ class DebounceTest {
Thread.sleep(30)
assertEquals(10, i)
}
-
-} \ No newline at end of file
+}
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 2025422..eaaaacb 100644
--- a/core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt
+++ b/core/src/test/kotlin/ca/allanwang/kau/kotlin/LazyResettableTest.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
import org.junit.Before
@@ -33,5 +48,4 @@ class LazyResettableTest {
assertEquals(t1, t2, "Lazy resettable not returning same value after second call")
assertNotEquals(t1, t3, "Lazy resettable not invalidated by registry")
}
-
-} \ No newline at end of file
+}
diff --git a/core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt b/core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt
index 1c40f57..4dc4a34 100644
--- a/core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt
+++ b/core/src/test/kotlin/ca/allanwang/kau/kotlin/StreamsTest.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.kotlin
import org.junit.Test
@@ -38,5 +53,4 @@ class StreamsTest {
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/kotlin/ZipTest.kt b/core/src/test/kotlin/ca/allanwang/kau/kotlin/ZipTest.kt
deleted file mode 100644
index 7eeffaf..0000000
--- a/core/src/test/kotlin/ca/allanwang/kau/kotlin/ZipTest.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package ca.allanwang.kau.kotlin
-
-import org.jetbrains.anko.doAsync
-import org.junit.Test
-import java.util.*
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertTrue
-
-/**
- * Created by Allan Wang on 2017-08-06.
- */
-class ZipTest {
-
- val debug = false
-
- fun p(text: String) {
- if (debug) println(text)
- }
-
- @Test
- fun basic() {
- val start = System.currentTimeMillis()
- val latch = CountDownLatch(1)
- val rnd = Random()
- (0..10).map {
- { callback: ZipCallback<Int> ->
- doAsync {
- val sleepTime = rnd.nextInt(100) + 200L
- p("Task $it will sleep for ${sleepTime}ms")
- Thread.sleep(sleepTime)
- val finish = System.currentTimeMillis()
- p("Task $it finished in ${finish - start}ms at $finish")
- callback(it)
- }; Unit
- }
- }.zip(-1) { results ->
- val finish = System.currentTimeMillis()
- println("Results ${results.contentToString()} received in ${finish - start}ms at $finish")
- assertTrue((0..10).toList().toTypedArray().contentEquals(results), "Basic zip results do not match")
- assertTrue(finish - start < 1000L, "Basic zip does not seem to be running asynchronously")
- latch.countDown()
-
- }
- latch.await(1100, TimeUnit.MILLISECONDS)
- }
-
- @Test
- fun basicAsync() {
- val start = System.currentTimeMillis()
- val latch = CountDownLatch(1)
- val rnd = Random()
- (0..10).map {
- {
- val sleepTime = rnd.nextInt(100) + 200L
- p("Task $it will sleep for ${sleepTime}ms")
- Thread.sleep(sleepTime)
- val finish = System.currentTimeMillis()
- p("Task $it finished in ${finish - start}ms at $finish")
- }
- }.zipAsync {
- val finish = System.currentTimeMillis()
- println("Results received in ${finish - start}ms at $finish")
- assertTrue(finish - start < 1000L, "BasicAsync does not seem to be wrapping the tasks asynchronously")
- latch.countDown()
- }
- latch.await(1100, TimeUnit.MILLISECONDS)
- }
-
-} \ 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 ce2b757..b9c200a 100644
--- a/core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt
+++ b/core/src/test/kotlin/ca/allanwang/kau/utils/UtilsTest.kt
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2018 Allan Wang
+ *
+ * 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 ca.allanwang.kau.utils
import android.graphics.Color
@@ -17,9 +32,27 @@ class UtilsTest {
}
@Test
+ fun colorWithAlpha() {
+ val origColor = 0xFF123456.toInt()
+ assertEquals(0x00123456, origColor.withAlpha(0), "Failed to convert with alpha 0")
+ assertEquals(0x50123456, origColor.withAlpha(80), "Failed to convert with alpha 80")
+ assertEquals(0xFF123456.toInt(), origColor.withAlpha(255), "Failed to convert with alpha 255")
+ assertEquals(0xFF123456.toInt(), origColor.withAlpha(0xFF), "Failed to convert with alpha 0xFF")
+ assertEquals(Color.TRANSPARENT, Color.BLACK.withAlpha(0), "Failed to convert black to transparent")
+ }
+
+ @Test
+ fun colorWithMinAlpha() {
+ val origColor = 0x80123456.toInt()
+ assertEquals(origColor, origColor.withMinAlpha(0), "Failed to convert with min alpha 0")
+ assertEquals(0xFA123456.toInt(), origColor.withMinAlpha(0xFA), "Failed to convert with min alpha 0xFA")
+ assertEquals(Color.BLUE, Color.BLUE.withMinAlpha(89), "Failed to convert blue with min alpha 89")
+ }
+
+ @Test
fun rounding() {
assertEquals("1.23", 1.23456f.round(2))
assertEquals("22.466", 22.465920439.round(3))
assertEquals("22", 22f.round(3))
}
-} \ No newline at end of file
+}