diff options
92 files changed, 1046 insertions, 414 deletions
diff --git a/about/README.md b/about/README.md index dfe6452..e7012b5 100644 --- a/about/README.md +++ b/about/README.md @@ -13,7 +13,12 @@ This activity can be easily added by extending `AboutActivityBase`. Everything is already prepared, but you can modify the theme or other components through the config DSL or through the open functions. There are also numerous iitem cards already prepared (in this submodule and from `:adapter`)if you wish to add that in your main view. -Be sure to include the activity in your Manifest and have it extend `Kau.Translucent.About`, or any other style that achieves the same look. +You may also easily launch the activity through the simple binder: +``` +Activity.kauLaunchAbout(YourClass::class.java) +``` + +Be sure to include the activity in your Manifest and have it extend `Kau.About`, or any other style that achieves the same look. ## Proguard diff --git a/about/build.gradle b/about/build.gradle index 6898217..5decae4 100644 --- a/about/build.gradle +++ b/about/build.gradle @@ -1,9 +1,5 @@ apply from: '../android-lib.gradle' -android { - resourcePrefix "kau_" -} - dependencies { compile project(':core-ui') compile project(':adapter') 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 b3e3e41..19fb4c4 100644 --- a/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt +++ b/about/src/main/kotlin/ca/allanwang/kau/about/AboutActivityBase.kt @@ -121,7 +121,7 @@ abstract class AboutActivityBase(val rClass: Class<*>?, val configBuilder: Confi * Method to fetch the library list * This is fetched asynchronously and you may override it to customize the list */ - open fun getLibraries(libs: Libs): List<Library> = libs.prepareLibraries(this, null, null, true, true) + open fun getLibraries(libs: Libs): List<Library> = libs.prepareLibraries(this, null, null, true, true)!! /** * Gets the view associated with the given page position diff --git a/about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt b/about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt new file mode 100644 index 0000000..902f6e5 --- /dev/null +++ b/about/src/main/kotlin/ca/allanwang/kau/about/AboutBinder.kt @@ -0,0 +1,15 @@ +package ca.allanwang.kau.about + +import android.app.Activity +import ca.allanwang.kau.utils.startActivity + +/** + * Created by Allan Wang on 2017-07-22. + */ + +/** + * About activity launcher + */ +fun Activity.kauLaunchAbout(clazz: Class<out AboutActivityBase>) { + startActivity(clazz, transition = true) +}
\ No newline at end of file diff --git a/about/src/main/res-public/values/public.xml b/about/src/main/res-public/values/public.xml new file mode 100644 index 0000000..f89ddb7 --- /dev/null +++ b/about/src/main/res-public/values/public.xml @@ -0,0 +1,16 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='kau_about_libraries_intro' type='string' /> + <public name='library_kau_libraryVersion' type='string' /> + <public name='define_kau' type='string' /> + <public name='library_kau_author' type='string' /> + <public name='library_kau_authorWebsite' type='string' /> + <public name='library_kau_libraryName' type='string' /> + <public name='library_kau_libraryDescription' type='string' /> + <public name='library_kau_libraryWebsite' type='string' /> + <public name='library_kau_isOpenSource' type='string' /> + <public name='library_kau_repositoryLink' type='string' /> + <public name='library_kau_classPath' type='string' /> + <public name='library_kau_licenseId' type='string' /> + <public name='Kau.About' type='style' /> +</resources>
\ No newline at end of file diff --git a/about/src/main/res-public/values/strings.xml b/about/src/main/res-public/values/strings.xml new file mode 100644 index 0000000..509b56c --- /dev/null +++ b/about/src/main/res-public/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="kau_about_libraries_intro">This app would not be possible without the following great libraries.</string> +</resources>
\ No newline at end of file diff --git a/about/src/main/res/values/strings_about.xml b/about/src/main/res-public/values/strings_about.xml index f538e59..f538e59 100644 --- a/about/src/main/res/values/strings_about.xml +++ b/about/src/main/res-public/values/strings_about.xml diff --git a/about/src/main/res-public/values/styles.xml b/about/src/main/res-public/values/styles.xml new file mode 100644 index 0000000..c395e9f --- /dev/null +++ b/about/src/main/res-public/values/styles.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <style name="Kau.About" parent="Kau.Translucent.SlideTop"/> + +</resources>
\ No newline at end of file diff --git a/core-ui/src/main/res/values/colors.xml b/about/src/main/res/values/colors.xml index 273d6f1..fcfc537 100644 --- a/core-ui/src/main/res/values/colors.xml +++ b/about/src/main/res/values/colors.xml @@ -2,5 +2,4 @@ <resources> <color name="kau_about_page_indicator_dark">#80ffffff</color> <color name="kau_about_page_indicator_dark_selected">#fff</color> - <color name="kau_shadow_overlay">#80000000</color> </resources> diff --git a/about/src/main/res/values/dimens.xml b/about/src/main/res/values/dimens.xml new file mode 100644 index 0000000..2b5250a --- /dev/null +++ b/about/src/main/res/values/dimens.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <dimen name="kau_about_header_height">224dp</dimen> +</resources>
\ No newline at end of file diff --git a/about/src/main/res/values/styles.xml b/about/src/main/res/values/styles.xml deleted file mode 100644 index f878950..0000000 --- a/about/src/main/res/values/styles.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - - <style name="Kau.Translucent.About" parent="Kau.Translucent.SlideTop"/> - -</resources>
\ No newline at end of file diff --git a/adapter/build.gradle b/adapter/build.gradle index bdeee97..772adca 100644 --- a/adapter/build.gradle +++ b/adapter/build.gradle @@ -1,8 +1,6 @@ -apply from: '../android-lib.gradle' +ext.kauSubModuleMinSdk = project.CORE_MIN_SDK -android { - resourcePrefix "kau_" -} +apply from: '../android-lib.gradle' dependencies { diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt b/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt index 1349a35..b1c281a 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt +++ b/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt @@ -1,6 +1,8 @@ package ca.allanwang.kau.adapters import android.content.res.ColorStateList +import android.os.Build +import android.support.annotation.RequiresApi import android.view.View import android.widget.ImageView import android.widget.TextView @@ -174,6 +176,7 @@ class ThemableIItemDelegate : ThemableIItem, ThemableIItemColors by ThemableIIte views.forEach { it?.setBackgroundColor(color) } } + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun bindBackgroundRipple(vararg views: View?) { val background = backgroundColor ?: return val foreground = accentColor ?: textColor ?: backgroundColor ?: return //default to normal background @@ -181,6 +184,7 @@ class ThemableIItemDelegate : ThemableIItem, ThemableIItemColors by ThemableIIte views.forEach { it?.background = ripple } } + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun bindIconColor(vararg views: ImageView?) { val color = accentColor ?: textColor ?: return views.forEach { it?.drawable?.setTintList(ColorStateList.valueOf(color)) } diff --git a/adapter/src/main/res-public/values/public.xml b/adapter/src/main/res-public/values/public.xml new file mode 100644 index 0000000..cf14680 --- /dev/null +++ b/adapter/src/main/res-public/values/public.xml @@ -0,0 +1,4 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='dummy' type='id' /> +</resources>
\ No newline at end of file diff --git a/android-lib.gradle b/android-lib.gradle index 7eb6a79..78526e5 100644 --- a/android-lib.gradle +++ b/android-lib.gradle @@ -14,8 +14,18 @@ android { compileSdkVersion Integer.parseInt(project.TARGET_SDK) buildToolsVersion project.BUILD_TOOLS + def kauMinSdk = project.MIN_SDK + if (project.hasProperty('kauSubModuleMinSdk')) + kauMinSdk = kauSubModuleMinSdk + + def kauResourcePrefix = "kau_" + if (project.hasProperty('kauSubModuleResourcePrefix')) + kauResourcePrefix = kauSubModuleResourcePrefix + + resourcePrefix kauResourcePrefix + defaultConfig { - minSdkVersion Integer.parseInt(project.MIN_SDK) + minSdkVersion Integer.parseInt(kauMinSdk) targetSdkVersion Integer.parseInt(project.TARGET_SDK) consumerProguardFiles 'progress-proguard.txt' testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -42,5 +52,6 @@ android { sourceSets { main.java.srcDirs += 'src/main/kotlin' test.java.srcDirs += 'src/test/kotlin' + main.res.srcDirs += 'src/main/res-public' } }
\ No newline at end of file diff --git a/artifacts.gradle b/artifacts.gradle index 6db3cfb..12dd3fa 100644 --- a/artifacts.gradle +++ b/artifacts.gradle @@ -1,3 +1,5 @@ +import groovy.xml.MarkupBuilder + apply plugin: 'com.github.dcendents.android-maven' // build a jar with source files @@ -22,4 +24,76 @@ task javadocJar(type: Jar, dependsOn: javadoc) { artifacts { archives sourcesJar archives javadocJar +} + +// Task to generate our public.xml file +// See https://developer.android.com/studio/projects/android-library.html#PrivateResources +// We assume resources within res-public are public +task generatepublicxml { + + def resDir = project.projectDir.absolutePath + "/src/main/res-public" + + def publicFolder = file(resDir + "/values") + if (!publicFolder.exists()) publicFolder.mkdirs() + + // Include the desired res types + // Note: we don't need the qualified resource directories, + // since those resources will already be defined in the unqualified directories + // however, there are special cases like transition-v21 that is only available on lollipop and up + def tree = fileTree(dir: resDir, + includes: ['**/anim/*.xml', + '**/color/*.xml', + '**/drawable/*.xml', + '**/layout/*.xml', + '**/transition-v21/*.xml', + '**/values/*.xml' + ], + exclude: '**/public.xml' + ); + + // Create new public.xml with writer + new File(resDir + "/values/public.xml").withWriter { writer -> + // Create MarkupBuilder with 4 space indent + def destXml = new MarkupBuilder(new IndentPrinter(writer, " ", true)); + def destXmlMkp = destXml.getMkp(); + + // GIST NOTE: our project needed the ResourceName suppression, but its not needed in general + destXml.resources( + 'xmlns:tools': 'http://schemas.android.com/tools', + 'tools:ignore': 'ResourceName' + ) { + // Leave file comment + destXmlMkp.yield "\r\n" + destXmlMkp.comment("AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task") + + if (tree.isEmpty()) + "public"("name": "dummy", "type": "id") + else + tree.each { resFile -> + + // use the directory name to get the type + def type = resFile.getParentFile().getName() + + if (type == "values") { + // Resource files under values. Parse the file, and pull out the resource definitions + def parsePublicResources = new XmlParser().parse(resFile) + parsePublicResources.children().each { + + // Type is usually the element, but sometimes a type attribute is present + // example: <item name="line_spacing_multiplier" format="float" type="dimen">1.4</item> + type = it.name() + if (it.@type) { + type = it.@type + } + + // it.@name is value in name= + "public"("name": it.@name, "type": type) + } + } else { + // Drawable, layout, etc files + "public"("name": resFile.getName().tokenize('.')[0], "type": type.tokenize('-')[0]) + } + } + } + } }
\ No newline at end of file diff --git a/build.gradle b/build.gradle index b81cf56..bd440a8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +import groovy.xml.MarkupBuilder buildscript { repositories { @@ -18,7 +19,7 @@ task clean(type: Delete) { delete rootProject.buildDir } -task generateChangelogMd() { +task generateChangelogMd { def parsedProjectXml = (new XmlParser()).parse("$project.rootDir/sample/src/main/res/xml/kau_changelog.xml") def sw = new StringWriter() sw.append("# Changelog\n") diff --git a/colorpicker/build.gradle b/colorpicker/build.gradle index c522e9f..f6e412a 100644 --- a/colorpicker/build.gradle +++ b/colorpicker/build.gradle @@ -1,8 +1,8 @@ -apply from: '../android-lib.gradle' +ext.kauSubModuleResourcePrefix = "kau_color_" -android { - resourcePrefix "kau_color_" -} +ext.kauSubModuleMinSdk = project.CORE_MIN_SDK + +apply from: '../android-lib.gradle' dependencies { compile project(':core') diff --git a/colorpicker/src/main/res-public/values/public.xml b/colorpicker/src/main/res-public/values/public.xml new file mode 100644 index 0000000..cf14680 --- /dev/null +++ b/colorpicker/src/main/res-public/values/public.xml @@ -0,0 +1,4 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='dummy' type='id' /> +</resources>
\ No newline at end of file diff --git a/colorpicker/src/main/res/values/strings.xml b/colorpicker/src/main/res/values/strings.xml new file mode 100644 index 0000000..5a6f89b --- /dev/null +++ b/colorpicker/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="ResourceName"> + <string name="kau_md_color_palette">Color Palette</string> + <string name="kau_md_custom">Custom</string> + <string name="kau_md_presets">Presets</string> +</resources> diff --git a/core-ui/build.gradle b/core-ui/build.gradle index 2562de3..c4dcc72 100644 --- a/core-ui/build.gradle +++ b/core-ui/build.gradle @@ -1,8 +1,6 @@ -apply from: '../android-lib.gradle' +ext.kauSubModuleMinSdk = project.CORE_MIN_SDK -android { - resourcePrefix "kau_" -} +apply from: '../android-lib.gradle' dependencies { 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 1dcf14b..20a81e4 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 @@ -1,6 +1,8 @@ package ca.allanwang.kau.ui.activities +import android.os.Build import android.os.Bundle +import android.support.annotation.RequiresApi import android.support.design.widget.AppBarLayout import android.support.design.widget.CoordinatorLayout import android.support.design.widget.FloatingActionButton @@ -23,7 +25,8 @@ import ca.allanwang.kau.utils.bindView * * The exit animation is set to slide out, but the entrance must be defined yourself */ -abstract class ElasticRecyclerActivity() : AppCompatActivity() { +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) +abstract class ElasticRecyclerActivity : AppCompatActivity() { val appBar: AppBarLayout by bindView(R.id.kau_appbar) val toolbar: Toolbar by bindView(R.id.kau_toolbar) @@ -68,14 +71,5 @@ abstract class ElasticRecyclerActivity() : AppCompatActivity() { draggableFrame.setOnClickListener { listener() } } - fun hideFabOnUpwardsScroll() { - recycler.addOnScrollListener(object :RecyclerView.OnScrollListener(){ - override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) { - if (dy > 0 && fab.isShown) fab.hide() - else if (dy < 0 && !fab.isShown) fab.show() - } - }) - } - } diff --git a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/MeasuredImageView.kt b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/MeasuredImageView.kt index 2627d13..ebb6397 100644 --- a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/MeasuredImageView.kt +++ b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/views/MeasuredImageView.kt @@ -1,6 +1,7 @@ package ca.allanwang.kau.ui.views import android.content.Context +import android.support.v7.widget.AppCompatImageView import android.util.AttributeSet import android.widget.ImageView @@ -8,8 +9,8 @@ import android.widget.ImageView * Created by Allan Wang on 2017-07-14. */ class MeasuredImageView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 -) : ImageView(context, attrs, defStyleAttr, defStyleRes), MeasureSpecContract by MeasureSpecDelegate() { + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : AppCompatImageView(context, attrs, defStyleAttr), MeasureSpecContract by MeasureSpecDelegate() { init { initAttrs(context, attrs) diff --git a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/widgets/ElasticDragDismissFrameLayout.kt b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/widgets/ElasticDragDismissFrameLayout.kt index c208210..995ccab 100644 --- a/core-ui/src/main/kotlin/ca/allanwang/kau/ui/widgets/ElasticDragDismissFrameLayout.kt +++ b/core-ui/src/main/kotlin/ca/allanwang/kau/ui/widgets/ElasticDragDismissFrameLayout.kt @@ -19,6 +19,8 @@ package ca.allanwang.kau.ui.widgets import android.app.Activity import android.content.Context import android.graphics.Color +import android.os.Build +import android.support.annotation.RequiresApi import android.util.AttributeSet import android.view.View import android.widget.FrameLayout @@ -30,6 +32,7 @@ import ca.allanwang.kau.utils.* * Applies an elasticity factor to reduce movement as you approach the given dismiss distance. * Optionally also scales down content during drag. */ +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) class ElasticDragDismissFrameLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) { diff --git a/core-ui/src/main/res/values/styles.xml b/core-ui/src/main/res-public/values-v21/styles.xml index dfbb6d3..fe2c9bf 100644 --- a/core-ui/src/main/res/values/styles.xml +++ b/core-ui/src/main/res-public/values-v21/styles.xml @@ -1,7 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="no"?> <resources> - <style name="Kau" parent="Theme.AppCompat.NoActionBar"/> - <style name="Kau.Translucent"> <item name="android:windowBackground">@color/kau_shadow_overlay</item> <item name="android:colorBackgroundCacheHint">@null</item> @@ -12,10 +10,6 @@ <item name="android:windowDrawsSystemBarBackgrounds">true</item> </style> - <style name="Kau.Translucent.NoAnimation"> - <item name="android:windowAnimationStyle">@null</item> - </style> - <style name="Kau.Translucent.SlideBottom"> <item name="android:windowEnterTransition">@transition/kau_enter_slide_bottom</item> <item name="android:windowReturnTransition">@transition/kau_exit_slide_bottom</item> diff --git a/core-ui/src/main/res-public/values/colors.xml b/core-ui/src/main/res-public/values/colors.xml new file mode 100644 index 0000000..82bf172 --- /dev/null +++ b/core-ui/src/main/res-public/values/colors.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<resources> + <color name="kau_shadow_overlay">#80000000</color> +</resources> diff --git a/core-ui/src/main/res-public/values/public.xml b/core-ui/src/main/res-public/values/public.xml new file mode 100644 index 0000000..59e34a6 --- /dev/null +++ b/core-ui/src/main/res-public/values/public.xml @@ -0,0 +1,8 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='kau_shadow_overlay' type='color' /> + <public name='Kau.Translucent' type='style' /> + <public name='Kau.Translucent.NoAnimation' type='style' /> + <public name='Kau.Translucent.SlideBottom' type='style' /> + <public name='Kau.Translucent.SlideTop' type='style' /> +</resources>
\ No newline at end of file diff --git a/core-ui/src/main/res-public/values/styles.xml b/core-ui/src/main/res-public/values/styles.xml new file mode 100644 index 0000000..583ede7 --- /dev/null +++ b/core-ui/src/main/res-public/values/styles.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<resources> + <style name="Kau.Translucent"> + <item name="android:windowBackground">@color/kau_shadow_overlay</item> + <item name="android:colorBackgroundCacheHint">@null</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:windowIsFloating">false</item> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowNoTitle">true</item> + </style> + + <style name="Kau.Translucent.NoAnimation"> + <item name="android:windowAnimationStyle">@null</item> + </style> + + <style name="Kau.Translucent.SlideBottom" /> + + <style name="Kau.Translucent.SlideTop" /> +</resources> diff --git a/core-ui/src/main/res/values/strings.xml b/core-ui/src/main/res/values/strings.xml deleted file mode 100644 index 80e6233..0000000 --- a/core-ui/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <string name="kau_blurrable_imageview">Blurrable ImageView</string> -</resources>
\ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle index 258f85a..af36d80 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,8 +1,6 @@ -apply from: '../android-lib.gradle' +ext.kauSubModuleMinSdk = project.CORE_MIN_SDK -android { - resourcePrefix "kau_" -} +apply from: '../android-lib.gradle' dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) 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 7f4399d..1474c1a 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/SwipeBackLayout.kt @@ -1,5 +1,6 @@ package ca.allanwang.kau.swipe +import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.graphics.Canvas @@ -37,6 +38,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu } var activity: Activity? = null + @SuppressLint("NewApi") set(value) { field = value if (value != null) { @@ -81,6 +83,7 @@ class SwipeBackLayout @JvmOverloads constructor(context: Context, attrs: Attribu val chromeFadeListener: SwipeListener by lazy { object : SwipeListener { + @SuppressLint("NewApi") override fun onScroll(percent: Float, px: Int, edgeFlag: Int) { if (!transitionSystemBars) return activity?.apply { 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 30c8edd..b92b222 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/ui/SimpleRippleDrawable.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/ui/SimpleRippleDrawable.kt @@ -3,7 +3,9 @@ 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 ca.allanwang.kau.utils.adjustAlpha /** @@ -11,6 +13,7 @@ import ca.allanwang.kau.utils.adjustAlpha * * Tries to mimic a standard ripple, given the foreground and background colors */ +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) fun createSimpleRippleDrawable(@ColorInt foregroundColor: Int, @ColorInt backgroundColor: Int): RippleDrawable { val states = ColorStateList(arrayOf(intArrayOf()), intArrayOf(foregroundColor)) val content = ColorDrawable(backgroundColor) 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 cd6e089..54aeaff 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ActivityUtils.kt @@ -39,13 +39,17 @@ fun Activity.finishSlideOut() { } inline var Activity.navigationBarColor: Int + @SuppressLint("NewApi") get() = if (buildIsLollipopAndUp) window.navigationBarColor else Color.BLACK + @SuppressLint("NewApi") set(value) { if (buildIsLollipopAndUp) window.navigationBarColor = value } inline var Activity.statusBarColor: Int + @SuppressLint("NewApi") get() = if (buildIsLollipopAndUp) window.statusBarColor else Color.BLACK + @SuppressLint("NewApi") set(value) { if (buildIsLollipopAndUp) window.statusBarColor = value } 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 3db8b9c..2767f04 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/AnimHolder.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/AnimHolder.kt @@ -1,5 +1,7 @@ package ca.allanwang.kau.utils +import android.os.Build +import android.support.annotation.RequiresApi import ca.allanwang.kau.kotlin.lazyInterpolator /** @@ -9,6 +11,7 @@ import ca.allanwang.kau.kotlin.lazyInterpolator */ 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) 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 bbde077..ed4b7bd 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/AnimUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/AnimUtils.kt @@ -2,12 +2,12 @@ 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.animation.Animation import android.view.animation.AnimationUtils -import android.view.animation.DecelerateInterpolator import android.widget.TextView /** @@ -15,33 +15,8 @@ import android.widget.TextView * * Animation extension functions for Views */ -@KauUtils fun View.rootCircularReveal(x: Int = 0, y: Int = 0, duration: Long = 500L, onStart: (() -> Unit)? = null, onFinish: (() -> Unit)? = null) { - this.addOnLayoutChangeListener(object : View.OnLayoutChangeListener { - override @KauUtils fun onLayoutChange(v: View, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, - oldRight: Int, oldBottom: Int) { - v.removeOnLayoutChangeListener(this) - var x2 = x - var y2 = y - if (x2 > right) x2 = 0 - if (y2 > bottom) y2 = 0 - val radius = Math.hypot(Math.max(x2, right - x2).toDouble(), Math.max(y2, bottom - y2).toDouble()).toInt() - val reveal = ViewAnimationUtils.createCircularReveal(v, x2, y2, 0f, radius.toFloat()) - reveal.interpolator = DecelerateInterpolator(1f) - reveal.duration = duration - reveal.addListener(object : AnimatorListenerAdapter() { - override @KauUtils fun onAnimationStart(animation: Animator?) { - visible() - onStart?.invoke() - } - - override @KauUtils fun onAnimationEnd(animation: Animator?) = onFinish?.invoke() ?: Unit - override @KauUtils fun onAnimationCancel(animation: Animator?) = onFinish?.invoke() ?: Unit - }) - reveal.start() - } - }) -} +@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) { if (!isAttachedToWindow) { onStart?.invoke() @@ -49,10 +24,11 @@ import android.widget.TextView onFinish?.invoke() return } - var r = radius - if (r < 0.0f) { - r = Math.max(Math.hypot(x.toDouble(), y.toDouble()), Math.hypot((width - x.toDouble()), (height - y.toDouble()))).toFloat() - } + 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() + val anim = ViewAnimationUtils.createCircularReveal(this, x, y, 0f, r).setDuration(duration) anim.startDelay = offset anim.addListener(object : AnimatorListenerAdapter() { @@ -67,6 +43,7 @@ import android.widget.TextView anim.start() } +@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) { if (!isAttachedToWindow) { onStart?.invoke() @@ -74,10 +51,11 @@ import android.widget.TextView onFinish?.invoke() return } - var r = radius - if (r < 0.0f) { - r = Math.max(Math.hypot(x.toDouble(), y.toDouble()), Math.hypot((width - x.toDouble()), (height - y.toDouble()))).toFloat() - } + 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() + val anim = ViewAnimationUtils.createCircularReveal(this, x, y, r, 0f).setDuration(duration) anim.startDelay = offset anim.addListener(object : AnimatorListenerAdapter() { @@ -100,20 +78,18 @@ import android.widget.TextView onFinish?.invoke() return } - if (isAttachedToWindow) { - val anim = AnimationUtils.loadAnimation(context, android.R.anim.fade_in) - anim.startOffset = offset - anim.duration = duration - anim.setAnimationListener(object : Animation.AnimationListener { - override @KauUtils fun onAnimationRepeat(animation: Animation?) {} - override @KauUtils fun onAnimationEnd(animation: Animation?) = onFinish?.invoke() ?: Unit - override @KauUtils fun onAnimationStart(animation: Animation?) { - visible() - onStart?.invoke() - } - }) - startAnimation(anim) - } + val anim = AnimationUtils.loadAnimation(context, android.R.anim.fade_in) + anim.startOffset = offset + anim.duration = duration + anim.setAnimationListener(object : Animation.AnimationListener { + override @KauUtils fun onAnimationRepeat(animation: Animation?) {} + override @KauUtils fun onAnimationEnd(animation: Animation?) = onFinish?.invoke() ?: Unit + override @KauUtils fun onAnimationStart(animation: Animation?) { + visible() + onStart?.invoke() + } + }) + startAnimation(anim) } @KauUtils fun View.fadeOut(offset: Long = 0L, duration: Long = 200L, onStart: (() -> Unit)? = null, onFinish: (() -> Unit)? = null) { 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 9fcc7e7..f267a60 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/Const.kt @@ -8,4 +8,7 @@ const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android" const val KAU_LEFT = 1 const val KAU_TOP = 2 const val KAU_RIGHT = 4 -const val KAU_BOTTOM = 8
\ No newline at end of file +const val KAU_BOTTOM = 8 +const val KAU_HORIZONTAL = KAU_LEFT and KAU_RIGHT +const val KAU_VERTICAL = KAU_TOP and KAU_BOTTOM +const val KAU_ALL = KAU_HORIZONTAL and KAU_VERTICAL
\ No newline at end of file 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 a8e0715..bf30a91 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt @@ -1,5 +1,6 @@ package ca.allanwang.kau.utils +import android.annotation.SuppressLint import android.app.Activity import android.app.ActivityOptions import android.content.ClipData @@ -25,6 +26,7 @@ import com.afollestad.materialdialogs.MaterialDialog /** * Created by Allan Wang on 2017-06-03. */ +@SuppressLint("NewApi") fun Context.startActivity( clazz: Class<out Activity>, clearStack: Boolean = false, @@ -34,7 +36,9 @@ fun Context.startActivity( val intent = (Intent(this, clazz)) if (clearStack) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) intent.intentBuilder() - val fullBundle = if (transition && this is Activity) ActivityOptions.makeSceneTransitionAnimation(this).toBundle() else Bundle() + val fullBundle = if (transition && this is Activity && buildIsLollipopAndUp) + ActivityOptions.makeSceneTransitionAnimation(this).toBundle() + else Bundle() if (transition && this !is Activity) KL.d("Cannot make scene transition when context is not an instance of an Activity") if (bundle != null) fullBundle.putAll(bundle) ContextCompat.startActivity(this, intent, if (fullBundle.isEmpty) null else fullBundle) @@ -97,7 +101,11 @@ inline fun Context.drawable(@DrawableRes id: Int): Drawable = ContextCompat.getD inline fun Context.drawable(@DrawableRes id: Int, fallback: Drawable?): Drawable? = if (id > 0) 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) -inline fun Context.plural(@PluralsRes id: Int, quantity: Number) = resources.getQuantityString(id, quantity.toInt()) +/** + * 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()) //Attr retrievers fun Context.resolveColor(@AttrRes attr: Int, fallback: Int = 0): Int { 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 03a1605..4c71945 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/IIconUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/IIconUtils.kt @@ -13,8 +13,7 @@ import com.mikepenz.iconics.typeface.IIcon */ @KauUtils 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).sizeDp(sizeDp) - icon.setTintList(state) + val icon = IconicsDrawable(c).icon(this).sizeDp(sizeDp).color(state) icon.builder() return icon }
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt index 89d64e5..36bcc93 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/PackageUtils.kt @@ -30,12 +30,14 @@ import android.os.Build } } -inline val buildIsLollipopAndUp: Boolean - get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP - inline val buildIsMarshmallowAndUp: Boolean + get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M +inline val buildIsLollipopAndUp: Boolean + @SuppressWarnings("NewApi") + get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP + inline val buildIsNougatAndUp: Boolean get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N 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 9e668d0..fa062f7 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/TransitionUtils.kt @@ -1,11 +1,19 @@ package ca.allanwang.kau.utils -import android.support.transition.Transition -import android.support.transition.TransitionSet +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.support.transition.Transition as SupportTransition +import android.transition.Transition +import android.view.ViewGroup /** * Created by Allan Wang on 2017-06-24. */ +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) class TransitionEndListener(val onEnd: (transition: Transition) -> Unit) : Transition.TransitionListener { override fun onTransitionEnd(transition: Transition) = onEnd(transition) override fun onTransitionResume(transition: Transition) {} @@ -14,6 +22,35 @@ class TransitionEndListener(val onEnd: (transition: Transition) -> Unit) : Trans override fun onTransitionStart(transition: Transition) {} } -@KauUtils fun TransitionSet.addEndListener(onEnd: (transition: Transition) -> Unit) { +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) +@KauUtils fun Transition.addEndListener(onEnd: (transition: Transition) -> Unit) { addListener(TransitionEndListener(onEnd)) +} + +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) +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) {} + override fun onTransitionCancel(transition: SupportTransition) {} + override fun onTransitionStart(transition: SupportTransition) {} +} + +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) +@KauUtils fun SupportTransition.addEndListener(onEnd: (transition: SupportTransition) -> Unit) { + addListener(SupportTransitionEndListener(onEnd)) +} + +@KauUtils fun ViewGroup.transitionAuto(builder: AutoTransition.() -> Unit = {}) { + if (!buildIsLollipopAndUp) return + val transition = AutoTransition() + transition.builder() + TransitionManager.beginDelayedTransition(this, transition) +} + +@KauUtils fun ViewGroup.transitionDelayed(@TransitionRes id: Int, builder: android.support.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/ViewUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt index 59ae204..ead2cb7 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt @@ -5,10 +5,8 @@ package ca.allanwang.kau.utils import android.animation.ValueAnimator import android.content.Context import android.graphics.Color -import android.support.annotation.ColorInt -import android.support.annotation.ColorRes -import android.support.annotation.StringRes -import android.support.annotation.TransitionRes +import android.os.Build +import android.support.annotation.* import android.support.design.widget.FloatingActionButton import android.support.design.widget.Snackbar import android.support.design.widget.TextInputEditText @@ -93,30 +91,98 @@ fun FloatingActionButton.hideIf(hide: Boolean) = if (hide) hide() else show() /** * Set left margin to a value in px */ -@KauUtils fun View.updateLeftMargin(margin: Int) = updateMargins(margin, KAU_LEFT) +@KauUtils fun View.setMarginLeft(margin: Int) = setMargins(margin, KAU_LEFT) /** * Set top margin to a value in px */ -@KauUtils fun View.updateTopMargin(margin: Int) = updateMargins(margin, KAU_TOP) +@KauUtils fun View.setMarginTop(margin: Int) = setMargins(margin, KAU_TOP) /** * Set right margin to a value in px */ -@KauUtils fun View.updateRightMargin(margin: Int) = updateMargins(margin, KAU_RIGHT) +@KauUtils fun View.setMarginRight(margin: Int) = setMargins(margin, KAU_RIGHT) /** * Set bottom margin to a value in px */ -@KauUtils fun View.updateBottomMargin(margin: Int) = updateMargins(margin, KAU_BOTTOM) +@KauUtils fun View.setMarginBottom(margin: Int) = setMargins(margin, KAU_BOTTOM) -@KauUtils private fun View.updateMargins(margin: Int, flag: Int) { - val p = (layoutParams as? ViewGroup.MarginLayoutParams) ?: return +/** + * Set left and right margins to a value in px + */ +@KauUtils fun View.setMarginHorizontal(margin: Int) = setMargins(margin, KAU_HORIZONTAL) + +/** + * Set top and bottom margins to a value in px + */ +@KauUtils fun View.setMarginVertical(margin: Int) = setMargins(margin, KAU_VERTICAL) + +/** + * Set all margins to a value in px + */ +@KauUtils fun View.setMargin(margin: Int) = setMargins(margin, KAU_ALL) + +/** + * Base margin setter + * returns true if setting is successful, false otherwise + */ +@KauUtils private fun View.setMargins(margin: Int, flag: Int): Boolean { + val p = (layoutParams as? ViewGroup.MarginLayoutParams) ?: return false p.setMargins( - if (flag == KAU_LEFT) margin else p.leftMargin, - if (flag == KAU_TOP) margin else p.topMargin, - if (flag == KAU_RIGHT) margin else p.rightMargin, - if (flag == KAU_BOTTOM) 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 + ) + requestLayout() + return true +} + +/** + * Set left padding to a value in px + */ +@KauUtils fun View.setPaddingLeft(padding: Int) = setPadding(padding, KAU_LEFT) + +/** + * Set top padding to a value in px + */ +@KauUtils fun View.setPaddingTop(padding: Int) = setPadding(padding, KAU_TOP) + +/** + * Set right padding to a value in px + */ +@KauUtils fun View.setPaddingRight(padding: Int) = setPadding(padding, KAU_RIGHT) + +/** + * Set bottom padding to a value in px + */ +@KauUtils fun View.setPaddingBottom(padding: Int) = setPadding(padding, KAU_BOTTOM) + +/** + * Set left and right padding to a value in px + */ +@KauUtils fun View.setPaddingHorizontal(padding: Int) = setPadding(padding, KAU_HORIZONTAL) + +/** + * Set top and bottom padding to a value in px + */ +@KauUtils fun View.setPaddingVertical(padding: Int) = setPadding(padding, KAU_VERTICAL) + +/** + * Set all padding to a value in px + */ +@KauUtils fun View.setPadding(padding: Int) = setPadding(padding, KAU_ALL) + +/** + * Base padding setter + */ +@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 ) requestLayout() } @@ -131,18 +197,8 @@ fun FloatingActionButton.hideIf(hide: Boolean) = if (hide) hide() else show() (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) } -@KauUtils fun ViewGroup.transitionAuto(builder: AutoTransition.() -> Unit = {}) { - val transition = AutoTransition() - transition.builder() - TransitionManager.beginDelayedTransition(this, transition) -} - -@KauUtils fun ViewGroup.transitionDelayed(@TransitionRes id: Int, builder: Transition.() -> Unit = {}) { - val transition = TransitionInflater.from(context).inflateTransition(id) - transition.builder() - TransitionManager.beginDelayedTransition(this, transition) -} +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) @KauUtils fun View.setRippleBackground(@ColorInt foregroundColor: Int, @ColorInt backgroundColor: Int) { background = createSimpleRippleDrawable(foregroundColor, backgroundColor) } @@ -192,4 +248,22 @@ inline fun FloatingActionButton.transition(crossinline action: FloatingActionBut start() } } +} + +/** + * Attaches a listener to the recyclerview to hide the fab when it is scrolling downwards + * The fab will reappear when scrolling has stopped or if the user scrolls up + */ +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(); + } + + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + if (dy > 0 && isShown) hide() + else if (dy < 0 && isHidden) show() + } + }) }
\ No newline at end of file diff --git a/core/src/main/res/anim/kau_fade_in.xml b/core/src/main/res-public/anim/kau_fade_in.xml index 03312a2..03312a2 100644 --- a/core/src/main/res/anim/kau_fade_in.xml +++ b/core/src/main/res-public/anim/kau_fade_in.xml diff --git a/core/src/main/res/anim/kau_fade_out.xml b/core/src/main/res-public/anim/kau_fade_out.xml index 322befc..322befc 100644 --- a/core/src/main/res/anim/kau_fade_out.xml +++ b/core/src/main/res-public/anim/kau_fade_out.xml diff --git a/core/src/main/res/anim/kau_slide_in_bottom.xml b/core/src/main/res-public/anim/kau_slide_in_bottom.xml index a07cba4..a07cba4 100644 --- a/core/src/main/res/anim/kau_slide_in_bottom.xml +++ b/core/src/main/res-public/anim/kau_slide_in_bottom.xml diff --git a/core/src/main/res/anim/kau_slide_in_left.xml b/core/src/main/res-public/anim/kau_slide_in_left.xml index 828bdae..828bdae 100644 --- a/core/src/main/res/anim/kau_slide_in_left.xml +++ b/core/src/main/res-public/anim/kau_slide_in_left.xml diff --git a/core/src/main/res/anim/kau_slide_in_right.xml b/core/src/main/res-public/anim/kau_slide_in_right.xml index 0f9fbce..0f9fbce 100644 --- a/core/src/main/res/anim/kau_slide_in_right.xml +++ b/core/src/main/res-public/anim/kau_slide_in_right.xml diff --git a/core/src/main/res/anim/kau_slide_in_top.xml b/core/src/main/res-public/anim/kau_slide_in_top.xml index 8caee9b..8caee9b 100644 --- a/core/src/main/res/anim/kau_slide_in_top.xml +++ b/core/src/main/res-public/anim/kau_slide_in_top.xml diff --git a/core/src/main/res/anim/kau_slide_out_bottom.xml b/core/src/main/res-public/anim/kau_slide_out_bottom.xml index 44e7e21..44e7e21 100644 --- a/core/src/main/res/anim/kau_slide_out_bottom.xml +++ b/core/src/main/res-public/anim/kau_slide_out_bottom.xml diff --git a/core/src/main/res/anim/kau_slide_out_left.xml b/core/src/main/res-public/anim/kau_slide_out_left.xml index 6fab33e..6fab33e 100644 --- a/core/src/main/res/anim/kau_slide_out_left.xml +++ b/core/src/main/res-public/anim/kau_slide_out_left.xml diff --git a/core/src/main/res/anim/kau_slide_out_right.xml b/core/src/main/res-public/anim/kau_slide_out_right.xml index 9322741..9322741 100644 --- a/core/src/main/res/anim/kau_slide_out_right.xml +++ b/core/src/main/res-public/anim/kau_slide_out_right.xml diff --git a/core/src/main/res/anim/kau_slide_out_right_top.xml b/core/src/main/res-public/anim/kau_slide_out_right_top.xml index 5b63474..5b63474 100644 --- a/core/src/main/res/anim/kau_slide_out_right_top.xml +++ b/core/src/main/res-public/anim/kau_slide_out_right_top.xml diff --git a/core/src/main/res/anim/kau_slide_out_top.xml b/core/src/main/res-public/anim/kau_slide_out_top.xml index 9f8e14c..9f8e14c 100644 --- a/core/src/main/res/anim/kau_slide_out_top.xml +++ b/core/src/main/res-public/anim/kau_slide_out_top.xml diff --git a/core-ui/src/main/res/drawable/kau_selectable_white.xml b/core/src/main/res-public/drawable-v21/kau_selectable_white.xml index 942f149..942f149 100644 --- a/core-ui/src/main/res/drawable/kau_selectable_white.xml +++ b/core/src/main/res-public/drawable-v21/kau_selectable_white.xml diff --git a/core/src/main/res-public/drawable/kau_selectable_white.xml b/core/src/main/res-public/drawable/kau_selectable_white.xml new file mode 100644 index 0000000..5738478 --- /dev/null +++ b/core/src/main/res-public/drawable/kau_selectable_white.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <selector> + <item android:state_activated="true"> + <color android:color="#40ffffff" /> + </item> + <item> + <color android:color="@android:color/transparent" /> + </item> + </selector> + </item> +</layer-list>
\ No newline at end of file diff --git a/core/src/main/res/drawable/kau_transparent.xml b/core/src/main/res-public/drawable/kau_transparent.xml index 399a46b..399a46b 100644 --- a/core/src/main/res/drawable/kau_transparent.xml +++ b/core/src/main/res-public/drawable/kau_transparent.xml diff --git a/core/src/main/res/transition/kau_enter_slide_bottom.xml b/core/src/main/res-public/transition-v21/kau_enter_slide_bottom.xml index 575e189..575e189 100644 --- a/core/src/main/res/transition/kau_enter_slide_bottom.xml +++ b/core/src/main/res-public/transition-v21/kau_enter_slide_bottom.xml diff --git a/core/src/main/res/transition/kau_enter_slide_top.xml b/core/src/main/res-public/transition-v21/kau_enter_slide_top.xml index 8cf613b..8cf613b 100644 --- a/core/src/main/res/transition/kau_enter_slide_top.xml +++ b/core/src/main/res-public/transition-v21/kau_enter_slide_top.xml diff --git a/core/src/main/res/transition/kau_exit_slide_bottom.xml b/core/src/main/res-public/transition-v21/kau_exit_slide_bottom.xml index e0967ec..e0967ec 100644 --- a/core/src/main/res/transition/kau_exit_slide_bottom.xml +++ b/core/src/main/res-public/transition-v21/kau_exit_slide_bottom.xml diff --git a/core/src/main/res/transition/kau_exit_slide_top.xml b/core/src/main/res-public/transition-v21/kau_exit_slide_top.xml index a9849c0..a9849c0 100644 --- a/core/src/main/res/transition/kau_exit_slide_top.xml +++ b/core/src/main/res-public/transition-v21/kau_exit_slide_top.xml diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res-public/values/dimens.xml index b7c237a..efc7598 100644 --- a/core/src/main/res/values/dimens.xml +++ b/core/src/main/res-public/values/dimens.xml @@ -20,14 +20,13 @@ <dimen name="kau_spacing_large">32dp</dimen> <dimen name="kau_spacing_xlarge">48dp</dimen> <dimen name="kau_spacing_huge">64dp</dimen> + <dimen name="kau_padding_small">8dp</dimen> <dimen name="kau_padding_normal">16dp</dimen> <dimen name="kau_padding_large">24dp</dimen> <dimen name="kau_fab_size">56dp</dimen> <dimen name="kau_fab_radius">28dp</dimen> <dimen name="kau_display_4_text_size">112sp</dimen> - <dimen name="kau_about_header_height">224dp</dimen> - <!-- avatar should be a 40dp asset in a 48dp touch target & optically aligned with standard padding --> <dimen name="kau_avatar_size">40dp</dimen> <dimen name="kau_avatar_bounds">48dp</dimen> diff --git a/core/src/main/res-public/values/public.xml b/core/src/main/res-public/values/public.xml new file mode 100644 index 0000000..7057f1f --- /dev/null +++ b/core/src/main/res-public/values/public.xml @@ -0,0 +1,111 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='kau_fade_in' type='anim' /> + <public name='kau_fade_out' type='anim' /> + <public name='kau_slide_in_bottom' type='anim' /> + <public name='kau_slide_in_left' type='anim' /> + <public name='kau_slide_in_right' type='anim' /> + <public name='kau_slide_in_top' type='anim' /> + <public name='kau_slide_out_bottom' type='anim' /> + <public name='kau_slide_out_left' type='anim' /> + <public name='kau_slide_out_right' type='anim' /> + <public name='kau_slide_out_right_top' type='anim' /> + <public name='kau_slide_out_top' type='anim' /> + <public name='kau_selectable_white' type='drawable' /> + <public name='kau_transparent' type='drawable' /> + <public name='kau_enter_slide_bottom' type='transition' /> + <public name='kau_enter_slide_top' type='transition' /> + <public name='kau_exit_slide_bottom' type='transition' /> + <public name='kau_exit_slide_top' type='transition' /> + <public name='kau_activity_horizontal_margin' type='dimen' /> + <public name='kau_activity_vertical_margin' type='dimen' /> + <public name='kau_dialog_margin' type='dimen' /> + <public name='kau_dialog_margin_bottom' type='dimen' /> + <public name='kau_fab_margin' type='dimen' /> + <public name='kau_appbar_padding_top' type='dimen' /> + <public name='kau_splash_logo' type='dimen' /> + <public name='kau_progress_bar_height' type='dimen' /> + <public name='kau_account_image_size' type='dimen' /> + <public name='kau_status_bar_height' type='dimen' /> + <public name='kau_drag_dismiss_distance' type='dimen' /> + <public name='kau_drag_dismiss_distance_large' type='dimen' /> + <public name='kau_spacing_normal' type='dimen' /> + <public name='kau_spacing_micro' type='dimen' /> + <public name='kau_spacing_large' type='dimen' /> + <public name='kau_spacing_xlarge' type='dimen' /> + <public name='kau_spacing_huge' type='dimen' /> + <public name='kau_padding_small' type='dimen' /> + <public name='kau_padding_normal' type='dimen' /> + <public name='kau_padding_large' type='dimen' /> + <public name='kau_fab_size' type='dimen' /> + <public name='kau_fab_radius' type='dimen' /> + <public name='kau_display_4_text_size' type='dimen' /> + <public name='kau_avatar_size' type='dimen' /> + <public name='kau_avatar_bounds' type='dimen' /> + <public name='kau_avatar_padding' type='dimen' /> + <public name='kau_avatar_margin' type='dimen' /> + <public name='kau_avatar_ripple_radius' type='dimen' /> + <public name='kau_about_app' type='string' /> + <public name='kau_about_x' type='string' /> + <public name='kau_add_account' type='string' /> + <public name='kau_amoled' type='string' /> + <public name='kau_back' type='string' /> + <public name='kau_cancel' type='string' /> + <public name='kau_changelog' type='string' /> + <public name='kau_close' type='string' /> + <public name='kau_contact_us' type='string' /> + <public name='kau_copy' type='string' /> + <public name='kau_custom' type='string' /> + <public name='kau_dark' type='string' /> + <public name='kau_default' type='string' /> + <public name='kau_do_not_show_again' type='string' /> + <public name='kau_done' type='string' /> + <public name='kau_error' type='string' /> + <public name='kau_exit' type='string' /> + <public name='kau_exit_confirmation' type='string' /> + <public name='kau_exit_confirmation_x' type='string' /> + <public name='kau_glass' type='string' /> + <public name='kau_got_it' type='string' /> + <public name='kau_great' type='string' /> + <public name='kau_hide' type='string' /> + <public name='kau_light' type='string' /> + <public name='kau_login' type='string' /> + <public name='kau_logout' type='string' /> + <public name='kau_logout_confirm_as_x' type='string' /> + <public name='kau_lorem_ipsum' type='string' /> + <public name='kau_manage_account' type='string' /> + <public name='kau_maybe' type='string' /> + <public name='kau_menu' type='string' /> + <public name='kau_no' type='string' /> + <public name='kau_no_results_found' type='string' /> + <public name='kau_none' type='string' /> + <public name='kau_ok' type='string' /> + <public name='kau_play_store' type='string' /> + <public name='kau_rate' type='string' /> + <public name='kau_report_bug' type='string' /> + <public name='kau_search' type='string' /> + <public name='kau_send_feedback' type='string' /> + <public name='kau_send_via' type='string' /> + <public name='kau_settings' type='string' /> + <public name='kau_share' type='string' /> + <public name='kau_text_copied' type='string' /> + <public name='kau_thank_you' type='string' /> + <public name='kau_uh_oh' type='string' /> + <public name='kau_warning' type='string' /> + <public name='kau_x_days' type='plurals' /> + <public name='kau_x_hours' type='plurals' /> + <public name='kau_x_minutes' type='plurals' /> + <public name='kau_x_seconds' type='plurals' /> + <public name='kau_yes' type='string' /> + <public name='kau_permission_denied' type='string' /> + <public name='kau_0' type='string' /> + <public name='kau_bullet_point' type='string' /> + <public name='Kau' type='style' /> + <public name='KauFadeIn' type='style' /> + <public name='KauFadeInFadeOut' type='style' /> + <public name='KauSlideInRight' type='style' /> + <public name='KauSlideInBottom' type='style' /> + <public name='KauSlideInFadeOut' type='style' /> + <public name='KauSlideInSlideOutRight' type='style' /> + <public name='KauSlideInSlideOutBottom' type='style' /> +</resources>
\ No newline at end of file diff --git a/core/src/main/res/values/strings_commons.xml b/core/src/main/res-public/values/strings_commons.xml index 560a478..d236021 100644 --- a/core/src/main/res/values/strings_commons.xml +++ b/core/src/main/res-public/values/strings_commons.xml @@ -68,4 +68,7 @@ Most resources are verbatim and x represents a formatted item <item quantity="other">%d seconds</item> </plurals> <string name="kau_yes">Yes</string> + <string name="kau_permission_denied">Permission denied</string> + <string name="kau_0">0</string> + <string name="kau_bullet_point">•</string> </resources> diff --git a/core/src/main/res-public/values/styles.xml b/core/src/main/res-public/values/styles.xml new file mode 100644 index 0000000..f6f1929 --- /dev/null +++ b/core/src/main/res-public/values/styles.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<resources> + <style name="Kau" parent="Theme.AppCompat.NoActionBar"/> +</resources> diff --git a/core/src/main/res/values/styles_animations.xml b/core/src/main/res-public/values/styles_animations.xml index fc872bd..b98add9 100644 --- a/core/src/main/res/values/styles_animations.xml +++ b/core/src/main/res-public/values/styles_animations.xml @@ -18,7 +18,7 @@ <item name="android:windowExitAnimation">@anim/kau_fade_out</item> </style> - <style name="KauSlideIn" parent="@android:style/Animation.Activity"> + <style name="KauSlideInRight" parent="@android:style/Animation.Activity"> <item name="android:activityOpenEnterAnimation">@anim/kau_slide_in_right</item> <item name="android:activityCloseEnterAnimation">@anim/kau_slide_in_right</item> <item name="android:taskOpenEnterAnimation">@anim/kau_slide_in_right</item> @@ -27,7 +27,16 @@ <item name="android:windowEnterAnimation">@anim/kau_slide_in_right</item> </style> - <style name="KauSlideInFadeOut" parent="@style/KauSlideIn"> + <style name="KauSlideInBottom" parent="@android:style/Animation.Activity"> + <item name="android:activityOpenEnterAnimation">@anim/kau_slide_in_bottom</item> + <item name="android:activityCloseEnterAnimation">@anim/kau_slide_in_bottom</item> + <item name="android:taskOpenEnterAnimation">@anim/kau_slide_in_bottom</item> + <item name="android:taskCloseEnterAnimation">@anim/kau_slide_in_bottom</item> + <item name="android:taskToFrontEnterAnimation">@anim/kau_slide_in_bottom</item> + <item name="android:windowEnterAnimation">@anim/kau_slide_in_bottom</item> + </style> + + <style name="KauSlideInFadeOut" parent="@style/KauSlideInRight"> <item name="android:activityOpenExitAnimation">@anim/kau_fade_out</item> <item name="android:activityCloseExitAnimation">@anim/kau_fade_out</item> <item name="android:taskOpenExitAnimation">@anim/kau_fade_out</item> @@ -36,7 +45,7 @@ <item name="android:windowExitAnimation">@anim/kau_fade_out</item> </style> - <style name="KauSlideInSlideOut" parent="@style/KauSlideIn"> + <style name="KauSlideInSlideOutRight" parent="@style/KauSlideInRight"> <item name="android:activityOpenExitAnimation">@anim/kau_slide_out_right</item> <item name="android:activityCloseExitAnimation">@anim/kau_slide_out_right</item> <item name="android:taskOpenExitAnimation">@anim/kau_slide_out_right</item> @@ -44,4 +53,13 @@ <item name="android:taskToFrontExitAnimation">@anim/kau_slide_out_right</item> <item name="android:windowExitAnimation">@anim/kau_slide_out_right</item> </style> + + <style name="KauSlideInSlideOutBottom" parent="@style/KauSlideInBottom"> + <item name="android:activityOpenExitAnimation">@anim/kau_slide_out_bottom</item> + <item name="android:activityCloseExitAnimation">@anim/kau_slide_out_bottom</item> + <item name="android:taskOpenExitAnimation">@anim/kau_slide_out_bottom</item> + <item name="android:taskCloseExitAnimation">@anim/kau_slide_out_bottom</item> + <item name="android:taskToFrontExitAnimation">@anim/kau_slide_out_bottom</item> + <item name="android:windowExitAnimation">@anim/kau_slide_out_bottom</item> + </style> </resources> diff --git a/core/src/main/res/layout/kau_changelog_content.xml b/core/src/main/res/layout/kau_changelog_content.xml index 92b87b9..5c463aa 100644 --- a/core/src/main/res/layout/kau_changelog_content.xml +++ b/core/src/main/res/layout/kau_changelog_content.xml @@ -15,7 +15,7 @@ android:layout_height="wrap_content" android:lineSpacingMultiplier="1.6" android:paddingRight="5dp" - android:text="@string/kau_u2022" + android:text="@string/kau_bullet_point" android:textAppearance="@style/TextAppearance.AppCompat.Small" /> <TextView diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml deleted file mode 100644 index 7ad6e38..0000000 --- a/core/src/main/res/values/strings.xml +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<resources> - <string name="kau_about_libraries_intro">This app would not be possible without the following great libraries.</string> - <string name="kau_color_picker">Color Picker</string> - <string name="kau_dependencies_used">Dependencies Used</string> - <string name="kau_kpref_title_placeholder">Title Placeholder</string> - <string name="kau_md_color_palette">Color Palette</string> - <!--Color Picker--> - <string name="kau_md_custom">Custom</string> - <string name="kau_md_presets">Presets</string> - <string name="kau_pref_icon">Pref Icon</string> - <string name="kau_u2022">•</string> -</resources> diff --git a/docs/Changelog.md b/docs/Changelog.md index e958476..f0f4470 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,5 +1,10 @@ # Changelog +## v2.2 +* :imagepicker: Fully implement picker +* :core: [breaking] Replace update[x]Margin to setMargin[x] +* :core: Add setPadding[x] + ## v2.1 * :adapter: Fix up CardIItem * :adapter: Modularized kau animators @@ -13,6 +18,7 @@ * :core: Introduce slide transition style templates * :core: Update utils and remove StringHolder * :imagepicker: Create full image picker with blurrable selections +* Update dependencies ## v2.0 * Huge refactoring to separate functions to their own submodules diff --git a/gradle.properties b/gradle.properties index 102d6a7..7825465 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,6 +17,7 @@ org.gradle.jvmargs=-Xmx1536m # org.gradle.parallel=true APP_ID=KPrefs APP_GROUP=ca.allanwang +CORE_MIN_SDK=19 MIN_SDK=21 TARGET_SDK=26 BUILD_TOOLS=26.0.0 diff --git a/imagepicker/README.md b/imagepicker/README.md index 7fb185c..055b1c5 100644 --- a/imagepicker/README.md +++ b/imagepicker/README.md @@ -1,3 +1,21 @@ # KAU :imagepicker -WIP
\ No newline at end of file +ImagePicker is a beautiful gallery activity that allows you to pick images +from your storage. It is backed by FastAdapter and Glide, and offers blur and fade transitions. + +`ImagePickerActivity` is already fully functional, so you may directly add it to your manifest. +However, you can also extend it to change the package name. + +You may also easily launch the activity through the simple binder: +``` +Activity.kauLaunchImagePicker(YourClass::class.java, yourRequestCode) +``` + +If you are using the built in activity, you may omit the class argument. + +Note that this launches the activity through a `startActivityForResult` call + +You may get the activity response by overriding your `onActivityResult` method +to first verify that the request code matches and then call `kauOnImagePickerResult` + +This module also has a template style `Kau.ImagePicker` that defaults to a slide up animation.
\ No newline at end of file diff --git a/imagepicker/build.gradle b/imagepicker/build.gradle index d63f5fd..a31fac0 100644 --- a/imagepicker/build.gradle +++ b/imagepicker/build.gradle @@ -1,12 +1,10 @@ -apply from: '../android-lib.gradle' +ext.kauSubModuleMinSdk = project.CORE_MIN_SDK -android { - resourcePrefix "kau_" -} +apply from: '../android-lib.gradle' dependencies { - compile project(':core-ui') + compile project(':adapter') compile "com.github.bumptech.glide:glide:${GLIDE}" kapt "com.github.bumptech.glide:compiler:${GLIDE}" diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/BlurredImageView.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/BlurredImageView.kt index 8fb5cf3..2ce00ba 100644 --- a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/BlurredImageView.kt +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/BlurredImageView.kt @@ -2,6 +2,7 @@ package ca.allanwang.kau.imagepicker import android.content.Context import android.graphics.Color +import android.support.annotation.StyleRes import android.util.AttributeSet import android.view.View import android.widget.FrameLayout @@ -17,15 +18,15 @@ import jp.wasabeef.blurry.internal.BlurTask /** * Created by Allan Wang on 2017-07-14. * - * ImageView that is can be blurred and selected + * ImageView that can be blurred and selected * The frame is composed of three layers: the base, the blur, and the foreground * Images should be placed in the base view, and the blur view should not be touched * as the class will handle it * The foreground by default contains a white checkmark, but can be customized or hidden depending on the situation */ class BlurredImageView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 -) : FrameLayout(context, attrs, defStyleAttr, defStyleRes), MeasureSpecContract by MeasureSpecDelegate() { + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr), MeasureSpecContract by MeasureSpecDelegate() { private var blurred = false val imageBase: ImageView by bindView(R.id.image_base) @@ -38,11 +39,6 @@ class BlurredImageView @JvmOverloads constructor( imageForeground.setIcon(GoogleMaterial.Icon.gmd_check, 30) } - companion object { - const val ANIMATION_DURATION = 200L - const val ANIMATION_SCALE = 0.95f - } - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val result = onMeasure(this, widthMeasureSpec, heightMeasureSpec) super.onMeasure(result.first, result.second) @@ -73,13 +69,12 @@ class BlurredImageView @JvmOverloads constructor( val factor = BlurFactor() factor.width = width factor.height = height - val task = BlurTask(imageBase, factor) { + BlurTask(imageBase, factor) { imageBlur.setImageDrawable(it) scaleAnimate(ANIMATION_SCALE).start() imageBlur.alphaAnimate(1f).start() imageForeground.alphaAnimate(1f).start() - } - task.execute() + }.execute() } /** diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageHelper.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageHelper.kt deleted file mode 100644 index 9b45679..0000000 --- a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageHelper.kt +++ /dev/null @@ -1,10 +0,0 @@ -package ca.allanwang.kau.imagepicker - -import com.bumptech.glide.annotation.GlideModule -import com.bumptech.glide.module.LibraryGlideModule - -/** - * Created by Allan Wang on 2017-07-04. - */ -@GlideModule -class KauGlide : LibraryGlideModule()
\ No newline at end of file diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt index 852e1e8..d258822 100644 --- a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageItem.kt @@ -25,33 +25,42 @@ class ImageItem(val data: ImageModel) : KauIItem<ImageItem, ImageItem.ViewHolder>(R.layout.kau_iitem_image, { ViewHolder(it) }) { private var failedToLoad = false + var withFade = true - fun bindEvents(fastAdapter: FastAdapter<ImageItem>) { - fastAdapter.withMultiSelect(true) - fastAdapter.withSelectable(true) - fastAdapter.withOnClickListener { v, _, _, _ -> - val image = v as BlurredImageView - image.toggleBlur() - true + companion object { + fun bindEvents(fastAdapter: FastAdapter<ImageItem>) { + fastAdapter.withMultiSelect(true) + .withSelectable(true) + //adapter selector occurs before the on click event + .withOnClickListener { v, _, item, _ -> + val image = v as BlurredImageView + if (item.isSelected) image.blur() + else image.removeBlur() + true + } } } + override fun isSelectable(): Boolean = !failedToLoad + override fun bindView(holder: ViewHolder, payloads: List<Any>?) { super.bindView(holder, payloads) - holder.container.alpha = 0f + if (withFade) holder.container.alpha = 0f Glide.with(holder.itemView) .load(data.data) .listener(object : RequestListener<Drawable> { override fun onLoadFailed(e: GlideException?, model: Any, target: Target<Drawable>, isFirstResource: Boolean): Boolean { failedToLoad = true; holder.container.setIcon(GoogleMaterial.Icon.gmd_error); - holder.container.animate().alpha(1f).start(); + if (withFade) holder.container.animate().alpha(1f).start(); return true; } override fun onResourceReady(resource: Drawable, model: Any, target: Target<Drawable>, dataSource: DataSource, isFirstResource: Boolean): Boolean { - holder.container.animate().alpha(1f).start(); - return false; + holder.container.imageBase.setImageDrawable(resource) + if (isSelected) holder.container.blurInstantly() + if (withFade) holder.container.animate().alpha(1f).start(); + return true; } }) .into(holder.container.imageBase) @@ -63,14 +72,13 @@ class ImageItem(val data: ImageModel) .sizePx(sizePx) .paddingPx(sizePx / 3) .color(Color.WHITE)) - //todo add background - imageBase.setBackgroundColor(ImagePickerActivityBase.accentColor) + imageBase.setBackgroundColor(ImagePickerActivity.accentColor) imageForeground.gone() } private fun computeViewSize(context: Context): Int { val screenWidthPx = context.resources.displayMetrics.widthPixels - return screenWidthPx / ImagePickerActivityBase.computeColumnCount(context) + return screenWidthPx / ImagePickerActivity.computeColumnCount(context) } override fun unbindView(holder: ViewHolder) { @@ -81,6 +89,7 @@ class ImageItem(val data: ImageModel) } else { holder.container.fullReset() } + failedToLoad = false } class ViewHolder(v: View) : RecyclerView.ViewHolder(v) { diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageModel.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageModel.kt index 26e4137..d744650 100644 --- a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageModel.kt +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImageModel.kt @@ -1,6 +1,8 @@ package ca.allanwang.kau.imagepicker import android.database.Cursor +import android.os.Parcel +import android.os.Parcelable import android.provider.MediaStore import android.support.annotation.NonNull @@ -8,14 +10,45 @@ import android.support.annotation.NonNull /** * Created by Allan Wang on 2017-07-14. */ -class ImageModel(@NonNull cursor: Cursor) { - val size = cursor.getLong(MediaStore.Images.Media.SIZE) - val dateModified = cursor.getLong(MediaStore.Images.Media.DATE_MODIFIED) - val data = cursor.getString(MediaStore.Images.Media.DATA) - val displayName = cursor.getString(MediaStore.Images.Media.DISPLAY_NAME) +data class ImageModel(val size: Long, val dateModified: Long, val data: String, val displayName: String) : Parcelable { - private fun Cursor.getString(name: String) = getString(getColumnIndex(name)) - private fun Cursor.getLong(name: String) = getLong(getColumnIndex(name)) + constructor(@NonNull cursor: Cursor) : this( + cursor.getLong(MediaStore.Images.Media.SIZE), + cursor.getLong(MediaStore.Images.Media.DATE_MODIFIED), + cursor.getString(MediaStore.Images.Media.DATA), + cursor.getString(MediaStore.Images.Media.DISPLAY_NAME) + ) -}
\ No newline at end of file + constructor(parcel: Parcel) : this( + parcel.readLong(), + parcel.readLong(), + parcel.readString(), + parcel.readString()) + + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeLong(this.size) + parcel.writeLong(this.dateModified) + parcel.writeString(this.data) + parcel.writeString(this.displayName) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator<ImageModel> { + override fun createFromParcel(parcel: Parcel): ImageModel { + return ImageModel(parcel) + } + + override fun newArray(size: Int): Array<ImageModel?> { + return arrayOfNulls(size) + } + } + +} + +private fun Cursor.getString(name: String) = getString(getColumnIndex(name)) +private fun Cursor.getLong(name: String) = getLong(getColumnIndex(name))
\ No newline at end of file diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivity.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivity.kt new file mode 100644 index 0000000..814cde4 --- /dev/null +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivity.kt @@ -0,0 +1,200 @@ +package ca.allanwang.kau.imagepicker + +import android.Manifest +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.database.Cursor +import android.os.Bundle +import android.provider.MediaStore +import android.support.design.widget.AppBarLayout +import android.support.design.widget.CoordinatorLayout +import android.support.design.widget.FloatingActionButton +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.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.Toolbar +import android.widget.TextView +import ca.allanwang.kau.animators.FadeScaleAnimatorAdd +import ca.allanwang.kau.animators.KauAnimator +import ca.allanwang.kau.permissions.kauRequestPermissions +import ca.allanwang.kau.utils.* +import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter +import com.mikepenz.google_material_typeface_library.GoogleMaterial + + +/** + * Created by Allan Wang on 2017-07-04. + * + * Base activity for selecting images from storage + */ +open class ImagePickerActivity : AppCompatActivity(), LoaderManager.LoaderCallbacks<Cursor> { + + val imageAdapter = FastItemAdapter<ImageItem>() + + val coordinator: CoordinatorLayout by bindView(R.id.kau_coordinator) + val toolbar: Toolbar by bindView(R.id.kau_toolbar) + val selectionCount: TextView by bindView(R.id.kau_selection_count) + val recycler: RecyclerView by bindView(R.id.kau_recyclerview) + val fab: FloatingActionButton by bindView(R.id.kau_fab) + + companion object { + /** + * 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 { + val minImageSizePx = context.dimenPixelSize(R.dimen.kau_image_minimum_size) + val screenWidthPx = context.resources.displayMetrics.widthPixels + return screenWidthPx / minImageSizePx + } + + var accentColor: Int = 0xff666666.toInt() + + fun onImagePickerResult(resultCode: Int, data: Intent?): List<ImageModel> { + if (resultCode != Activity.RESULT_OK || data == null || !data.hasExtra(IMAGE_PICKER_RESULT)) + return emptyList() + return data.getParcelableArrayListExtra(IMAGE_PICKER_RESULT) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.kau_activity_image_picker) + + selectionCount.setCompoundDrawables(null, null, GoogleMaterial.Icon.gmd_image.toDrawable(this, 18), null) + + setSupportActionBar(toolbar) + supportActionBar?.apply { + setDisplayHomeAsUpEnabled(true) + setDisplayShowHomeEnabled(true) + setHomeAsUpIndicator(GoogleMaterial.Icon.gmd_close.toDrawable(this@ImagePickerActivity, 18)) + } + toolbar.setNavigationOnClickListener { onBackPressed() } + + recycler.apply { + layoutManager = GridLayoutManager(context, computeColumnCount(context)) + adapter = imageAdapter + setHasFixedSize(true) + itemAnimator = KauAnimator(FadeScaleAnimatorAdd(0.8f)) + } + + ImageItem.bindEvents(imageAdapter) + imageAdapter.withSelectionListener({ _, _ -> selectionCount.text = imageAdapter.selections.size.toString() }) + + fab.apply { + show() + setIcon(GoogleMaterial.Icon.gmd_send) + setOnClickListener { + val selection = imageAdapter.selectedItems + if (selection.isEmpty()) { + toast(R.string.kau_no_images_selected) + } else { + val intent = Intent() + val data = ArrayList(selection.map { it.data }) + intent.putParcelableArrayListExtra(IMAGE_PICKER_RESULT, data) + setResult(RESULT_OK, intent) + finish() + } + } + hideOnDownwardsScroll(recycler) + } + + loadImages() + } + + /** + * Request read permissions and load all external images + * The result will be filtered through {@link #onLoadFinished(Loader, Cursor)} + * Call this to make sure that we request permissions each time + * The adapter will be cleared on each successful call + */ + private fun loadImages() { + kauRequestPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) { + granted, _ -> + if (granted) { + supportLoaderManager.initLoader(LOADER_ID, null, this) + setToolbarScrollable(true) + } else { + toast(R.string.kau_permission_denied) + setToolbarScrollable(false) + } + } + } + + /** + * Decide whether the toolbar can hide itself + * We typically want this behaviour unless we don't have enough images + * to fill the entire screen. In that case we don't want the recyclerview to be scrollable + * which means the toolbar shouldn't scroll either + + * @param scrollable true if scroll flags are enabled, false otherwise + */ + private fun setToolbarScrollable(scrollable: Boolean) { + val params = toolbar.layoutParams as AppBarLayout.LayoutParams + if (scrollable) + params.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS or AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL + else + params.scrollFlags = 0 + } + + override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { + val columns = arrayOf( + MediaStore.Images.Media._ID, + MediaStore.Images.Media.TITLE, + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.SIZE, + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATE_MODIFIED + ) + return CursorLoader(this, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + columns, + null, + null, + //Sort by descending date + MediaStore.Images.Media.DATE_MODIFIED + " DESC") + } + + override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor?) { + reset() + if (data == null || !data.moveToFirst()) { + toast(R.string.kau_no_images_found) + setToolbarScrollable(false) + return + } + do { + val model = ImageModel(data) + if (!shouldLoad(model)) continue + imageAdapter.add(ImageItem(model)) + } while (data.moveToNext()) + setToolbarScrollable((recycler.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition() < imageAdapter.getItemCount() - 1) + } + + /** + * Optional filter to decide which images get displayed + * Defaults to checking their sizes to filter out + * very small images such as lurking drawables/icons + * + * Returns true if model should be displayed, false otherwise + */ + open fun shouldLoad(model: ImageModel): Boolean = model.size > 10000L + + private fun reset() { + imageAdapter.clear(); + } + + override fun onLoaderReset(loader: Loader<Cursor>) = reset() + + override fun onBackPressed() { + setResult(RESULT_CANCELED) + super.onBackPressed() + } +}
\ No newline at end of file diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivityBase.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivityBase.kt deleted file mode 100644 index 24c2db7..0000000 --- a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerActivityBase.kt +++ /dev/null @@ -1,114 +0,0 @@ -package ca.allanwang.kau.imagepicker - -import android.Manifest -import android.content.Context -import android.database.Cursor -import android.os.Bundle -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 android.support.v7.widget.Toolbar -import ca.allanwang.kau.permissions.kauRequestPermissions -import ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout -import ca.allanwang.kau.utils.bindView -import ca.allanwang.kau.utils.dimenPixelSize -import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter - - -/** - * Created by Allan Wang on 2017-07-04. - * - */ -abstract class ImagePickerActivityBase : AppCompatActivity(), LoaderManager.LoaderCallbacks<Cursor> { - - val toolbar: Toolbar by bindView(R.id.kau_toolbar) - val draggableFrame: ElasticDragDismissFrameLayout by bindView(R.id.kau_draggable) - val recycler: RecyclerView by bindView(R.id.kau_recycler) - val imageAdapter = FastItemAdapter<ImageItem>() - - companion object { - /** - * 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 { - val minImageSizePx = context.dimenPixelSize(R.dimen.kau_image_minimum_size) - val screenWidthPx = context.resources.displayMetrics.widthPixels - return screenWidthPx / minImageSizePx - } - - var accentColor: Int = 0xff666666.toInt() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.kau_activity_image_picker) - recycler.layoutManager = GridLayoutManager(this, computeColumnCount(this)) - recycler.adapter = imageAdapter - - with(imageAdapter) { - withPositionBasedStateManagement(false) - withMultiSelect(true) - withSelectable(true) - withOnClickListener { v, _, _, _ -> - (v as BlurredImageView).toggleBlur() - true - } - } - draggableFrame.addListener(object : ElasticDragDismissFrameLayout.SystemChromeFader(this) { - override fun onDragDismissed() { - if (draggableFrame.translationY < 0) { -// window.returnTransition = TransitionInflater.from(this@ImagePickerActivityBase) -// .inflateTransition(R.transition.kau_about_return_upwards) - } - finishAfterTransition() - } - }) - kauRequestPermissions(Manifest.permission.READ_EXTERNAL_STORAGE) { - granted, _ -> - if (granted) { - supportLoaderManager.initLoader(42, null, this) - } - } - } - - override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { - val columns = arrayOf( - MediaStore.Images.Media._ID, - MediaStore.Images.Media.TITLE, - MediaStore.Images.Media.DATA, - MediaStore.Images.Media.SIZE, - MediaStore.Images.Media.DISPLAY_NAME, - MediaStore.Images.Media.DATE_MODIFIED - ) - return CursorLoader(this, - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - columns, - null, - null, - MediaStore.Images.Media.DATE_MODIFIED + " DESC") - } - - override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor?) { - reset() - if (data == null) return - if (data.moveToFirst()) { - do { - val img = ImageModel(data) - imageAdapter.add(ImageItem(img)) - } while (data.moveToNext()) - } - } - - private fun reset() { - imageAdapter.clear(); - } - - override fun onLoaderReset(loader: Loader<Cursor>) = reset() -}
\ No newline at end of file diff --git a/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerBinder.kt b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerBinder.kt new file mode 100644 index 0000000..9e63464 --- /dev/null +++ b/imagepicker/src/main/kotlin/ca/allanwang/kau/imagepicker/ImagePickerBinder.kt @@ -0,0 +1,34 @@ +package ca.allanwang.kau.imagepicker + +import android.app.Activity +import android.content.Intent + +/** + * Created by Allan Wang on 2017-07-21. + * + * Extension functions for interacting with the image picker + * as well as internal constants + */ + +/** + * Image picker launcher + */ +fun Activity.kauLaunchImagePicker(clazz: Class<out ImagePickerActivity>, requestCode: Int) { + startActivityForResult(Intent(this, clazz), requestCode) +} + +fun Activity.kauLaunchImagePicker(requestCode: Int) = kauLaunchImagePicker(ImagePickerActivity::class.java, requestCode) + +/** + * Image picker result + * call under [Activity.onActivityResult] + * and make sure that the requestCode matches first + */ +fun Activity.kauOnImagePickerResult(resultCode: Int, data: Intent?) = ImagePickerActivity.onImagePickerResult(resultCode, data) + +internal const val LOADER_ID = 42 +internal const val IMAGE_PICKER_RESULT = "image_picker_result" + +internal const val ANIMATION_DURATION = 200L +internal const val ANIMATION_SCALE = 0.95f + diff --git a/imagepicker/src/main/res-public/values/public.xml b/imagepicker/src/main/res-public/values/public.xml new file mode 100644 index 0000000..cf14680 --- /dev/null +++ b/imagepicker/src/main/res-public/values/public.xml @@ -0,0 +1,4 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='dummy' type='id' /> +</resources>
\ No newline at end of file diff --git a/imagepicker/src/main/res/layout/kau_activity_image_picker.xml b/imagepicker/src/main/res/layout/kau_activity_image_picker.xml index 6e0bf67..5b0300d 100644 --- a/imagepicker/src/main/res/layout/kau_activity_image_picker.xml +++ b/imagepicker/src/main/res/layout/kau_activity_image_picker.xml @@ -1,29 +1,54 @@ <?xml version="1.0" encoding="utf-8"?> -<ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/kau_coordinator" android:layout_width="match_parent" android:layout_height="match_parent" - android:id="@+id/kau_draggable" - app:dragDismissDistance="@dimen/kau_drag_dismiss_distance" - app:dragDismissScale="0.95"> + android:fitsSystemWindows="true"> - <LinearLayout + <android.support.design.widget.AppBarLayout + android:id="@+id/kau_appbar" android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginTop="@dimen/kau_drag_dismiss_distance" - android:orientation="vertical"> + android:layout_height="wrap_content" + android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/kau_toolbar" android:layout_width="match_parent" - android:layout_height="?attr/actionBarSize" /> + android:layout_height="?attr/actionBarSize" + app:layout_scrollFlags="scroll|enterAlways" + app:popupTheme="@style/ThemeOverlay.AppCompat.Light"> - <android.support.v7.widget.RecyclerView - android:id="@+id/kau_recycler" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="?android:colorBackground" /> + <TextView + android:id="@+id/kau_selection_count" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:drawablePadding="@dimen/kau_padding_small" + android:gravity="center_vertical" + android:paddingEnd="@dimen/kau_padding_normal" + android:paddingStart="@dimen/kau_padding_normal" + android:text="@string/kau_0" /> + + </android.support.v7.widget.Toolbar> + + </android.support.design.widget.AppBarLayout> + + <android.support.v7.widget.RecyclerView + android:id="@+id/kau_recyclerview" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> + + <android.support.design.widget.FloatingActionButton + android:id="@+id/kau_fab" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="@dimen/kau_fab_margin" + android:clickable="true" + app:backgroundTint="?colorAccent" + app:layout_anchor="@id/kau_recyclerview" + app:layout_anchorGravity="bottom|right|end" /> - </LinearLayout> -</ca.allanwang.kau.ui.widgets.ElasticDragDismissFrameLayout>
\ No newline at end of file +</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file diff --git a/imagepicker/src/main/res/values/strings.xml b/imagepicker/src/main/res/values/strings.xml new file mode 100644 index 0000000..7aa7f3e --- /dev/null +++ b/imagepicker/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="kau_no_images_found">No images found</string> + <string name="kau_no_images_selected">No images have been selected</string> + <string name="kau_blurrable_imageview">Blurrable ImageView</string> +</resources>
\ No newline at end of file diff --git a/imagepicker/src/main/res/values/styles.xml b/imagepicker/src/main/res/values/styles.xml index 1fbb184..0d9ce64 100644 --- a/imagepicker/src/main/res/values/styles.xml +++ b/imagepicker/src/main/res/values/styles.xml @@ -1,5 +1,7 @@ <resources> - <style name="Kau.Translucent.ImagePicker" parent="Kau.Translucent.SlideBottom" /> + <style name="Kau.ImagePicker"> + <item name="android:windowAnimationStyle">@style/KauSlideInSlideOutBottom</item> + </style> </resources> diff --git a/kpref-activity/build.gradle b/kpref-activity/build.gradle index 963d9c0..2ced0c2 100644 --- a/kpref-activity/build.gradle +++ b/kpref-activity/build.gradle @@ -1,8 +1,6 @@ -apply from: '../android-lib.gradle' +ext.kauSubModuleResourcePrefix = "kau_pref_" -android { - resourcePrefix "kau_pref_" -} +apply from: '../android-lib.gradle' dependencies { diff --git a/kpref-activity/src/main/res-public/values/public.xml b/kpref-activity/src/main/res-public/values/public.xml new file mode 100644 index 0000000..cf14680 --- /dev/null +++ b/kpref-activity/src/main/res-public/values/public.xml @@ -0,0 +1,4 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='dummy' type='id' /> +</resources>
\ No newline at end of file diff --git a/kpref-activity/src/main/res/values/strings.xml b/kpref-activity/src/main/res/values/strings.xml new file mode 100644 index 0000000..de6c42f --- /dev/null +++ b/kpref-activity/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="kau_pref_icon">Pref Icon</string> +</resources>
\ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index 27af7c2..a31385d 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -17,7 +17,6 @@ android { androidGitVersion { codeFormat = 'MMNNBBBB' - prefix 'v' } defaultConfig { diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index ab5b6d8..d041a3e 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -27,10 +27,10 @@ android:theme="@style/Kau.Translucent" /> <activity android:name=".AboutActivity" - android:theme="@style/Kau.Translucent.About" /> + android:theme="@style/Kau.About" /> <activity - android:name=".ImageActivity" - android:theme="@style/Kau.Translucent.ImagePicker" /> + android:name="ca.allanwang.kau.imagepicker.ImagePickerActivity" + android:theme="@style/Kau.ImagePicker" /> <activity android:name=".AdapterActivity" android:theme="@style/Kau.Translucent.SlideBottom" /> diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/ImageActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/ImageActivity.kt deleted file mode 100644 index a0b3dc5..0000000 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/ImageActivity.kt +++ /dev/null @@ -1,8 +0,0 @@ -package ca.allanwang.kau.sample - -import ca.allanwang.kau.imagepicker.ImagePickerActivityBase - -/** - * Created by Allan Wang on 2017-07-04. - */ -class ImageActivity : ImagePickerActivityBase()
\ No newline at end of file diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt index 53ec745..4711701 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt @@ -1,10 +1,14 @@ package ca.allanwang.kau.sample +import android.content.Intent import android.os.Bundle import android.os.PersistableBundle import android.view.Menu import android.view.MenuItem +import ca.allanwang.kau.about.kauLaunchAbout import ca.allanwang.kau.email.sendEmail +import ca.allanwang.kau.imagepicker.kauLaunchImagePicker +import ca.allanwang.kau.imagepicker.kauOnImagePickerResult import ca.allanwang.kau.kpref.activity.CoreAttributeContract import ca.allanwang.kau.kpref.activity.KPrefActivity import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder @@ -22,53 +26,59 @@ import com.mikepenz.google_material_typeface_library.GoogleMaterial class MainActivity : KPrefActivity() { var searchView: SearchView? = null - //some of the most common english words for show - val wordBank: List<String> by lazy { - listOf("the", "name", "of", "very", "to", "through", - "and", "just", "a", "form", "in", "much", "is", "great", "it", "think", "you", "say", - "that", "help", "he", "low", "was", "line", "for", "before", "on", "turn", "are", "cause", - "with", "same", "as", "mean", "I", "differ", "his", "move", "they", "right", "be", "boy", - "at", "old", "one", "too", "have", "does", "this", "tell", "from", "sentence", "or", "set", - "had", "three", "by", "want", "hot", "air", "but", "well", "some", "also", "what", "play", - "there", "small", "we", "end", "can", "put", "out", "home", "other", "read", "were", "hand", - "all", "port", "your", "large", "when", "spell", "up", "add", "use", "even", "word", "land", - "how", "here", "said", "must", "an", "big", "each", "high", "she", "such", "which", "follow", - "do", "act", "their", "why", "time", "ask", "if", "men", "will", "change", "way", "went", - "about", "light", "many", "kind", "then", "off", "them", "need", "would", "house", "write", - "picture", "like", "try", "so", "us", "these", "again", "her", "animal", "long", "point", - "make", "mother", "thing", "world", "see", "near", "him", "build", "two", "self", "has", - "earth", "look", "father", "more", "head", "day", "stand", "could", "own", "go", "page", - "come", "should", "did", "country", "my", "found", "sound", "answer", "no", "school", "most", - "grow", "number", "study", "who", "still", "over", "learn", "know", "plant", "water", "cover", - "than", "food", "call", "sun", "first", "four", "people", "thought", "may", "let", "down", "keep", - "side", "eye", "been", "never", "now", "last", "find", "door", "any", "between", "new", "city", - "work", "tree", "part", "cross", "take", "since", "get", "hard", "place", "start", "made", - "might", "live", "story", "where", "saw", "after", "far", "back", "sea", "little", "draw", - "only", "left", "round", "late", "man", "run", "year", "don't", "came", "while", "show", - "press", "every", "close", "good", "night", "me", "real", "give", "life", "our", "few", "under", - "stopRankWordRankWord", "open", "ten", "seem", "simple", "together", "several", "next", - "vowel", "white", "toward", "children", "war", "begin", "lay", "got", "against", "walk", "pattern", - "example", "slow", "ease", "center", "paper", "love", "often", "person", "always", "money", - "music", "serve", "those", "appear", "both", "road", "mark", "map", "book", "science", "letter", - "rule", "until", "govern", "mile", "pull", "river", "cold", "car", "notice", "feet", "voice", - "care", "fall", "second", "power", "group", "town", "carry", "fine", "took", "certain", "rain", - "fly", "eat", "unit", "room", "lead", "friend", "cry", "began", "dark", "idea", "machine", - "fish", "note", "mountain", "wait", "north", "plan", "once", "figure", "base", "star", "hear", - "box", "horse", "noun", "cut", "field", "sure", "rest", "watch", "correct", "color", "able", - "face", "pound", "wood", "done", "main", "beauty", "enough", "drive", "plain", "stood", "girl", - "contain", "usual", "front", "young", "teach", "ready", "week", "above", "final", "ever", "gave", - "red", "green", "list", "oh", "though", "quick", "feel", "develop", "talk", "sleep", "bird", - "warm", "soon", "free", "body", "minute", "dog", "strong", "family", "special", "direct", "mind", - "pose", "behind", "leave", "clear", "song", "tail", "measure", "produce", "state", "fact", "product", - "street", "black", "inch", "short", "lot", "numeral", "nothing", "class", "course", "wind", "stay", - "question", "wheel", "happen", "full", "complete", "force", "ship", "blue", "area", "object", "half", - "decide", "rock", "surface", "order", "deep", "fire", "moon", "south", "island", "problem", "foot", - "piece", "yet", "told", "busy", "knew", "test", "pass", "record", "farm", "boat", "top", "common", - "whole", "gold", "king", "possible", "size", "plane", "heard", "age", "best", "dry", "hour", "wonder", - "better", "laugh", "true.", "thousand", "during", "ago", "hundred", "ran", "am", "check", "remember", - "game", "step", "shape", "early", "yes", "hold", "hot", "west", "miss", "ground", "brought", "interest", - "heat", "reach", "snow", "fast", "bed", "five", "bring", "sing", "sit", "listen", "perhaps", "six", - "fill", "table", "east", "travel", "weight", "less", "language", "morning", "among") + + companion object { + + //some of the most common english words for show + val wordBank: List<String> by lazy { + listOf("the", "name", "of", "very", "to", "through", + "and", "just", "a", "form", "in", "much", "is", "great", "it", "think", "you", "say", + "that", "help", "he", "low", "was", "line", "for", "before", "on", "turn", "are", "cause", + "with", "same", "as", "mean", "I", "differ", "his", "move", "they", "right", "be", "boy", + "at", "old", "one", "too", "have", "does", "this", "tell", "from", "sentence", "or", "set", + "had", "three", "by", "want", "hot", "air", "but", "well", "some", "also", "what", "play", + "there", "small", "we", "end", "can", "put", "out", "home", "other", "read", "were", "hand", + "all", "port", "your", "large", "when", "spell", "up", "add", "use", "even", "word", "land", + "how", "here", "said", "must", "an", "big", "each", "high", "she", "such", "which", "follow", + "do", "act", "their", "why", "time", "ask", "if", "men", "will", "change", "way", "went", + "about", "light", "many", "kind", "then", "off", "them", "need", "would", "house", "write", + "picture", "like", "try", "so", "us", "these", "again", "her", "animal", "long", "point", + "make", "mother", "thing", "world", "see", "near", "him", "build", "two", "self", "has", + "earth", "look", "father", "more", "head", "day", "stand", "could", "own", "go", "page", + "come", "should", "did", "country", "my", "found", "sound", "answer", "no", "school", "most", + "grow", "number", "study", "who", "still", "over", "learn", "know", "plant", "water", "cover", + "than", "food", "call", "sun", "first", "four", "people", "thought", "may", "let", "down", "keep", + "side", "eye", "been", "never", "now", "last", "find", "door", "any", "between", "new", "city", + "work", "tree", "part", "cross", "take", "since", "get", "hard", "place", "start", "made", + "might", "live", "story", "where", "saw", "after", "far", "back", "sea", "little", "draw", + "only", "left", "round", "late", "man", "run", "year", "don't", "came", "while", "show", + "press", "every", "close", "good", "night", "me", "real", "give", "life", "our", "few", "under", + "stopRankWordRankWord", "open", "ten", "seem", "simple", "together", "several", "next", + "vowel", "white", "toward", "children", "war", "begin", "lay", "got", "against", "walk", "pattern", + "example", "slow", "ease", "center", "paper", "love", "often", "person", "always", "money", + "music", "serve", "those", "appear", "both", "road", "mark", "map", "book", "science", "letter", + "rule", "until", "govern", "mile", "pull", "river", "cold", "car", "notice", "feet", "voice", + "care", "fall", "second", "power", "group", "town", "carry", "fine", "took", "certain", "rain", + "fly", "eat", "unit", "room", "lead", "friend", "cry", "began", "dark", "idea", "machine", + "fish", "note", "mountain", "wait", "north", "plan", "once", "figure", "base", "star", "hear", + "box", "horse", "noun", "cut", "field", "sure", "rest", "watch", "correct", "color", "able", + "face", "pound", "wood", "done", "main", "beauty", "enough", "drive", "plain", "stood", "girl", + "contain", "usual", "front", "young", "teach", "ready", "week", "above", "final", "ever", "gave", + "red", "green", "list", "oh", "though", "quick", "feel", "develop", "talk", "sleep", "bird", + "warm", "soon", "free", "body", "minute", "dog", "strong", "family", "special", "direct", "mind", + "pose", "behind", "leave", "clear", "song", "tail", "measure", "produce", "state", "fact", "product", + "street", "black", "inch", "short", "lot", "numeral", "nothing", "class", "course", "wind", "stay", + "question", "wheel", "happen", "full", "complete", "force", "ship", "blue", "area", "object", "half", + "decide", "rock", "surface", "order", "deep", "fire", "moon", "south", "island", "problem", "foot", + "piece", "yet", "told", "busy", "knew", "test", "pass", "record", "farm", "boat", "top", "common", + "whole", "gold", "king", "possible", "size", "plane", "heard", "age", "best", "dry", "hour", "wonder", + "better", "laugh", "true.", "thousand", "during", "ago", "hundred", "ran", "am", "check", "remember", + "game", "step", "shape", "early", "yes", "hold", "hot", "west", "miss", "ground", "brought", "interest", + "heat", "reach", "snow", "fast", "bed", "five", "bring", "sing", "sit", "listen", "perhaps", "six", + "fill", "table", "east", "travel", "weight", "less", "language", "morning", "among") + } + + const val REQUEST_IMAGE = 27 } override fun kPrefCoreAttributes(): CoreAttributeContract.() -> Unit = { @@ -155,7 +165,7 @@ class MainActivity : KPrefActivity() { } plainText(R.string.gallery_showcase) { - onClick = { _, _, _ -> startActivity(ImageActivity::class.java, transition = true); false } + onClick = { _, _, _ -> kauLaunchImagePicker(REQUEST_IMAGE); false } } plainText(R.string.adapter_showcase) { @@ -163,7 +173,7 @@ class MainActivity : KPrefActivity() { } plainText(R.string.kau_about_app) { - onClick = { _, _, _ -> startActivity(AboutActivity::class.java, transition = true); false } + onClick = { _, _, _ -> kauLaunchAbout(AboutActivity::class.java); false } } } @@ -195,12 +205,6 @@ class MainActivity : KPrefActivity() { } - override fun onPostCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { - super.onPostCreate(savedInstanceState, persistentState) - //TODO testing - startActivity(ImageActivity::class.java, transition = true) - } - override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_main, menu) if (searchView == null) searchView = bindSearchView(menu, R.id.action_search) { @@ -231,7 +235,7 @@ class MainActivity : KPrefActivity() { when (item.itemId) { R.id.action_settings -> startActivity(AnimActivity::class.java) R.id.action_email -> sendEmail(R.string.your_email, R.string.your_subject) - R.id.test -> startActivity(ImageActivity::class.java, transition = true) + R.id.test -> kauLaunchImagePicker(REQUEST_IMAGE) else -> return super.onOptionsItemSelected(item) } return true @@ -240,4 +244,11 @@ class MainActivity : KPrefActivity() { override fun onBackPressed() { if (!(searchView?.onBackPressed() ?: false)) super.onBackPressed() } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + REQUEST_IMAGE -> toast("${kauOnImagePickerResult(resultCode, data).size} images selected") + } + } } diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml index b550607..15c1745 100644 --- a/sample/src/main/res/values/styles.xml +++ b/sample/src/main/res/values/styles.xml @@ -20,7 +20,7 @@ </style> <style name="AppTheme.Slide" parent="AppTheme"> - <item name="android:windowAnimationStyle">@style/KauSlideInSlideOut</item> + <item name="android:windowAnimationStyle">@style/KauSlideInSlideOutRight</item> </style> </resources> diff --git a/sample/src/main/res/xml/kau_changelog.xml b/sample/src/main/res/xml/kau_changelog.xml index 1599f08..488e01b 100644 --- a/sample/src/main/res/xml/kau_changelog.xml +++ b/sample/src/main/res/xml/kau_changelog.xml @@ -5,6 +5,18 @@ <version title="v"/> <item text="" /> --> + + <version title="v2.2"/> + <item text=":imagepicker: Fully implement picker" /> + <item text=":core: [breaking] Replace update[x]Margin to setMargin[x]" /> + <item text=":core: Add setPadding[x]" /> + <item text="" /> + <item text="" /> + <item text="" /> + <item text="" /> + <item text="" /> + <item text="" /> + <item text="" /> <version title="v2.1"/> <item text=":adapter: Fix up CardIItem" /> diff --git a/searchview/build.gradle b/searchview/build.gradle index 9504b20..e503ce4 100644 --- a/searchview/build.gradle +++ b/searchview/build.gradle @@ -1,8 +1,6 @@ -apply from: '../android-lib.gradle' +ext.kauSubModuleResourcePrefix = "kau_search_" -android { - resourcePrefix "kau_search_" -} +apply from: '../android-lib.gradle' dependencies { diff --git a/searchview/src/main/res-public/values/public.xml b/searchview/src/main/res-public/values/public.xml new file mode 100644 index 0000000..cf14680 --- /dev/null +++ b/searchview/src/main/res-public/values/public.xml @@ -0,0 +1,4 @@ +<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<!-- AUTO-GENERATED FILE. DO NOT MODIFY. public.xml is generated by the generatepublicxml gradle task --> + <public name='dummy' type='id' /> +</resources>
\ No newline at end of file |