diff options
author | Allan Wang <me@allanwang.ca> | 2017-08-02 16:21:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-02 16:21:49 -0700 |
commit | 53382b44bb7ab7ccb559e96fd1f93c47020878ee (patch) | |
tree | 79c1862992f458ac52c1910b3a2e0c01cb7d5a5a | |
parent | 7d894be6de118357ec908d2d171b6152ce67307d (diff) | |
download | kau-53382b44bb7ab7ccb559e96fd1f93c47020878ee.tar.gz kau-53382b44bb7ab7ccb559e96fd1f93c47020878ee.tar.bz2 kau-53382b44bb7ab7ccb559e96fd1f93c47020878ee.zip |
Improve video prefetching (#17)
* Create base activity and add thumbnails to media picker
* Add checker to see if requested permission is inside the manifest
* Add faq parser with tests
* Add kpref testers and expose sp
* Test jitpack sample exclusion
* Test caching
* Improve glide caching
28 files changed, 322 insertions, 52 deletions
diff --git a/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt b/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt index 19fb4c4..61a3bb2 100644 --- a/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt +++ b/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt @@ -16,6 +16,7 @@ import ca.allanwang.kau.adapters.ThemableIItemColorsDelegate import ca.allanwang.kau.animators.FadeScaleAnimatorAdd import ca.allanwang.kau.animators.KauAnimator import ca.allanwang.kau.iitems.HeaderIItem +import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout import ca.allanwang.kau.ui.widgets.InkPageIndicator import ca.allanwang.kau.utils.* @@ -37,7 +38,7 @@ import java.security.InvalidParameterException * Note that for the auto detection to work, the R fields must be excluded from Proguard * Manual lib listings and other extra modifications can be done so by overriding the open functions */ -abstract class AboutActivityBase(val rClass: Class<*>?, val configBuilder: Configs.() -> Unit = {}) : AppCompatActivity(), ViewPager.OnPageChangeListener { +abstract class AboutActivityBase(val rClass: Class<*>?, val configBuilder: Configs.() -> Unit = {}) : KauBaseActivity(), ViewPager.OnPageChangeListener { val draggableFrame: ElasticDragDismissFrameLayout by bindView(R.id.about_draggable_frame) val pager: ViewPager by bindView(R.id.about_pager) diff --git a/android-lib.gradle b/android-lib.gradle index f45aa02..46de84c 100644 --- a/android-lib.gradle +++ b/android-lib.gradle @@ -72,10 +72,7 @@ android { dependencies { androidTestCompile 'com.android.support.test:runner:0.5' - androidTestCompile 'com.android.support.test:rules:0.5' - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { - exclude group: 'com.android.support', module: 'support-annotations' - }) - testCompile 'junit:junit:4.12' + androidTestCompile "org.jetbrains.kotlin:kotlin-test-junit:${KOTLIN}" testCompile "org.jetbrains.kotlin:kotlin-test-junit:${KOTLIN}" + testCompile 'junit:junit:4.12' }
\ No newline at end of file diff --git a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/activities/ElasticRecyclerActivity.kt b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/activities/ElasticRecyclerActivity.kt index 20a81e4..4c5563b 100644 --- a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/activities/ElasticRecyclerActivity.kt +++ b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/activities/ElasticRecyclerActivity.kt @@ -10,6 +10,7 @@ import android.support.v7.app.AppCompatActivity import android.support.v7.widget.RecyclerView import android.support.v7.widget.Toolbar import android.transition.TransitionInflater +import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.ui.R import ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout import ca.allanwang.kau.utils.bindView @@ -26,7 +27,7 @@ import ca.allanwang.kau.utils.bindView * The exit animation is set to slide out, but the entrance must be defined yourself */ @RequiresApi(Build.VERSION_CODES.LOLLIPOP) -abstract class ElasticRecyclerActivity : AppCompatActivity() { +abstract class ElasticRecyclerActivity : KauBaseActivity() { val appBar: AppBarLayout by bindView(R.id.kau_appbar) val toolbar: Toolbar by bindView(R.id.kau_toolbar) diff --git a/core/README.md b/core/README.md index c26836e..b952797 100644 --- a/core/README.md +++ b/core/README.md @@ -6,6 +6,7 @@ * [KPrefs](#kprefs) * [Changelog XML](#changelog) +* [FAQ XML](#faq-xml) * [Kotterknife](#kotterknife) * [Ripple Canvas](#ripple-canvas) * [MeasureSpecDelegate](#measure-spec-delegate) @@ -106,6 +107,20 @@ Here is a template xml changelog file: </resources> ``` +<a name="faq-xml"></a> +## FAQ XML + +There is another parser for a FAQ list with the following format: + +```xml +<question>This is a question</question> +<answer>This is an answer</answer> +``` + +Calling `kauParseFaq` will give you a `List<Pair<Spanned, Spanned>` that you can work with. +By default, the questions are numbered, and the content is formatted with HTML. +You may still need to add your own methods to allow interaction with certain elements such as links. + <a name="kotterknife"></a> ## Kotterknife diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt new file mode 100644 index 0000000..e806a3f --- /dev/null +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt @@ -0,0 +1,85 @@ +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 org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +/** + * Created by Allan Wang on 2017-08-01. + */ +@RunWith(AndroidJUnit4::class) +@MediumTest +class ChangelogTest { + + lateinit var pref: TestPref + + class TestPref : KPref() { + init { + initialize(InstrumentationRegistry.getTargetContext(), "kpref_test_${System.currentTimeMillis()}") + } + + var one: Int by kpref("one", 1) + + var `true`: Boolean by kpref("true", true) + + var hello: String by kpref("hello", "hello") + + var set: StringSet by kpref("set", setOf("po", "ta", "to")) + + val oneShot: Boolean by kprefSingle("asdf") + } + + @Before + fun init() { + pref = TestPref() + } + + @Test + fun getDefaults() { + assertEquals(1, pref.one) + assertEquals(true, pref.`true`) + assertEquals("hello", pref.hello) + assertEquals(3, pref.set.size) + assertTrue(pref.set.contains("po")) + assertTrue(pref.set.contains("ta")) + assertTrue(pref.set.contains("to")) + } + + @Test + fun setter() { + assertEquals(1, pref.one) + pref.one = 2 + assertEquals(2, pref.one) + pref.hello = "goodbye" + assertEquals("goodbye", pref.hello) + assertEquals(pref.hello, pref.sp.getString("hello", "hello")) + } + + @SuppressLint("CommitPrefEdits") + @Test + fun reset() { + pref.one = 2 + assertEquals(2, pref.one) + pref.reset() //only invalidates our lazy delegate; doesn't change the actual pref + assertEquals(2, pref.one) + pref.sp.edit().putInt("one", -1).commit() + assertEquals(2, pref.one) //our lazy delegate still retains the old value + pref.reset() + assertEquals(-1, pref.one) //back in sync with sp + } + + + @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 3282911..1dac92f 100644 --- a/core/src/androidTest/kotlin/ca/allanwang/kau/utils/KotterknifeTest.kt +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/utils/KotterknifeTest.kt @@ -7,10 +7,12 @@ import android.support.test.runner.AndroidJUnit4 import android.view.View import android.widget.FrameLayout import android.widget.TextView -import org.junit.Assert.* import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull /** * Created by Allan Wang on 2017-07-30. diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/ChangelogTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/ChangelogTest.kt index dcff70e..a3c9ff1 100644 --- a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/ChangelogTest.kt +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/ChangelogTest.kt @@ -14,9 +14,9 @@ import org.junit.runner.RunWith @MediumTest class ChangelogTest { - @Test +// @Test //todo internal function sharing is only available on gradle 3.0.0+ fun simpleTest() { - val data = parse(InstrumentationRegistry.getTargetContext(), R.xml.text_changelog) +// val data = parse(InstrumentationRegistry.getTargetContext(), R.xml.test_changelog) } }
\ No newline at end of file diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt new file mode 100644 index 0000000..94d1330 --- /dev/null +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/xml/FaqTest.kt @@ -0,0 +1,38 @@ +package ca.allanwang.kau.xml + +import android.support.test.InstrumentationRegistry +import android.support.test.filters.MediumTest +import android.support.test.runner.AndroidJUnit4 +import ca.allanwang.kau.test.R +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals + +/** + * Created by Allan Wang on 2017-08-01. + */ +@RunWith(AndroidJUnit4::class) +@MediumTest +class FaqTest { + + @Test + fun simpleTest() { + val data = InstrumentationRegistry.getTargetContext().kauParseFaq(R.xml.test_faq) + assertEquals(2, data.size, "FAQ size is incorrect") + assertEquals("1. This is a question", data.first().first.toString(), "First question does not match") + assertEquals("This is an answer", data.first().second.toString(), "First answer does not match") + assertEquals("2. This is another question", data.last().first.toString(), "Second question does not match") + assertEquals("This is another answer", data.last().second.toString(), "Second answer does not match") + } + + @Test + fun withoutNumbering() { + val data = InstrumentationRegistry.getTargetContext().kauParseFaq(R.xml.test_faq, false) + assertEquals(2, data.size, "FAQ size is incorrect") + assertEquals("This is a question", data.first().first.toString(), "First question does not match") + assertEquals("This is an answer", data.first().second.toString(), "First answer does not match") + assertEquals("This is another question", data.last().first.toString(), "Second question does not match") + assertEquals("This is another answer", data.last().second.toString(), "Second answer does not match") + } + +}
\ No newline at end of file diff --git a/core/src/androidTest/res/xml/test_changelog.xml b/core/src/androidTest/res/xml/test_changelog.xml new file mode 100644 index 0000000..2e90561 --- /dev/null +++ b/core/src/androidTest/res/xml/test_changelog.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <version title="v1.1"/> + <item text="This is version 1.1" /> + <item text="This is the last line to be displayed" /> + <item text="" /> + + <version title="v1.0"/> + <item text="potato 1.0" /> + +</resources>
\ No newline at end of file diff --git a/core/src/androidTest/res/xml/test_faq.xml b/core/src/androidTest/res/xml/test_faq.xml new file mode 100644 index 0000000..4905df3 --- /dev/null +++ b/core/src/androidTest/res/xml/test_faq.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <question>This is a question</question> + <answer>This is an answer</answer> + <question>This is another question</question> + <answer>This is another answer</answer> + +</resources>
\ No newline at end of file diff --git a/core/src/androidTest/res/xml/text_changelog.xml b/core/src/androidTest/res/xml/text_changelog.xml deleted file mode 100644 index 6294144..0000000 --- a/core/src/androidTest/res/xml/text_changelog.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - - <version title="title1"/> - <item text="test case" /> - <item text="" /> - - <version title="title2"/> - <item text="potato" /> - -</resources>
\ 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 new file mode 100644 index 0000000..87d94ce --- /dev/null +++ b/core/src/main/kotlin/ca/allanwang/kau/internal/KauBaseActivity.kt @@ -0,0 +1,21 @@ +package ca.allanwang.kau.internal + +import android.support.v7.app.AppCompatActivity +import ca.allanwang.kau.permissions.kauOnRequestPermissionsResult + +/** + * Created by Allan Wang on 2017-08-01. + * + * Base activity for any activity that would have extended [AppCompatActivity] + * + * Ensures that some singleton methods are called. + * This is simply a convenience class; + * you can always copy and paste this to your own class. + */ +abstract class KauBaseActivity : AppCompatActivity() { + + 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/LazyResettable.kt b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt index 701cb07..2ac5d2f 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kotlin/LazyResettable.kt @@ -50,7 +50,7 @@ open class LazyResettable<T : Any>(private val initializer: () -> T, lock: Any? } } -interface ILazyResettable<T> : Lazy<T> { +interface ILazyResettable<out T> : Lazy<T> { fun invalidate() } 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 c1ce282..be16c7c 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt @@ -39,7 +39,8 @@ open class KPref { } } - internal val sp: SharedPreferences by lazy { + //todo hide this + val sp: SharedPreferences by lazy { if (!initialized) throw KPrefException("KPref object has not yet been initialized; please initialize it with a context and preference name") c.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) } 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 d6e17db..0c42574 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/permissions/PermissionManager.kt @@ -2,13 +2,17 @@ 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 ca.allanwang.kau.kotlin.lazyContext import ca.allanwang.kau.logging.KL import ca.allanwang.kau.utils.KauException import ca.allanwang.kau.utils.buildIsMarshmallowAndUp 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. */ @@ -17,6 +21,17 @@ internal object PermissionManager { var requestInProgress = false val pendingResults: MutableList<WeakReference<PermissionResult>> by lazy { mutableListOf<WeakReference<PermissionResult>>() } + /** + * Retrieve permissions requested in our manifest + */ + val manifestPermission = lazyContext<Array<String>> { + try { + it.packageManager.getPackageInfo(it.packageName, PackageManager.GET_PERMISSIONS)?.requestedPermissions ?: emptyArray() + } catch (e: Exception) { + emptyArray() + } + } + 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) @@ -30,6 +45,13 @@ internal object PermissionManager { } @Synchronized internal fun requestPermissions(context: Context, permissions: Array<out String>) { + permissions.forEach { + if (!manifestPermission(context).contains(it)) { + KL.e("Requested permission $it is not stated in the manifest") + context.toast("$it is not in the manifest") + //we'll let the request pass through so it can be denied and so the callback can be triggered + } + } val activity = (context as? Activity) ?: throw KauException("Context is not an instance of an activity; cannot request permissions") KL.d("Requesting permissions ${permissions.contentToString()}") ActivityCompat.requestPermissions(activity, permissions, 1) 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 edc1536..716fd71 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 @@ -11,6 +11,8 @@ import ca.allanwang.kau.utils.parentViewGroup * Created by Allan Wang on 2017-07-14. * * Handles relative sizes for any view + * You may delegate all methods to [MeasureSpecDelegate] + * and call the two methods: [initAttrs] and [onMeasure] */ interface MeasureSpecContract { @@ -53,6 +55,16 @@ interface MeasureSpecContract { * Calculates the final measure specs * Call this from [View.onMeasure] and send the Pair result as the specs * The pair is of the format (width, height) + * + * Example: + * <pre> + * {@code + * override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + * val result = onMeasure(this, widthMeasureSpec, heightMeasureSpec) + * super.onMeasure(result.first, result.second) + * } + * } + * </pre> */ fun onMeasure(view: View, widthMeasureSpec: Int, heightMeasureSpec: Int): Pair<Int, Int> } 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 dedfbbf..b39540c 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/xml/FAQ.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/xml/FAQ.kt @@ -22,16 +22,28 @@ fun Context.kauParseFaq(@XmlRes xmlRes: Int, withNumbering: Boolean = true): Lis 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) { - if (parser.name == "question") { - var q = parser.text.replace("\n", "<br/>") - if (withNumbering) q = "${items.size + 1}. $q" - question = Html.fromHtml(q) - } else if (parser.name == "answer") { - items.add(Pair(question ?: throw IllegalArgumentException("KAU FAQ answer found without a question"), - Html.fromHtml(parser.text.replace("\n", "<br/>")))) - question = null + flag = when (parser.name) { + "question" -> 0 + "answer" -> 1 + else -> -1 + } + } else if (eventType == XmlPullParser.TEXT) { + when (flag) { + 0 -> { + var q = parser.text.replace("\n", "<br/>") + if (withNumbering) q = "${items.size + 1}. $q" + question = Html.fromHtml(q) + flag = -1 + } + 1 -> { + items.add(Pair(question ?: throw IllegalArgumentException("KAU FAQ answer found without a question"), + Html.fromHtml(parser.text.replace("\n", "<br/>")))) + question = null + flag = -1 + } } } diff --git a/docs/Changelog.md b/docs/Changelog.md index 9a1ec82..64d4644 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,5 +1,11 @@ # Changelog +## v3.2.2 +* :core: Add simple KauBaseActivity so that activities extending AppCompatActivity can have some default kau helpers implemented +* :core: The permission manager will now notify you if you try to request a permission that isn\'t added to your manifest +* :core: Create faq parser +* Begin writing android tests + ## v3.2.1 * :core: Remove requestLayout call from setMargin and setPadding * :core: Fix kau direction bits diff --git a/gradle.properties b/gradle.properties index 084621b..5fa8125 100644 --- a/gradle.properties +++ b/gradle.properties @@ -30,7 +30,7 @@ BLURRY=2.1.1 CONSTRAINT_LAYOUT=1.1.0-beta1 FAST_ADAPTER=2.6.2 FAST_ADAPTER_COMMONS=2.6.0 -GLIDE=4.0.0-RC1 +GLIDE=4.0.0 ICONICS=2.9.0 IICON_GOOGLE=3.0.1.1 MATERIAL_DIALOG=0.9.4.5 diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt index 91c0cf2..4324fd3 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefActivity.kt @@ -12,6 +12,7 @@ import android.view.animation.Animation import android.view.animation.AnimationUtils import android.widget.FrameLayout import android.widget.ViewAnimator +import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.kpref.activity.items.KPrefItemCore import ca.allanwang.kau.ui.views.RippleCanvas import ca.allanwang.kau.ui.widgets.TextSlider @@ -21,7 +22,7 @@ import ca.allanwang.kau.utils.statusBarColor import ca.allanwang.kau.utils.string import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter -abstract class KPrefActivity : AppCompatActivity(), KPrefActivityContract { +abstract class KPrefActivity : KauBaseActivity(), KPrefActivityContract { val adapter: FastItemAdapter<KPrefItemCore> @Suppress("UNCHECKED_CAST") diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt index 3947809..b6f3721 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt @@ -40,6 +40,7 @@ class MediaItem(val data: MediaModel) super.bindView(holder, payloads) Glide.with(holder.itemView) .load(data.data) + .applyMediaOptions(holder.itemView.context) .listener(object : RequestListener<Drawable> { override fun onLoadFailed(e: GlideException?, model: Any, target: Target<Drawable>, isFirstResource: Boolean): Boolean { failedToLoad = true diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt index 4fbe955..c28ed29 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt @@ -47,6 +47,7 @@ class MediaItemBasic(val data: MediaModel) super.bindView(holder, payloads) Glide.with(holder.itemView) .load(data.data) + .applyMediaOptions(holder.itemView.context) .listener(object : RequestListener<Drawable> { override fun onLoadFailed(e: GlideException?, model: Any, target: Target<Drawable>, isFirstResource: Boolean): Boolean { holder.image.setImageDrawable(MediaPickerCore.getErrorDrawable(holder.itemView.context)) diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt index bdd25ba..cb218fc 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt @@ -1,8 +1,12 @@ package ca.allanwang.kau.mediapicker import android.app.Activity +import android.content.Context import android.content.Intent import ca.allanwang.kau.utils.startActivityForResult +import com.bumptech.glide.RequestBuilder +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.RequestOptions /** * Created by Allan Wang on 2017-07-21. @@ -31,3 +35,6 @@ internal const val MEDIA_PICKER_RESULT = "media_picker_result" internal const val ANIMATION_DURATION = 200L internal const val ANIMATION_SCALE = 0.95f +internal fun <T> RequestBuilder<T>.applyMediaOptions(context: Context) + = apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.RESOURCE).centerCrop().override(MediaPickerCore.viewSize(context))) + diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt index 255cec4..ee3481d 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt @@ -12,34 +12,42 @@ import android.provider.MediaStore import android.support.v4.app.LoaderManager import android.support.v4.content.CursorLoader import android.support.v4.content.Loader -import android.support.v7.app.AppCompatActivity import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.RecyclerView import ca.allanwang.kau.animators.FadeScaleAnimatorAdd import ca.allanwang.kau.animators.KauAnimator +import ca.allanwang.kau.internal.KauBaseActivity +import ca.allanwang.kau.kotlin.lazyContext import ca.allanwang.kau.permissions.kauRequestPermissions import ca.allanwang.kau.utils.dimenPixelSize import ca.allanwang.kau.utils.toast +import com.bumptech.glide.Glide import com.mikepenz.fastadapter.IItem import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.IconicsDrawable +import org.jetbrains.anko.doAsync +import java.util.concurrent.ExecutionException +import java.util.concurrent.Future /** * Created by Allan Wang on 2017-07-23. * * Container for the main logic behind the both pickers */ -abstract class MediaPickerCore<T : IItem<*, *>>(val mediaType: MediaType) : AppCompatActivity(), LoaderManager.LoaderCallbacks<Cursor> { +abstract class MediaPickerCore<T : IItem<*, *>>( + val mediaType: MediaType, val preload: Boolean = mediaType == MediaType.VIDEO +) : KauBaseActivity(), LoaderManager.LoaderCallbacks<Cursor> { companion object { + val viewSize = lazyContext { computeViewSize(it) } /** * Given the dimensions of our device and a minimum image size, * Computer the optimal column count for our grid layout * * @return column count */ - fun computeColumnCount(context: Context): Int { + private fun computeColumnCount(context: Context): Int { val minImageSizePx = context.dimenPixelSize(R.dimen.kau_image_minimum_size) val screenWidthPx = context.resources.displayMetrics.widthPixels return screenWidthPx / minImageSizePx @@ -48,7 +56,7 @@ abstract class MediaPickerCore<T : IItem<*, *>>(val mediaType: MediaType) : AppC /** * Compute our resulting image size */ - fun computeViewSize(context: Context): Int { + private fun computeViewSize(context: Context): Int { val screenWidthPx = context.resources.displayMetrics.widthPixels return screenWidthPx / computeColumnCount(context) } @@ -84,6 +92,9 @@ abstract class MediaPickerCore<T : IItem<*, *>>(val mediaType: MediaType) : AppC const val CACHE_SIZE = 80 } + private var hasPreloaded = false + private var prefetcher: Future<*>? = null + val adapter: FastItemAdapter<T> = FastItemAdapter() /** @@ -140,13 +151,30 @@ abstract class MediaPickerCore<T : IItem<*, *>>(val mediaType: MediaType) : AppC onStatusChange(false) return } - val items = mutableListOf<T>() + val models = mutableListOf<MediaModel>() do { val model = MediaModel(data) if (!shouldLoad(model)) continue - items.add(converter(model)) + models.add(model) } while (data.moveToNext()) - addItems(items) + addItems(models.map { converter(it) }) + if (!hasPreloaded && preload) { + hasPreloaded = true + prefetcher = doAsync { + models.subList(0, Math.min(models.size, 50)).map { it.data }.forEach { + val target = Glide.with(this@MediaPickerCore).load(it) + .applyMediaOptions(this@MediaPickerCore) + .submit() + try { + target.get() + } catch (ignored: InterruptedException) { + } catch (ignored: ExecutionException) { + } finally { + Glide.with(this@MediaPickerCore).clear(target) + } + } + } + } } abstract fun converter(model: MediaModel): T @@ -179,4 +207,8 @@ abstract class MediaPickerCore<T : IItem<*, *>>(val mediaType: MediaType) : AppC open fun onStatusChange(loaded: Boolean) {} + override fun onDestroy() { + prefetcher?.cancel(true) + super.onDestroy() + } }
\ No newline at end of file diff --git a/mediapicker/src/main/res/layout/kau_blurred_imageview.xml b/mediapicker/src/main/res/layout/kau_blurred_imageview.xml index e28cb9a..70ad00e 100644 --- a/mediapicker/src/main/res/layout/kau_blurred_imageview.xml +++ b/mediapicker/src/main/res/layout/kau_blurred_imageview.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt index abf44d8..cd86d38 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/AnimActivity.kt @@ -1,11 +1,11 @@ package ca.allanwang.kau.sample import android.os.Bundle -import android.support.v7.app.AppCompatActivity +import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.logging.KL import ca.allanwang.kau.permissions.PERMISSION_ACCESS_COARSE_LOCATION import ca.allanwang.kau.permissions.PERMISSION_ACCESS_FINE_LOCATION -import ca.allanwang.kau.permissions.kauOnRequestPermissionsResult +import ca.allanwang.kau.permissions.PERMISSION_CAMERA import ca.allanwang.kau.permissions.kauRequestPermissions import ca.allanwang.kau.swipe.SWIPE_EDGE_LEFT import ca.allanwang.kau.swipe.kauSwipeOnCreate @@ -23,7 +23,7 @@ import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter * Activity for animations * Now also showcases permissions */ -class AnimActivity : AppCompatActivity() { +class AnimActivity : KauBaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -32,7 +32,8 @@ class AnimActivity : AppCompatActivity() { adapter.add(listOf( PERMISSION_ACCESS_COARSE_LOCATION, - PERMISSION_ACCESS_FINE_LOCATION + PERMISSION_ACCESS_FINE_LOCATION, + PERMISSION_CAMERA ).map { PermissionCheckbox(it) }) adapter.withOnClickListener { _, _, item, _ -> KL.d("Perm Click") @@ -62,8 +63,4 @@ class AnimActivity : AppCompatActivity() { startActivitySlideOut(MainActivity::class.java) } - 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/sample/src/main/res/xml/kau_changelog.xml b/sample/src/main/res/xml/kau_changelog.xml index 59d51c2..615f467 100644 --- a/sample/src/main/res/xml/kau_changelog.xml +++ b/sample/src/main/res/xml/kau_changelog.xml @@ -6,7 +6,14 @@ <item text="" /> --> - <version title="v3.2.1"/> + <version title="v3.2.2"/> + <item text=":core: Add simple KauBaseActivity so that activities extending AppCompatActivity can have some default kau helpers implemented" /> + <item text=":core: The permission manager will now notify you if you try to request a permission that isn\'t added to your manifest" /> + <item text=":core: Create faq parser" /> + <item text="Begin writing android tests" /> + <item text="" /> + + <version title="v3.2.1"/> <item text=":core: Remove requestLayout call from setMargin and setPadding" /> <item text=":core: Fix kau direction bits" /> <item text=":core: Greatly simplify ripple canvas and truly support transparent ripples" /> diff --git a/settings.gradle b/settings.gradle index 1a883b6..031dff4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,10 +1,12 @@ include ':core', - ':sample', + ':core-ui', ':about', ':adapter', ':colorpicker', - ':core-ui', ':mediapicker', ':kpref-activity', ':searchview' + +if (!System.env.JITPACK) + include ':sample'
\ No newline at end of file |