diff options
75 files changed, 664 insertions, 496 deletions
@@ -28,4 +28,6 @@ .idea/**/assetWizardSettings.xml .idea/**/caches .idea/modules.xml -.idea/modules
\ No newline at end of file +.idea/modules +.idea/vcs.xml +.idea/codeStyles/Project.xml
\ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index be6976d..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,136 +0,0 @@ -<component name="ProjectCodeStyleConfiguration"> - <code_scheme name="Project" version="173"> - <AndroidXmlCodeStyleSettings> - <option name="USE_CUSTOM_SETTINGS" value="true" /> - </AndroidXmlCodeStyleSettings> - <JetCodeStyleSettings> - <option name="PACKAGES_TO_USE_STAR_IMPORTS"> - <value> - <package name="kotlinx.android.synthetic" withSubpackages="true" static="false" /> - </value> - </option> - <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" /> - <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" /> - <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> - </JetCodeStyleSettings> - <XML> - <option name="XML_KEEP_LINE_BREAKS" value="false" /> - <option name="XML_ALIGN_ATTRIBUTES" value="false" /> - <option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" /> - </XML> - <codeStyleSettings language="XML"> - <option name="FORCE_REARRANGE_MODE" value="1" /> - <indentOptions> - <option name="CONTINUATION_INDENT_SIZE" value="4" /> - </indentOptions> - <arrangement> - <rules> - <section> - <rule> - <match> - <AND> - <NAME>xmlns:android</NAME> - <XML_NAMESPACE>^$</XML_NAMESPACE> - </AND> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>xmlns:.*</NAME> - <XML_NAMESPACE>^$</XML_NAMESPACE> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>.*:id</NAME> - <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> - </AND> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>.*:name</NAME> - <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> - </AND> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>name</NAME> - <XML_NAMESPACE>^$</XML_NAMESPACE> - </AND> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>style</NAME> - <XML_NAMESPACE>^$</XML_NAMESPACE> - </AND> - </match> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>.*</NAME> - <XML_NAMESPACE>^$</XML_NAMESPACE> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>.*</NAME> - <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> - </AND> - </match> - <order>ANDROID_ATTRIBUTE_ORDER</order> - </rule> - </section> - <section> - <rule> - <match> - <AND> - <NAME>.*</NAME> - <XML_NAMESPACE>.*</XML_NAMESPACE> - </AND> - </match> - <order>BY_NAME</order> - </rule> - </section> - </rules> - </arrangement> - </codeStyleSettings> - <codeStyleSettings language="kotlin"> - <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> - <option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" /> - <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> - <option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" /> - <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> - <indentOptions> - <option name="CONTINUATION_INDENT_SIZE" value="4" /> - </indentOptions> - </codeStyleSettings> - </code_scheme> -</component>
\ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project version="4"> - <component name="VcsDirectoryMappings"> - <mapping directory="" vcs="Git" /> - </component> -</project>
\ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 7bd509f..69dabb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ jdk: - oraclejdk8 env: global: - - ANDROID_API=28 + - ANDROID_API=29 - EMULATOR_API=19 - - ANDROID_BUILD_TOOLS=28.0.3 + - ANDROID_BUILD_TOOLS=29.0.0 git: depth: 500 android: @@ -15,28 +15,15 @@ android: - tools - build-tools-$ANDROID_BUILD_TOOLS - android-$ANDROID_API -# - android-$EMULATOR_API - extra-android-m2repository - extra-google-m2repository -# - sys-img-armeabi-v7a-addon-google_apis-google-$ANDROID_API_LEVEL -# - sys-img-armeabi-v7a-addon-google_apis-google-$EMULATOR_API_LEVEL licenses: - ".+" -#before_script: -#- echo "y" | android update sdk -a --no-ui --filter android-$EMULATOR_API -#- echo "y" | android update sdk -a --no-ui --filter sys-img-armeabi-v7a-android-$EMULATOR_API -#- android list targets | grep -E '^id:' | awk -F '"' '{$1=""; print $2}' # list all targets -#- echo no | android create avd --force -n test -t android-$EMULATOR_API --abi armeabi-v7a -#- emulator -avd test -skin -no-audio -no-window & -#- android-wait-for-emulator -#- adb shell settings put global window_animation_scale 0 & -#- adb shell settings put global transition_animation_scale 0 & -#- adb shell settings put global animator_duration_scale 0 & -#- adb shell input keyevent 82 & script: - chmod +x gradlew - "./gradlew --quiet androidGitVersion" -- if [[ "$TRAVIS_BRANCH" == "master" ]]; then ./gradlew lintRelease publishRelease; else ./gradlew lintRelease test; fi +- if [[ "$TRAVIS_BRANCH" == "master" ]]; then ./gradlew lintRelease publishRelease; + else ./gradlew lintRelease testReleaseUnitTest; fi branches: except: - gh-pages @@ -45,17 +32,17 @@ notifications: email: false slack: rooms: - - pitchedapps:G5OB9U1vsDxy9mxt0Nt6gbFu#kau + secure: kt/n/Mn7qbRKg6OXFLY2oxon9mjdrowuGnOavGTsXr7OQDKNp/PMSanIhxYJwkU8at5jO2Zlyjh/orksBGy6ERX4+AMbTWlDH0n/F5E7hHwxDABBup78VgU+pBgbdUrF5taUkrODcl3ytP3Pwx5MfSrdw5v6IKR0P00Tpwo0paeurBDp9XnG2DhOn3diJNH1YpdHuIKoPnLORFnUkTAWdGqQkfQFY64idbD9JO+/KODG7Y1KDtrWgg4x8FrOLAaVRQddISxyBpOoCiThF3k8nbQztAwhDyJWber0xWNuTwlKKfTFQvxkUkjb55jxRePFQTmgw/u+ip/fnBfVx9l/BAc1Rj2vRVRoAWfmWaBRQU05lZHeI4tvuuBmBxhT2qHeexdXYxPOugFHrlG34u6m1ZiSOQ5mcOxmMFaK2wjonL6haTqN5Uzm7ZX3y6LzIihZi5SzOAnfjUzGpEkw3uh+h7tNRXNpu4uk//GTd2gO/CHlIr+6Hm70RihN32ns5++EmbyP3rJ/6Xwk1tYJMRIJWpU+8kdadm9DZmsB1TPb/u9Zjdaq2pdkcyP5huZvZIdcPjiCkAiSuwtF+pxjd5Ygch7U/W/H73zDwo7dKknt40DOdv+1oiPstiaoDCgLvWiMDaszG15YKlTx8ggbxbLZZapriOc2u9F/XmQwNiZmqMo= on_success: always on_failure: always cache: directories: - - $HOME/.m2 - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - $HOME/.android/build-cache + - "$HOME/.m2" + - "$HOME/.gradle/caches/" + - "$HOME/.gradle/wrapper/" + - "$HOME/.android/build-cache" before_install: - yes | sdkmanager "platforms;android-$ANDROID_API" - openssl aes-256-cbc -K $encrypted_12e8842891a3_key -iv $encrypted_12e8842891a3_iv -in files/kau.tar.enc -out kau.tar -d -- tar xvf kau.tar
\ No newline at end of file +- tar xvf kau.tar @@ -1,17 +1,3 @@ - Copyright 2017 Allan Wang - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -189,3 +175,27 @@ END OF TERMS AND CONDITIONS + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. @@ -8,7 +8,7 @@ This library contains small helper functions used throughout almost all of my ot <a href='https://play.google.com/store/apps/details?id=ca.allanwang.kau.sample&utm_source=github'><img alt='Get it on Google Play' width="30%" src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png'/></a> -[Changelog](docs/Changelog.md) +[Changelog](docs/Changelog.md) • [Migration](docs/Migration.md) ------------ @@ -88,26 +88,29 @@ This means that you'll need to explicitly include each submodule you'd like to u ## [Core UI](core-ui#readme) * Collection of complex views and widgets -* Includes `:core`, `:adapter` +* Includes `:core` ## [About](about#readme) * Modularized overlaying about section. Comes with a main panel, automatic lib detection, and a FAQ parser; also includes the lib strings for KAU. -* Includes `:core-ui`, `:adapter`, +* Includes `:core-ui`, `:fastadapter`, [`About Libraries`](https://github.com/mikepenz/AboutLibraries) ## [Adapter](adapter#readme) -* Kotlin bindings for the fast adapter, as well as modularized RecyclerView animations -* Includes `:core`, -[`Fast Adapter`](https://github.com/mikepenz/FastAdapter) +* RecyclerView animations +* Includes `:core` ## [Color Picker](colorpicker#readme) * Implementation of a color picker dialog with subtle transitions and a decoupled callback -* Includes `:core`, -([`Material Dialogs (commons)`](https://github.com/afollestad/material-dialogs)) +* Includes `:core` + +## [FastAdapter](fastadapter#readme) +* Kotlin bindings for the fast adapter +* Includes `:core`, `:adapter`, +[`Fast Adapter`](https://github.com/mikepenz/FastAdapter) ## [KPref Activity](kpref-activity#readme) * Fully programmatic implementation of a Preference Activity, backed by a RecyclerView -* Includes `:core`, `:adapter`, `:colorpicker` +* Includes `:core`, `:fastadapter`, `:colorpicker` ## [Media Picker](mediapicker#readme) * Fully functional image and video pickers, both as an overlay and as a requested activity. @@ -117,7 +120,7 @@ This means that you'll need to explicitly include each submodule you'd like to u ## [SearchView](searchview#readme) * Material searchview with kotlin bindings -* Includes `:core-ui`, `:adapter` +* Includes `:core-ui`, `:fastadapter` ## [Gradle Plugin](buildSrc#readme) * Gradle plugin to help facilitate versioning and other gradle functions @@ -152,11 +155,15 @@ Special thanks to the following awesome people for translating significant porti | Language | Contributors | |----------|--------------| +| Arabic | [Mohammed Qubati](https://crowdin.com/profile/Mrkqubati) | | Chinese (Simplified) | [Alcatelia](https://crowdin.com/profile/Alcatelia) | | Chinese (Traditional) | [yipinghuang](https://crowdin.com/profile/yipinghuang) • [Su, Jun-Ming](https://crowdin.com/profile/sujunmin) • [Wei](https://crowdin.com/profile/wei4green) | +| Danish | [mhtorp](https://crowdin.com/profile/mhtorp) | +| Dutch | [ItGuillaume](https://crowdin.com/profile/ltGuillaume) • [Tatum ter Kuile](https://crowdin.com/profile/Teitr) | | French | [Vincent Kulak](https://github.com/VonOx) • [Jean-Philippe Gravel](https://crowdin.com/profile/wokija) | | Galician | [Xesús M. Mosquera](https://twitter.com/xesusmmc?lang=en) | | German | [Bushido1992](https://forum.xda-developers.com/member.php?u=5179246) • [Marcel Soehnchen](https://crowdin.com/profile/msoehnchen) • [3LD0mi HA](https://forum.xda-developers.com/member.php?u=5860523) | +| Hungarian | [János Erkli](https://crowdin.com/profile/erklijani0521) | | Indonesian | [M. Angga Ariska](https://www.youtube.com/channel/UCkqMw81s2aw7bYO-U2YhD7w) | | Italian | [Bonnee](https://github.com/Bonnee) | | Korean | [잇스테이크](https://crowdin.com/profile/bexco2010) | @@ -166,8 +173,10 @@ Special thanks to the following awesome people for translating significant porti | Portuguese (Brazilian) | [TheusKhan](https://crowdin.com/profile/TheusKhan) | | Serbian | [Nikola Radmanović](https://crowdin.com/profile/nikoladradmanovic) | | Spanish | [Jahir Fiquitiva](https://jahirfiquitiva.me/) • [Nefi Salazar](https://plus.google.com/u/0/105547968033551087431)| +| Swedish | [Artswitcher](https://crowdin.com/profile/Artswitcher) | | Thai | [Thanawat Hanthong](https://crowdin.com/profile/peet6015) | | Turkish | [zuma17](https://crowdin.com/profile/zuma17) | +| Ukrainian | [Вадим Жушман](https://crowdin.com/profile/android54544) | | Vietnamese | [Alienz](https://crowdin.com/profile/alienyd) | The full activity stream for the translations can be found [here](https://crowdin.com/project/kotlin-android-utils/activity_stream) diff --git a/about/build.gradle b/about/build.gradle index 5a2a395..b970530 100644 --- a/about/build.gradle +++ b/about/build.gradle @@ -8,7 +8,7 @@ android { dependencies { implementation project(':core-ui') - implementation project(':adapter') + implementation project(':fastadapter') api kau.Dependencies.aboutLibraries } diff --git a/about/src/main/kotlin/ca/allanwang/kau/about/AboutPanelDelegate.kt b/about/src/main/kotlin/ca/allanwang/kau/about/AboutPanelDelegate.kt index 814fd64..aae6cb0 100644 --- a/about/src/main/kotlin/ca/allanwang/kau/about/AboutPanelDelegate.kt +++ b/about/src/main/kotlin/ca/allanwang/kau/about/AboutPanelDelegate.kt @@ -100,7 +100,7 @@ abstract class AboutPanelRecycler : AboutPanelContract { recycler.adapter = adapter recycler.itemAnimator = KauAnimator( addAnimator = FadeScaleAnimatorAdd(scaleFactor = 0.7f, itemDelayFactor = 0.2f), - changeAnimator = NoAnimatorChange() + changeAnimator = NoAnimatorChange ).apply { addDuration = 300; interpolator = AnimHolder.decelerateInterpolator(recycler.context) } } diff --git a/about/src/main/res/values-ar-rSA/strings_about.xml b/about/src/main/res/values-ar-rSA/strings_about.xml new file mode 100644 index 0000000..f80ee4d --- /dev/null +++ b/about/src/main/res/values-ar-rSA/strings_about.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<!--Generated by crowdin.com--> +<resources> + <string name="kau_about_libraries_intro">لن يتم تمكين هذا التطبيق بدون المكتبات الكبيرة التالية.</string> + <string name="kau_about_faq_intro">الأسئلة الشائعة</string> +</resources> diff --git a/adapter/README.md b/adapter/README.md index a6ffb6d..f3beaff 100644 --- a/adapter/README.md +++ b/adapter/README.md @@ -1,20 +1,6 @@ # KAU :adapter -Collection of kotlin bindings and custom IItems for [Fast Adapter](https://github.com/mikepenz/FastAdapter) - -## KauIItems - -Abstract base that extends `AbstractIItems` and contains the arguments `(layoutRes, ViewHolder lambda, idRes)` in that order. -Those variables are used to override the default abstract functions. -If a layout is only used for one item, it may also be used as the id, which you may leave blank in this case. -The ViewHolder lambda is typically of the form `::ViewHolder` -Where you will have a nested class `ViewHolder(v: View) : RecyclerView.ViewHolder(v)` - -## IItem Templates - -* CardIItem - generic all encompassing card item with a title, description, imageview, and button. -All items except for the title are optional. -* HeaderIItem - simple title container with a big top margin +Helpers dealing with recyclerviews and adapters ## KauAnimator diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/animators/NoAnimator.kt b/adapter/src/main/kotlin/ca/allanwang/kau/animators/NoAnimator.kt index cca8a25..52b6123 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/animators/NoAnimator.kt +++ b/adapter/src/main/kotlin/ca/allanwang/kau/animators/NoAnimator.kt @@ -42,7 +42,7 @@ class NoAnimatorRemove(override var itemDelayFactor: Float = 0f) : KauAnimatorRe override fun getDelay(remove: Long, move: Long, change: Long): Long = 0L } -class NoAnimatorChange : KauAnimatorChange { +object NoAnimatorChange : KauAnimatorChange { override fun changeOldAnimation( holder: RecyclerView.ViewHolder, diff --git a/adapter/src/main/res/values/dimens.xml b/adapter/src/main/res/values/dimens.xml deleted file mode 100644 index 193940e..0000000 --- a/adapter/src/main/res/values/dimens.xml +++ /dev/null @@ -1,3 +0,0 @@ -<resources> - <dimen name="kau_color_circle_size">56dp</dimen> -</resources> diff --git a/buildSrc/src/main/kotlin/kau/Dependencies.kt b/buildSrc/src/main/kotlin/kau/Dependencies.kt index 6634851..d1e2b89 100644 --- a/buildSrc/src/main/kotlin/kau/Dependencies.kt +++ b/buildSrc/src/main/kotlin/kau/Dependencies.kt @@ -5,6 +5,12 @@ package kau */ object Dependencies { @JvmStatic + fun kau(version: String) = "ca.allanwang:kau:$version" + + @JvmStatic + fun kau(type: String, version: String) = "ca.allanwang.kau:$type:$version" + + @JvmStatic fun kotlin(type: String) = "org.jetbrains.kotlin:kotlin-$type:${Versions.kotlin}" @JvmField diff --git a/buildSrc/src/main/kotlin/kau/Versions.kt b/buildSrc/src/main/kotlin/kau/Versions.kt index d3718b6..f3fbd09 100644 --- a/buildSrc/src/main/kotlin/kau/Versions.kt +++ b/buildSrc/src/main/kotlin/kau/Versions.kt @@ -3,10 +3,10 @@ package kau object Versions { const val coreMinSdk = 19 const val minSdk = 21 - const val targetSdk = 28 + const val targetSdk = 29 // https://developer.android.com/studio/releases/build-tools - const val buildTools = "28.0.3" + const val buildTools = "29.0.0" // https://mvnrepository.com/artifact/androidx.appcompat/appcompat?repo=google const val appcompat = "1.0.2" @@ -24,10 +24,10 @@ object Versions { const val constraintLayout = "1.1.3" // https://kotlinlang.org/docs/reference/using-gradle.html - const val kotlin = "1.3.31" + const val kotlin = "1.3.41" // https://github.com/Kotlin/kotlinx.coroutines/releases - const val coroutines = "1.3.0-M1" + const val coroutines = "1.3.0-RC" // https://github.com/mikepenz/AboutLibraries/releases const val aboutLibraries = "6.2.3" @@ -36,13 +36,13 @@ object Versions { const val blurry = "3.0.0" // https://github.com/mikepenz/FastAdapter#using-maven - const val fastAdapter = "4.0.0" + const val fastAdapter = "4.1.0-b01" // https://github.com/bumptech/glide/releases const val glide = "4.9.0" // https://github.com/mikepenz/Android-Iconics#1-provide-the-gradle-dependency - const val iconics = "4.0.0" + const val iconics = "4.0.1-b01" const val iconicsGoogle = "3.0.1.4" const val iconicsMaterial = "2.2.0.6" const val iconicsCommunity = "3.5.95.1" @@ -71,7 +71,7 @@ object Versions { const val bugsnagPlugin="4.1.1" // https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google - const val gradlePlugin = "3.4.1" + const val gradlePlugin = "3.5.0-rc01" // https://github.com/dcendents/android-maven-gradle-plugin/releases const val mavenPlugin = "2.1" // https://github.com/Triple-T/gradle-play-publisher/releases diff --git a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt index e748677..29257d8 100644 --- a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt +++ b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/CircleView.kt @@ -238,4 +238,4 @@ class CircleView @JvmOverloads constructor(context: Context, attrs: AttributeSet @ColorInt fun shiftColorUp(@ColorInt color: Int): Int = shiftColor(color, 1.1f) } -}
\ No newline at end of file +} diff --git a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt index 02a1fff..487ed76 100644 --- a/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt +++ b/colorpicker/src/main/kotlin/ca/allanwang/kau/colorpicker/ColorPickerDialog.kt @@ -63,4 +63,4 @@ fun MaterialDialog.kauColorChooser(c: ColorContract) { selection = c.callback ) positiveButton(R.string.kau_done) -}
\ No newline at end of file +} diff --git a/core-ui/build.gradle b/core-ui/build.gradle index c2732c6..23d601d 100644 --- a/core-ui/build.gradle +++ b/core-ui/build.gradle @@ -4,8 +4,6 @@ apply from: '../android-lib.gradle' dependencies { api project(':core') - implementation project(':adapter') - } apply from: '../artifacts.gradle' 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 f4578f2..2cf005a 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 @@ -50,7 +50,7 @@ class ElasticDragDismissFrameLayout @JvmOverloads constructor( ) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) { // configurable attribs - var dragDismissDistance = context.dimen(R.dimen.kau_drag_dismiss_distance).dpToPx + var dragDismissDistance = context.dimen(R.dimen.kau_drag_dismiss_distance) var dragDismissFraction = -1f var dragDismissScale = 1f set(value) { diff --git a/core-ui/src/main/res-public/values/public.xml b/core-ui/src/main/res-public/values/public.xml index af7ce44..71657d6 100644 --- a/core-ui/src/main/res-public/values/public.xml +++ b/core-ui/src/main/res-public/values/public.xml @@ -1,8 +1,8 @@ -<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<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_recycler_detached_background' type='layout' /> - <public name='kau_elastic_recycler_activity' type='layout' /> <public name='kau_recycler_textslider' type='layout' /> + <public name='kau_elastic_recycler_activity' type='layout' /> <public name='Kau.Translucent' type='style' /> <public name='Kau.Translucent.NoAnimation' type='style' /> <public name='Kau.Translucent.SlideBottom' type='style' /> diff --git a/core/README.md b/core/README.md index b9a10f5..b1140bf 100644 --- a/core/README.md +++ b/core/README.md @@ -71,6 +71,14 @@ object MyPrefs : KPref() { Notice that it is a `val` and takes no default. It will return true the first time and false for all subsequent calls. +### KPref Testing + +If your android components can be tested without an emulator, you can also modify KPref to operate without shared preferences. +To do so, call `KPref(KPrefBuilderInMemory)` when creating your preferences. +This variant does not pass updates to the shared preferences. +To set the builder, you may wish to use dependency injection or service locators to supply the builder and the KPref. +In that case, your preferences would be a class instead of an object. + ## Changelog XML Create an xml resource with the following structure: diff --git a/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt index 29f5af1..143b83f 100644 --- a/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt +++ b/core/src/androidTest/kotlin/ca/allanwang/kau/kpref/KPrefTest.kt @@ -24,8 +24,6 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue /** * Created by Allan Wang on 2017-08-01. @@ -34,19 +32,24 @@ import kotlin.test.assertTrue @MediumTest class KPrefTest { - lateinit var pref: TestPref + lateinit var androidPref: TestPref + lateinit var memPref: TestPref - class TestPref : KPref() { + class TestPref(builder: KPrefBuilder) : KPref(builder) { init { initialize(ApplicationProvider.getApplicationContext<Context>(), "kpref_test_${System.currentTimeMillis()}") } + var postSetterCount: Int = 0 + var one by kpref("one", 1) var two by kpref("two", 2f) - var `true` by kpref("true", true) + var `true` by kpref("true", true, postSetter = { + postSetterCount++ + }) var hello by kpref("hello", "hello") @@ -57,51 +60,67 @@ class KPrefTest { @Before fun init() { - pref = TestPref() - pref.sp.edit().clear().commit() + androidPref = TestPref(KPrefBuilderAndroid) + androidPref.sp.edit().clear().commit() + memPref = TestPref(KPrefBuilderInMemory) + } + + private fun pref(action: TestPref.() -> Unit) { + androidPref.action() + memPref.action() + } + + private fun <T> assertPrefEquals(expected: T, actual: TestPref.() -> T, message: String? = null) { + assertEquals(expected, androidPref.actual(), "Android KPrefs: $message") + assertEquals(expected, memPref.actual(), "In Mem KPrefs: $message") } @Test fun getDefaults() { - assertEquals(1, pref.one) - assertEquals(2f, pref.two) - assertEquals(true, pref.`true`) - assertEquals("hello", pref.hello) - assertEquals(3, pref.set.size) - assertTrue(pref.set.contains("po")) - assertTrue(pref.set.contains("ta")) - assertTrue(pref.set.contains("to")) - assertEquals(0, pref.sp.all.size, "Defaults should not be set automatically") + assertPrefEquals(1, { one }) + assertPrefEquals(2f, { two }) + assertPrefEquals(true, { `true` }) + assertPrefEquals("hello", { hello }) + assertPrefEquals(3, { set.size }) + assertPrefEquals(setOf("po", "ta", "to"), { set }) + assertEquals(0, androidPref.sp.all.size, "Defaults should not be set automatically") } @Test fun setter() { - assertEquals(1, pref.one) - pref.one = 2 - assertEquals(2, pref.one) - pref.hello = "goodbye" - assertEquals("goodbye", pref.hello) - assertEquals(pref.hello, pref.sp.getString("hello", "hello")) - assertEquals(2, pref.sp.all.size) + assertPrefEquals(1, { one }) + pref { one = 2 } + assertPrefEquals(2, { one }) + pref { hello = "goodbye" } + assertPrefEquals("goodbye", { hello }) + assertEquals(androidPref.hello, androidPref.sp.getString("hello", "badfallback")) + assertEquals(2, androidPref.sp.all.size) } @SuppressLint("CommitPrefEdits") @Test fun reset() { - pref.one = 2 - assertEquals(2, pref.one) - assertEquals(6, pref.prefMap.size, "Prefmap does not have all elements") - pref.reset() //only invalidates our lazy delegate; doesn't change the actual pref - assertEquals(2, pref.one, "Kpref did not properly fetch from shared prefs") - pref.sp.edit().putInt("one", -1).commit() - assertEquals(2, pref.one, "Lazy kpref should still retain old value") - pref.reset() - assertEquals(-1, pref.one, "Kpref did not refetch from shared prefs upon reset") + pref { one = 2 } + assertPrefEquals(2, { one }) + assertPrefEquals(6, { prefMap.size }, "Prefmap does not have all elements") + pref { reset() } //only invalidates our lazy delegate; doesn't change the actual pref + assertPrefEquals(2, { one }, "Kpref did not properly fetch from shared prefs") + // Android pref only + androidPref.sp.edit().putInt("one", -1).commit() + assertEquals(2, androidPref.one, "Lazy kpref should still retain old value") + androidPref.reset() + assertEquals(-1, androidPref.one, "Kpref did not refetch from shared prefs upon reset") } @Test fun single() { - assertTrue(pref.oneShot) - assertFalse(pref.oneShot) + assertPrefEquals(true, { oneShot }) + assertPrefEquals(false, { androidPref.oneShot }) + } + + @Test + fun postSetter() { + pref { `true` = true } + assertPrefEquals(1, { postSetterCount }, "Post setter was not called") } } diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt index 7a6330f..fc7a76a 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPref.kt @@ -36,14 +36,18 @@ import ca.allanwang.kau.logging.KL * You may optionally override [deleteKeys]. This will be called on initialization * And delete all keys returned from that method */ -open class KPref { +open class KPref(builder: KPrefBuilder = KPrefBuilderAndroid) : KPrefBuilder by builder { lateinit var PREFERENCE_NAME: String lateinit var sp: SharedPreferences - fun initialize(c: Context, preferenceName: String) { + fun initialize( + c: Context, + preferenceName: String, + sharedPrefs: SharedPreferences = c.applicationContext.getSharedPreferences(preferenceName, Context.MODE_PRIVATE) + ) { PREFERENCE_NAME = preferenceName - sp = c.applicationContext.getSharedPreferences(preferenceName, Context.MODE_PRIVATE) + sp = sharedPrefs KL.d { "Shared Preference $preferenceName has been initialized" } val toDelete = deleteKeys() if (toDelete.isNotEmpty()) { diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt new file mode 100644 index 0000000..4dd3012 --- /dev/null +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefBuilder.kt @@ -0,0 +1,75 @@ +package ca.allanwang.kau.kpref + +interface KPrefBuilder { + fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit = {}): KPrefDelegate<Boolean> + + fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit = {}): KPrefDelegate<Float> + + @Deprecated( + "Double is not supported in SharedPreferences; cast to float yourself", + ReplaceWith("kpref(key, fallback.toFloat(), postSetter)"), + DeprecationLevel.WARNING + ) + fun KPref.kpref(key: String, fallback: Double, postSetter: (value: Float) -> Unit = {}): KPrefDelegate<Float> = + kpref(key, fallback.toFloat(), postSetter) + + fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit = {}): KPrefDelegate<Int> + + fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit = {}): KPrefDelegate<Long> + + fun KPref.kpref( + key: String, + fallback: Set<String>, + postSetter: (value: Set<String>) -> Unit = {} + ): KPrefDelegate<Set<String>> + + fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit = {}): KPrefDelegate<String> + + fun KPref.kprefSingle(key: String): KPrefSingleDelegate +} + +object KPrefBuilderAndroid : KPrefBuilder { + + override fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit) = + KPrefDelegateAndroid(key, fallback, this, KPrefBooleanTransaction, postSetter) + + override fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit) = + KPrefDelegateAndroid(key, fallback, this, KPrefFloatTransaction, postSetter) + + override fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit) = + KPrefDelegateAndroid(key, fallback, this, KPrefIntTransaction, postSetter) + + override fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit) = + KPrefDelegateAndroid(key, fallback, this, KPrefLongTransaction, postSetter) + + override fun KPref.kpref(key: String, fallback: Set<String>, postSetter: (value: Set<String>) -> Unit) = + KPrefDelegateAndroid(key, fallback, this, KPrefSetTransaction, postSetter) + + override fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit) = + KPrefDelegateAndroid(key, fallback, this, KPrefStringTransaction, postSetter) + + override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateAndroid(key, this) +} + +object KPrefBuilderInMemory : KPrefBuilder { + + override fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit) = + KPrefDelegateInMemory(key, fallback, this, postSetter) + + override fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit) = + KPrefDelegateInMemory(key, fallback, this, postSetter) + + override fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit) = + KPrefDelegateInMemory(key, fallback, this, postSetter) + + override fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit) = + KPrefDelegateInMemory(key, fallback, this, postSetter) + + override fun KPref.kpref(key: String, fallback: Set<String>, postSetter: (value: Set<String>) -> Unit) = + KPrefDelegateInMemory(key, fallback, this, postSetter) + + override fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit) = + KPrefDelegateInMemory(key, fallback, this, postSetter) + + override fun KPref.kprefSingle(key: String) = KPrefSingleDelegateInMemory(key, this) +}
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt index 9813f24..684b139 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefDelegate.kt @@ -17,32 +17,6 @@ package ca.allanwang.kau.kpref import ca.allanwang.kau.kotlin.ILazyResettable -fun KPref.kpref(key: String, fallback: Boolean, postSetter: (value: Boolean) -> Unit = {}) = - KPrefDelegate(key, fallback, this, KPrefBooleanTransaction, postSetter) - -fun KPref.kpref(key: String, fallback: Float, postSetter: (value: Float) -> Unit = {}) = - KPrefDelegate(key, fallback, this, KPrefFloatTransaction, postSetter) - -@Deprecated( - "Double is not supported in SharedPreferences; cast to float yourself", - ReplaceWith("kpref(key, fallback.toFloat(), postSetter)"), - DeprecationLevel.WARNING -) -fun KPref.kpref(key: String, fallback: Double, postSetter: (value: Float) -> Unit = {}) = - kpref(key, fallback.toFloat(), postSetter) - -fun KPref.kpref(key: String, fallback: Int, postSetter: (value: Int) -> Unit = {}) = - KPrefDelegate(key, fallback, this, KPrefIntTransaction, postSetter) - -fun KPref.kpref(key: String, fallback: Long, postSetter: (value: Long) -> Unit = {}) = - KPrefDelegate(key, fallback, this, KPrefLongTransaction, postSetter) - -fun KPref.kpref(key: String, fallback: Set<String>, postSetter: (value: Set<String>) -> Unit = {}) = - KPrefDelegate(key, fallback, this, KPrefSetTransaction, postSetter) - -fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Unit = {}) = - KPrefDelegate(key, fallback, this, KPrefStringTransaction, postSetter) - /** * Created by Allan Wang on 2017-06-07. * @@ -50,13 +24,20 @@ fun KPref.kpref(key: String, fallback: String, postSetter: (value: String) -> Un * Contains a unique key for the shared preference as well as a nonnull fallback item * Also contains an optional mutable postSetter that will be called every time a new value is given */ -class KPrefDelegate<T> internal constructor( + +interface KPrefDelegate<T> : ILazyResettable<T> { + operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) +} + +class KPrefException(message: String) : IllegalAccessException(message) + +class KPrefDelegateAndroid<T> internal constructor( private val key: String, private val fallback: T, private val pref: KPref, private val transaction: KPrefTransaction<T>, private var postSetter: (value: T) -> Unit = {} -) : ILazyResettable<T> { +) : KPrefDelegate<T> { private object UNINITIALIZED @@ -67,28 +48,26 @@ class KPrefDelegate<T> internal constructor( init { if (pref.prefMap.containsKey(key)) throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") - pref.prefMap[key] = this@KPrefDelegate + pref.prefMap[key] = this@KPrefDelegateAndroid } override fun invalidate() { _value = UNINITIALIZED } + @Suppress("UNCHECKED_CAST") override val value: T get() { val _v1 = _value if (_v1 !== UNINITIALIZED) - @Suppress("UNCHECKED_CAST") return _v1 as T return synchronized(lock) { val _v2 = _value if (_v2 !== UNINITIALIZED) { - @Suppress("UNCHECKED_CAST") _v2 as T } else { _value = transaction.get(pref.sp, key, fallback) - @Suppress("UNCHECKED_CAST") _value as T } } @@ -98,7 +77,7 @@ class KPrefDelegate<T> internal constructor( override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." - operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { + override operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { _value = t val editor = pref.sp.edit() transaction.set(editor, key, t) @@ -107,4 +86,53 @@ class KPrefDelegate<T> internal constructor( } } -class KPrefException(message: String) : IllegalAccessException(message) +class KPrefDelegateInMemory<T> internal constructor( + private val key: String, + private val fallback: T, + private val pref: KPref, + private var postSetter: (value: T) -> Unit = {} +) : KPrefDelegate<T> { + + private object UNINITIALIZED + + @Volatile + private var _value: Any? = UNINITIALIZED + private val lock = this + + init { + if (pref.prefMap.containsKey(key)) + throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + pref.prefMap[key] = this + } + + override fun invalidate() { + // No op + } + + @Suppress("UNCHECKED_CAST") + override val value: T + get() { + val _v1 = _value + if (_v1 !== UNINITIALIZED) + return _v1 as T + + return synchronized(lock) { + val _v2 = _value + if (_v2 !== UNINITIALIZED) { + _v2 as T + } else { + _value = fallback + _value as T + } + } + } + + override fun isInitialized(): Boolean = _value !== UNINITIALIZED + + override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." + + override operator fun setValue(any: Any, property: kotlin.reflect.KProperty<*>, t: T) { + _value = t + postSetter(t) + } +} diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt index 204e07e..ef59e78 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefSingleDelegate.kt @@ -17,8 +17,6 @@ package ca.allanwang.kau.kpref import ca.allanwang.kau.kotlin.ILazyResettable -fun KPref.kprefSingle(key: String) = KPrefSingleDelegate(key, this) - /** * Created by Allan Wang on 2017-06-07. * @@ -27,17 +25,21 @@ fun KPref.kprefSingle(key: String) = KPrefSingleDelegate(key, this) * All subsequent retrievals will be [false] * This is useful for one time toggles such as showcasing items */ -class KPrefSingleDelegate internal constructor(private val key: String, private val pref: KPref, lock: Any? = null) : - ILazyResettable<Boolean> { +interface KPrefSingleDelegate : ILazyResettable<Boolean> + +class KPrefSingleDelegateAndroid internal constructor( + private val key: String, + private val pref: KPref +) : KPrefSingleDelegate { @Volatile private var _value: Boolean? = null - private val lock = lock ?: this + private val lock = this init { if (pref.prefMap.containsKey(key)) throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") - pref.prefMap.put(key, this@KPrefSingleDelegate) + pref.prefMap[key] = this } override fun invalidate() { @@ -47,9 +49,9 @@ class KPrefSingleDelegate internal constructor(private val key: String, private override val value: Boolean get() { val _v1 = _value - if (_v1 != null) + if (_v1 != null) { return _v1 - + } return synchronized(lock) { val _v2 = _value if (_v2 != null) { @@ -69,3 +71,43 @@ class KPrefSingleDelegate internal constructor(private val key: String, private override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." } + +class KPrefSingleDelegateInMemory internal constructor( + private val key: String, + private val pref: KPref +) : KPrefSingleDelegate { + @Volatile + private var _value: Boolean? = null + private val lock = this + + init { + if (pref.prefMap.containsKey(key)) + throw KPrefException("$key is already used elsewhere in preference ${pref.PREFERENCE_NAME}") + pref.prefMap[key] = this + } + + override fun invalidate() { + // No op + } + + override val value: Boolean + get() { + val _v1 = _value + if (_v1 != null) { + return _v1 + } + return synchronized(lock) { + val _v2 = _value + if (_v2 != null) { + _v2 + } else { + _value = false + true + } + } + } + + override fun isInitialized(): Boolean = _value != null + + override fun toString(): String = if (isInitialized()) value.toString() else "Lazy kPref $key not initialized yet." +}
\ No newline at end of file diff --git a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt index 1070e11..3f8fe28 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/kpref/KPrefTransaction.kt @@ -60,7 +60,7 @@ internal object KPrefFloatTransaction : KPrefTransaction<Float> { internal object KPrefStringTransaction : KPrefTransaction<String> { override fun get(prefs: SharedPreferences, key: String, fallback: String) = - prefs.getString(key, fallback) + prefs.getString(key, fallback) ?: "" override fun set(editor: SharedPreferences.Editor, key: String, data: String) { editor.putString(key, data) diff --git a/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java b/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java index ac7fb7e..f6e907a 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java +++ b/core/src/main/kotlin/ca/allanwang/kau/swipe/ViewDragHelper.java @@ -25,7 +25,7 @@ import static ca.allanwang.kau.swipe.SwipeBackHelperKt.SWIPE_EDGE_TOP; * of useful operations and state tracking for allowing a user to drag and reposition * views within their parent ViewGroup. * <p> - * This is an extension of {@link androidx.core.widget.ViewDragHelper} + * This is an extension of {@link androidx.customview.widget.ViewDragHelper} * Along with additional methods defined in {@link ViewDragHelperExtras} */ class ViewDragHelper implements ViewDragHelperExtras { diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt index 40c1c72..b857eb0 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/BundleUtils.kt @@ -89,16 +89,6 @@ fun bundleOf(vararg params: kotlin.Pair<String, Any?>): Bundle { } /** - * Adds transition bundle if context is activity and build is lollipop+ - */ -@SuppressLint("NewApi") -fun Bundle.withSceneTransitionAnimation(context: Context) { - if (context !is Activity || !buildIsLollipopAndUp) return - val options = ActivityOptions.makeSceneTransitionAnimation(context) - putAll(options.toBundle()) -} - -/** * Given the parent view and map of view ids to tags, * create a scene transition animation */ @@ -112,7 +102,7 @@ fun Bundle.withSceneTransitionAnimation(parent: View, data: Map<Int, String>) = * create a scene transition animation */ @SuppressLint("NewApi") -fun Bundle.withSceneTransitionAnimation(context: Context, data: Map<out View, String>) { +fun Bundle.withSceneTransitionAnimation(context: Context, data: Map<out View, String> = emptyMap()) { if (context !is Activity || !buildIsLollipopAndUp) return val options = ActivityOptions.makeSceneTransitionAnimation( context, diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt index bbb8953..3de0297 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ColorUtils.kt @@ -20,7 +20,6 @@ import android.content.Context import android.content.res.ColorStateList import android.graphics.Color import android.graphics.PorterDuff -import android.graphics.drawable.Drawable import android.os.Build import android.widget.CheckBox import android.widget.EditText @@ -28,13 +27,13 @@ import android.widget.ImageButton import android.widget.ProgressBar import android.widget.RadioButton import android.widget.SeekBar -import android.widget.TextView import androidx.annotation.ColorInt import androidx.annotation.FloatRange import androidx.annotation.IntRange import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.Toolbar import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.view.ViewCompat import com.afollestad.materialdialogs.R import java.util.Random @@ -248,37 +247,16 @@ fun Context.textColorStateList(@ColorInt color: Int): ColorStateList { return ColorStateList(states, colors) } -@SuppressLint("RestrictedApi") +/** + * Note that this does not tint the cursor, as there is no public api to do so. + */ fun EditText.tint(@ColorInt color: Int) { val editTextColorStateList = context.textColorStateList(color) if (this is AppCompatEditText) { - supportBackgroundTintList = editTextColorStateList + ViewCompat.setBackgroundTintList(this, editTextColorStateList) } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { backgroundTintList = editTextColorStateList } - tintCursor(color) -} - -fun EditText.tintCursor(@ColorInt color: Int) { - try { - val fCursorDrawableRes = TextView::class.java.getDeclaredField("mCursorDrawableRes") - fCursorDrawableRes.isAccessible = true - val mCursorDrawableRes = fCursorDrawableRes.getInt(this) - val fEditor = TextView::class.java.getDeclaredField("mEditor") - fEditor.isAccessible = true - val editor = fEditor.get(this) - val clazz = editor.javaClass - val fCursorDrawable = clazz.getDeclaredField("mCursorDrawable") - fCursorDrawable.isAccessible = true - val drawables: Array<Drawable> = Array(2, { - val drawable = context.drawable(mCursorDrawableRes) - drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN) - drawable - }) - fCursorDrawable.set(editor, drawables) - } catch (e: Exception) { - e.printStackTrace() - } } fun Toolbar.tint(@ColorInt color: Int, tintTitle: Boolean = true) { 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 e8680dc..d002fb8 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ContextUtils.kt @@ -239,7 +239,7 @@ fun Context.hasPermission(permissions: String) = !buildIsMarshmallowAndUp || Con fun Context.copyToClipboard(text: String?, label: String = "Copied Text", showToast: Boolean = true) { val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - clipboard.primaryClip = ClipData.newPlainText(label, text ?: "") + clipboard.setPrimaryClip(ClipData.newPlainText(label, text ?: "")) if (showToast) toast(R.string.kau_text_copied) } diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt index 57a9921..4d6ee54 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/CoroutineUtils.kt @@ -18,6 +18,7 @@ package ca.allanwang.kau.utils import android.content.Context import android.os.Handler import android.os.Looper +import ca.allanwang.kau.internal.KauBaseActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.android.asCoroutineDispatcher @@ -43,11 +44,11 @@ object ContextHelper : CoroutineScope { } /** - * Most context items implement [CoroutineScope] by default. + * Most context items implement [CoroutineScope] by default (through [KauBaseActivity]). * We will add a fallback just in case. * It is expected that the scope returned always has the Android main dispatcher as part of the context. */ -internal inline val Context.ctxCoroutine: CoroutineScope +inline val Context.ctxCoroutine: CoroutineScope get() = this as? CoroutineScope ?: ContextHelper /** diff --git a/core/src/main/res-public/values-ar-rSA/strings_commons.xml b/core/src/main/res-public/values-ar-rSA/strings_commons.xml new file mode 100644 index 0000000..efaa623 --- /dev/null +++ b/core/src/main/res-public/values-ar-rSA/strings_commons.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!--Generated by crowdin.com--> +<!-- +A collection of common string values +Most resources are verbatim and x represents a formatted item +--> +<resources> + <string name="kau_about_app">عن التطبيق</string> + <string name="kau_about_x">حول %s</string> + <string name="kau_add_account">إضافة حساب</string> + <string name="kau_back">العودة</string> + <string name="kau_cancel">إلغاء</string> + <string name="kau_changelog">سجل التغييرات</string> + <string name="kau_close">إغلاق</string> + <string name="kau_contact_us">التواصل معنا</string> + <string name="kau_copy">نسخ</string> + <string name="kau_custom">مخصص</string> + <string name="kau_dark">مظلم</string> + <string name="kau_default">الافتراضي</string> + <string name="kau_do_not_show_again">لا تظهر مجدداً</string> + <string name="kau_done">تم</string> + <string name="kau_error">خطأ</string> + <string name="kau_exit">خروج</string> + <string name="kau_exit_confirmation">هل أنت متأكد بأنك تريد الخروج؟</string> + <string name="kau_exit_confirmation_x">هل أنت متأكد بأنك تريد الخروج %s؟</string> + <string name="kau_glass">زجاجي</string> + <string name="kau_got_it">فهمت</string> + <string name="kau_great">رائع</string> + <string name="kau_hide">إخفاء</string> + <string name="kau_light">فاتح</string> + <string name="kau_login">تسجيل الدخول</string> + <string name="kau_logout">تسجيل الخروج</string> + <string name="kau_logout_confirm_as_x">هل أنت متأكد بأنك تريد تسجيل الخروج %s؟</string> + <string name="kau_manage_account">إدارة الحساب</string> + <string name="kau_maybe">ربما</string> + <string name="kau_menu">القائمة</string> + <string name="kau_no">لا</string> + <string name="kau_no_results_found">لم يتم العثور على نتائج</string> + <string name="kau_none">لا يوجد</string> + <string name="kau_ok">حسناً</string> + <string name="kau_play_store">Google play</string> + <string name="kau_rate">تقييم</string> + <string name="kau_report_bug">الإبلاغ عن خطأ</string> + <string name="kau_search">البحث</string> + <string name="kau_send_feedback">إرسال ملاحظات</string> + <string name="kau_send_via">الإرسال عبر</string> + <string name="kau_settings">الاعدادات</string> + <string name="kau_share">المشاركة</string> + <string name="kau_text_copied">تم نسخ النص إلى الحافظة.</string> + <string name="kau_thank_you">شكراً</string> + <string name="kau_uh_oh">أوبس</string> + <string name="kau_warning">تحذير</string> + <string name="kau_yes">نعم</string> + <string name="kau_permission_denied">الإذن مرفوض</string> +</resources> diff --git a/core/src/main/res-public/values/public.xml b/core/src/main/res-public/values/public.xml index 9761199..0b050dc 100644 --- a/core/src/main/res-public/values/public.xml +++ b/core/src/main/res-public/values/public.xml @@ -1,20 +1,27 @@ -<resources xmlns:tools='http://schemas.android.com/tools' tools:ignore='ResourceName'> +<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_enter_slide_left' type='transition' /> + <public name='kau_exit_slide_right' type='transition' /> + <public name='kau_exit_slide_bottom' type='transition' /> + <public name='kau_enter_slide_bottom' type='transition' /> + <public name='kau_enter_slide_right' type='transition' /> + <public name='kau_exit_slide_top' type='transition' /> + <public name='kau_enter_slide_top' type='transition' /> + <public name='kau_exit_slide_left' type='transition' /> + <public name='kau_selectable_white' type='drawable' /> + <public name='kau_transparent' type='drawable' /> + <public name='kau_slide_out_left_top' type='anim' /> + <public name='kau_slide_in_right' type='anim' /> + <public name='kau_slide_out_right_top' type='anim' /> <public name='kau_slide_in_top' type='anim' /> - <public name='kau_slide_in_left' 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_fade_in' type='anim' /> - <public name='kau_slide_out_top' type='anim' /> <public name='kau_slide_out_bottom' type='anim' /> - <public name='kau_fade_out' type='anim' /> - <public name='kau_slide_out_left' type='anim' /> - <public name='kau_slide_out_left_top' type='anim' /> <public name='kau_slide_in_bottom' type='anim' /> - <public name='kau_slide_in_right' type='anim' /> - <public name='kau_transparent' type='drawable' /> - <public name='kau_selectable_white' type='drawable' /> - <public name='kau_shadow_overlay' type='color' /> + <public name='kau_slide_out_top' type='anim' /> + <public name='kau_fade_out' type='anim' /> + <public name='kau_slide_in_left' type='anim' /> <public name='kau_activity_horizontal_margin' type='dimen' /> <public name='kau_activity_vertical_margin' type='dimen' /> <public name='kau_dialog_margin' type='dimen' /> @@ -43,6 +50,13 @@ <public name='kau_avatar_padding' type='dimen' /> <public name='kau_avatar_margin' type='dimen' /> <public name='kau_avatar_ripple_radius' type='dimen' /> + <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' /> <public name='kau_about_app' type='string' /> <public name='kau_about_x' type='string' /> <public name='kau_add_account' type='string' /> @@ -98,21 +112,7 @@ <public name='kau_permission_denied' type='string' /> <public name='kau_0' type='string' /> <public name='kau_bullet_point' type='string' /> + <public name='kau_shadow_overlay' type='color' /> <public name='Kau' type='style' /> <public name='Kau.Translucent' 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' /> - <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_enter_slide_right' type='transition' /> - <public name='kau_exit_slide_right' type='transition' /> - <public name='kau_exit_slide_left' type='transition' /> - <public name='kau_enter_slide_left' type='transition' /> </resources>
\ No newline at end of file diff --git a/core/src/test/kotlin/ca/allanwang/kau/ui/ProgressAnimatorTest.kt b/core/src/test/kotlin/ca/allanwang/kau/ui/ProgressAnimatorTest.kt index 60f8680..6b99b14 100644 --- a/core/src/test/kotlin/ca/allanwang/kau/ui/ProgressAnimatorTest.kt +++ b/core/src/test/kotlin/ca/allanwang/kau/ui/ProgressAnimatorTest.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2019 Allan Wang + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package ca.allanwang.kau.ui import org.junit.Test @@ -71,5 +86,4 @@ class ProgressAnimatorTest { assertTrue(called) assertTrue(i > 0.5f) } - -}
\ No newline at end of file +} diff --git a/docs/Changelog.md b/docs/Changelog.md index 61e5fb7..f8287ca 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -1,8 +1,19 @@ # Changelog +## v5.1.0 +* :adapter: Moved fastadapter elements to new module, :fastadapter:. To migrate, simply rename the dependency. If you don't use fast adapter, no changes are necessary +* :adapter: Make NoAnimatorChange an object; previously a class +* :core: KPref now supports in memory only variants for testing; pass KPrefBuilderInMemory to KPref constructor +* :core: KPref initializer takes in SharedPreferences so user can configure it + ## v5.0.0 +* Update Android SDK to 29 and Kotlin to 1.3.31 +* Update translations * :core: Update Material Dialogs to 3.x +* :core: Change ProgressAnimator API +* :core: Remove cursor tinting in EditText as it used reflection * :colorpicker: Strip down to just the interface; unless you require the accent palette, it may be fine to just use MD's color extension +* :gradle-plugin: Convert to kotlin, rework dependencies, and remove extension hooks ## v4.1.0 * :core: Deprecate NetworkUtils, as the underlying functions are deprecated diff --git a/docs/Migration.md b/docs/Migration.md index 58667ca..a7162fa 100644 --- a/docs/Migration.md +++ b/docs/Migration.md @@ -29,10 +29,6 @@ For instance, instead of using `kauDependencies`, we now use `kau.Dependencies`. There is also no longer a need to use `apply plugin 'ca.allanwang.kau'`; adding the plugin to the classpath suffices. -## Iconics - -With an iconics update, most of the package names have changed. - # v4.0.1-alpha02 * `kauParseFaq` is now synchronous. diff --git a/fastadapter/.gitignore b/fastadapter/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/fastadapter/.gitignore @@ -0,0 +1 @@ +/build diff --git a/fastadapter/README.md b/fastadapter/README.md new file mode 100644 index 0000000..fa339f7 --- /dev/null +++ b/fastadapter/README.md @@ -0,0 +1,17 @@ +# KAU :fastadapter + +Collection of kotlin bindings and custom IItems for [Fast Adapter](https://github.com/mikepenz/FastAdapter) + +## KauIItems + +Abstract base that extends `AbstractIItems` and contains the arguments `(layoutRes, ViewHolder lambda, idRes)` in that order. +Those variables are used to override the default abstract functions. +If a layout is only used for one item, it may also be used as the id, which you may leave blank in this case. +The ViewHolder lambda is typically of the form `::ViewHolder` +Where you will have a nested class `ViewHolder(v: View) : RecyclerView.ViewHolder(v)` + +## IItem Templates + +* CardIItem - generic all encompassing card item with a title, description, imageview, and button. +All items except for the title are optional. +* HeaderIItem - simple title container with a big top margin
\ No newline at end of file diff --git a/fastadapter/build.gradle b/fastadapter/build.gradle new file mode 100644 index 0000000..43e9c7c --- /dev/null +++ b/fastadapter/build.gradle @@ -0,0 +1,13 @@ +ext.kauSubModuleMinSdk = kau.Versions.coreMinSdk + +apply from: '../android-lib.gradle' + +dependencies { + implementation project(':core') + api project(':adapter') + + api kau.Dependencies.fastAdapter +// api kau.Dependencies.fastAdapterCommons +} + +apply from: '../artifacts.gradle' diff --git a/fastadapter/progress-proguard.txt b/fastadapter/progress-proguard.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/fastadapter/progress-proguard.txt @@ -0,0 +1 @@ + diff --git a/fastadapter/src/main/AndroidManifest.xml b/fastadapter/src/main/AndroidManifest.xml new file mode 100644 index 0000000..ab8cebb --- /dev/null +++ b/fastadapter/src/main/AndroidManifest.xml @@ -0,0 +1 @@ +<manifest package="ca.allanwang.kau.fastadapter" /> diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/AdapterUtils.kt b/fastadapter/src/main/kotlin/ca/allanwang/kau/adapters/AdapterUtils.kt index 42fe1a2..42fe1a2 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/AdapterUtils.kt +++ b/fastadapter/src/main/kotlin/ca/allanwang/kau/adapters/AdapterUtils.kt diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt b/fastadapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt index 01ac0e5..01ac0e5 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt +++ b/fastadapter/src/main/kotlin/ca/allanwang/kau/adapters/FastItemThemedAdapter.kt diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/RepeatedClickListener.kt b/fastadapter/src/main/kotlin/ca/allanwang/kau/adapters/RepeatedClickListener.kt index 3e7d707..3e7d707 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/adapters/RepeatedClickListener.kt +++ b/fastadapter/src/main/kotlin/ca/allanwang/kau/adapters/RepeatedClickListener.kt diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt b/fastadapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt index 47c465c..47c465c 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt +++ b/fastadapter/src/main/kotlin/ca/allanwang/kau/iitems/CardIItem.kt diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/HeaderIItem.kt b/fastadapter/src/main/kotlin/ca/allanwang/kau/iitems/HeaderIItem.kt index 2c488b1..2c488b1 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/HeaderIItem.kt +++ b/fastadapter/src/main/kotlin/ca/allanwang/kau/iitems/HeaderIItem.kt diff --git a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/KauIItem.kt b/fastadapter/src/main/kotlin/ca/allanwang/kau/iitems/KauIItem.kt index 853d388..34a2b7d 100644 --- a/adapter/src/main/kotlin/ca/allanwang/kau/iitems/KauIItem.kt +++ b/fastadapter/src/main/kotlin/ca/allanwang/kau/iitems/KauIItem.kt @@ -15,12 +15,9 @@ */ package ca.allanwang.kau.iitems -import android.annotation.SuppressLint import android.view.View import androidx.annotation.LayoutRes import androidx.recyclerview.widget.RecyclerView -import com.mikepenz.fastadapter.IClickable -import com.mikepenz.fastadapter.IItem import com.mikepenz.fastadapter.items.AbstractItem /** @@ -29,14 +26,10 @@ import com.mikepenz.fastadapter.items.AbstractItem * Kotlin implementation of the [AbstractItem] to make things shorter * If only one iitem type extends the given [layoutRes], you may use it as the type and not worry about another id */ -open class KauIItem<Item, VH : RecyclerView.ViewHolder>( - @param:LayoutRes private val layoutRes: Int, +open class KauIItem<VH : RecyclerView.ViewHolder>( + @param:LayoutRes override val layoutRes: Int, private val viewHolder: (v: View) -> VH, - private val type: Int = layoutRes -) : AbstractItem<Item, VH>() where Item : IItem<*>, Item : IClickable<*> { - @SuppressLint("ResourceType") - final override fun getType(): Int = type - + override val type: Int = layoutRes +) : AbstractItem<VH>() { final override fun getViewHolder(v: View): VH = viewHolder(v) - final override fun getLayoutRes(): Int = layoutRes } diff --git a/fastadapter/src/main/res/layout/kau_iitem_card.xml b/fastadapter/src/main/res/layout/kau_iitem_card.xml new file mode 100644 index 0000000..6bae0fe --- /dev/null +++ b/fastadapter/src/main/res/layout/kau_iitem_card.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Generic card with an imageview, title, description, and button + --> +<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/kau_card_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:selectableItemBackground" + android:minHeight="?android:listPreferredItemHeight"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="@dimen/kau_padding_normal"> + + <ImageView + android:id="@+id/kau_card_image" + android:layout_width="56dp" + android:layout_height="56dp" + android:layout_marginBottom="4dp" + android:layout_marginTop="4dp" + android:paddingEnd="32dp" + android:scaleType="fitCenter" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0" /> + + <TextView + android:id="@+id/kau_card_title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Subhead" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/kau_card_image" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/kau_card_description" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" + android:visibility="gone" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/kau_card_image" + app:layout_constraintTop_toBottomOf="@id/kau_card_title" /> + + <LinearLayout + android:id="@+id/kau_card_bottom_row" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/kau_card_image" + app:layout_constraintTop_toBottomOf="@id/kau_card_description"> + + <Button + android:id="@+id/kau_card_button" + style="?android:borderlessButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="?attr/colorAccent" /> + + </LinearLayout> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</androidx.cardview.widget.CardView> diff --git a/fastadapter/src/main/res/layout/kau_iitem_header.xml b/fastadapter/src/main/res/layout/kau_iitem_header.xml new file mode 100644 index 0000000..b0b2ec8 --- /dev/null +++ b/fastadapter/src/main/res/layout/kau_iitem_header.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/kau_header_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:id="@+id/kau_header_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/kau_spacing_xlarge" + android:padding="@dimen/kau_padding_normal" + android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> + +</androidx.cardview.widget.CardView>
\ No newline at end of file diff --git a/files/translation_migration.sh b/files/translation_migration.sh index d1372d1..d1372d1 100644..100755 --- a/files/translation_migration.sh +++ b/files/translation_migration.sh diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9fccf04..f1f2eac 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/kpref-activity/build.gradle b/kpref-activity/build.gradle index e2e2771..5cce460 100644 --- a/kpref-activity/build.gradle +++ b/kpref-activity/build.gradle @@ -7,7 +7,7 @@ apply from: '../android-lib.gradle' dependencies { implementation project(':core') implementation project(':colorpicker') - implementation project(':adapter') + implementation project(':fastadapter') } apply from: '../artifacts.gradle' diff --git a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefItemActions.kt b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefItemActions.kt index e28bac6..c1cdc15 100644 --- a/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefItemActions.kt +++ b/kpref-activity/src/main/kotlin/ca/allanwang/kau/kpref/activity/KPrefItemActions.kt @@ -1,3 +1,18 @@ +/* + * Copyright 2019 Allan Wang + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package ca.allanwang.kau.kpref.activity /** @@ -8,4 +23,4 @@ interface KPrefItemActions { * Attempts to reload current item by identifying it with its titleId */ fun reloadSelf() -}
\ No newline at end of file +} diff --git a/mediapicker/build.gradle b/mediapicker/build.gradle index b3a4153..06a18d0 100644 --- a/mediapicker/build.gradle +++ b/mediapicker/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'kotlin-kapt' dependencies { implementation project(':core-ui') - implementation project(':adapter') + implementation project(':fastadapter') api kau.Dependencies.glide api kau.Dependencies.blurry diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/BlurredImageView.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/BlurredImageView.kt index 4342229..739bf47 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/BlurredImageView.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/BlurredImageView.kt @@ -28,7 +28,7 @@ import ca.allanwang.kau.utils.scaleXY import ca.allanwang.kau.utils.setBackgroundColorRes import ca.allanwang.kau.utils.setIcon import ca.allanwang.kau.utils.visible -import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial +import com.mikepenz.google_material_typeface_library.GoogleMaterial import jp.wasabeef.blurry.internal.BlurFactor import jp.wasabeef.blurry.internal.BlurTask import kotlinx.android.synthetic.main.kau_blurred_imageview.view.* diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt index 8d2dab9..a365e13 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaActionItem.kt @@ -26,6 +26,7 @@ import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE import ca.allanwang.kau.permissions.kauRequestPermissions import ca.allanwang.kau.utils.materialDialog import ca.allanwang.kau.utils.string +import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import java.io.File diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerActivityBase.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerActivityBase.kt index fa161c7..5e5d1ed 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerActivityBase.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerActivityBase.kt @@ -26,7 +26,7 @@ import ca.allanwang.kau.utils.setIcon import ca.allanwang.kau.utils.toDrawable import ca.allanwang.kau.utils.toast import com.google.android.material.appbar.AppBarLayout -import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial +import com.mikepenz.google_material_typeface_library.GoogleMaterial import kotlinx.android.synthetic.main.kau_activity_image_picker.* /** diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt index bf681eb..c928e04 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt @@ -46,16 +46,13 @@ import com.bumptech.glide.Glide import com.bumptech.glide.RequestManager import com.mikepenz.fastadapter.IItem import com.mikepenz.fastadapter.adapters.ItemAdapter -import com.mikepenz.iconics.IconicsColor import com.mikepenz.iconics.IconicsDrawable -import com.mikepenz.iconics.IconicsSize import com.mikepenz.iconics.colorInt import com.mikepenz.iconics.paddingPx import com.mikepenz.iconics.sizePx import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial import com.mikepenz.iconics.utils.toIconicsColor -import com.mikepenz.iconics.utils.toIconicsSizePx import kotlinx.coroutines.CancellationException import java.io.File @@ -94,7 +91,8 @@ abstract class MediaPickerCore<T : IItem<*>>( /** * Create error tile for a given item */ - fun getErrorDrawable(context: Context) = getIconDrawable(context, GoogleMaterial.Icon.gmd_error, accentColor) + fun getErrorDrawable(context: Context) = + getIconDrawable(context, GoogleMaterial.Icon.gmd_error, accentColor) fun getIconDrawable(context: Context, iicon: IIcon, color: Int): Drawable { val sizePx = MediaPickerCore.computeViewSize(context) @@ -112,7 +110,10 @@ abstract class MediaPickerCore<T : IItem<*>>( * This is used for both single and multiple photo picks */ fun onMediaPickerResult(resultCode: Int, data: Intent?): List<MediaModel> { - if (resultCode != Activity.RESULT_OK || data == null || !data.hasExtra(MEDIA_PICKER_RESULT)) + if (resultCode != Activity.RESULT_OK || data == null || !data.hasExtra( + MEDIA_PICKER_RESULT + ) + ) return emptyList() return data.getParcelableArrayListExtra(MEDIA_PICKER_RESULT) } @@ -146,7 +147,9 @@ abstract class MediaPickerCore<T : IItem<*>>( recycler.apply { val manager = object : GridLayoutManager(context, computeColumnCount(context)) { override fun getExtraLayoutSpace(state: RecyclerView.State?): Int { - return if (mediaType != MediaType.VIDEO) extraSpace else super.getExtraLayoutSpace(state) + return if (mediaType != MediaType.VIDEO) extraSpace else super.getExtraLayoutSpace( + state + ) } } setItemViewCacheSize(CACHE_SIZE) @@ -161,7 +164,14 @@ abstract class MediaPickerCore<T : IItem<*>>( var sortQuery = MediaStore.MediaColumns.DATE_MODIFIED + " DESC" override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { - return CursorLoader(this, mediaType.contentUri, MediaModel.projection, null, null, sortQuery) + return CursorLoader( + this, + mediaType.contentUri, + MediaModel.projection, + null, + null, + sortQuery + ) } /** @@ -245,7 +255,11 @@ abstract class MediaPickerCore<T : IItem<*>>( * Method used to retrieve uri data for API 19+ * See <a href="http://hmkcode.com/android-display-selected-image-and-its-real-path/"></a> */ - private fun <R> ContentResolver.query(baseUri: Uri, uris: List<Uri>, block: (cursor: Cursor) -> R) { + private fun <R> ContentResolver.query( + baseUri: Uri, + uris: List<Uri>, + block: (cursor: Cursor) -> R + ) { val ids = uris.filter { val valid = DocumentsContract.isDocumentUri(this@MediaPickerCore, it) if (!valid) KL.d { "Non document uri: ${it.encodedPath}" } @@ -255,7 +269,9 @@ abstract class MediaPickerCore<T : IItem<*>>( }.joinToString(prefix = "(", separator = ",", postfix = ")") //? query replacements are done for one arg at a time //since we potentially have a list of ids, we'll just format the WHERE clause ourself - query(baseUri, MediaModel.projection, "${BaseColumns._ID} IN $ids", null, sortQuery)?.use(block) + query(baseUri, MediaModel.projection, "${BaseColumns._ID} IN $ids", null, sortQuery)?.use( + block + ) } internal var tempPath: String? = null diff --git a/mediapicker/src/main/res/values-ar-rSA/strings_mediapicker.xml b/mediapicker/src/main/res/values-ar-rSA/strings_mediapicker.xml new file mode 100644 index 0000000..c05d161 --- /dev/null +++ b/mediapicker/src/main/res/values-ar-rSA/strings_mediapicker.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!--Generated by crowdin.com--> +<resources> + <string name="kau_no_items_found">لم يتم العثور على أي عنصر</string> + <string name="kau_no_items_selected">لم يتم إختيار أي عنصر</string> + <string name="kau_no_items_loaded">لم يتم تحميل أي عنصر</string> + <string name="kau_no_camera_found">لا توجد كاميرا</string> + <string name="kau_no_camera_found_content">يرجى تثبيت تطبيق كاميرا والمحاولة مجدداً.</string> + <string name="kau_temp_file_creation_failed">فشل في حفظ صورة مؤقتة.</string> + <string name="kau_select_media">اختيار وسائط</string> +</resources> diff --git a/sample/build.gradle b/sample/build.gradle index 9880735..cacd21f 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -117,7 +117,7 @@ android { dependencies { implementation project(':about') - implementation project(':adapter') + implementation project(':fastadapter') implementation project(':colorpicker') implementation project(':core') implementation project(':core-ui') diff --git a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/ColorPickerTest.kt b/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/ColorPickerTest.kt deleted file mode 100644 index ef53817..0000000 --- a/sample/src/androidTest/kotlin/ca/allanwang/kau/sample/ColorPickerTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018 Allan Wang - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ca.allanwang.kau.sample - -import android.view.View -import androidx.test.espresso.DataInteraction -import androidx.test.espresso.Espresso.onData -import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.ViewAssertion -import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withText -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.MediumTest -import androidx.test.rule.ActivityTestRule -import ca.allanwang.kau.colorpicker.CircleView -import org.hamcrest.Matchers.anything -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import kotlin.test.assertEquals -import kotlin.test.fail - -/** - * Created by Allan Wang on 22/02/2018. - * - * Tests related to the :colorpicker module - */ -@RunWith(AndroidJUnit4::class) -@MediumTest -class ColorPickerTest { - - @get:Rule - val activity: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java) - - private fun DataInteraction.click(position: Int) = - atPosition(position).perform(click()) - - private fun View.colorSelected(selected: Boolean) { - val circle = this as? CircleView ?: fail("View is not a CircleView") - assertEquals( - selected, - circle.colorSelected, - "CircleView ${circle.tag} ${if (selected) "is not" else "is"} actually selected" - ) - } - - private val colorSelected = ViewAssertion { view, _ -> view.colorSelected(true) } - - private val colorNotSelected = ViewAssertion { view, _ -> view.colorSelected(false) } - - @Test - fun colorClick() { - onView(withText(R.string.accent_color)).perform(click()) - val colors = onData(anything()).inAdapterView(withId(R.id.md_grid)) - - colors.click(0).check(colorNotSelected) // enter sub grid - colors.click(0).check(colorSelected) // click first grid item - colors.atPosition(1).check(colorNotSelected) - colors.atPosition(2).check(colorNotSelected) - .perform(click()).check(colorSelected) - colors.atPosition(0).check(colorNotSelected) - .perform(click()).check(colorSelected) - // first item is now selected - } -} diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/AdapterActivity.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/AdapterActivity.kt index 2fedbeb..8c35c77 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/AdapterActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/AdapterActivity.kt @@ -22,7 +22,7 @@ import ca.allanwang.kau.ui.activities.ElasticRecyclerActivity import ca.allanwang.kau.utils.toast import com.mikepenz.fastadapter.IItem import com.mikepenz.fastadapter.adapters.ItemAdapter -import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial +import com.mikepenz.google_material_typeface_library.GoogleMaterial /** * Created by Allan Wang on 2017-07-17. diff --git a/sample/src/main/kotlin/ca/allanwang/kau/sample/KPrefSample.kt b/sample/src/main/kotlin/ca/allanwang/kau/sample/KPrefSample.kt index 0f20880..80a75bf 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/KPrefSample.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/KPrefSample.kt @@ -17,7 +17,6 @@ package ca.allanwang.kau.sample import android.graphics.Color import ca.allanwang.kau.kpref.KPref -import ca.allanwang.kau.kpref.kpref /** * Created by Allan Wang on 2017-06-07. 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 b848812..f4a09cf 100644 --- a/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt +++ b/sample/src/main/kotlin/ca/allanwang/kau/sample/MainActivity.kt @@ -39,8 +39,7 @@ import ca.allanwang.kau.utils.toast import ca.allanwang.kau.utils.withSceneTransitionAnimation import ca.allanwang.kau.xml.showChangelog import com.afollestad.materialdialogs.input.input -import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial -import java.lang.RuntimeException +import com.mikepenz.google_material_typeface_library.GoogleMaterial class MainActivity : KPrefActivity() { @@ -107,7 +106,7 @@ class MainActivity : KPrefActivity() { accentColor = KPrefSample::accentColor } - override fun onCreateKPrefs(savedInstanceState: android.os.Bundle?): KPrefAdapterBuilder.() -> Unit = { + override fun onCreateKPrefs(savedInstanceState: Bundle?): KPrefAdapterBuilder.() -> Unit = { header(R.string.header) diff --git a/sample/src/main/play/contactEmail b/sample/src/main/play/contact-email.txt index 3e03392..3e03392 100644 --- a/sample/src/main/play/contactEmail +++ b/sample/src/main/play/contact-email.txt diff --git a/sample/src/main/play/defaultLanguage b/sample/src/main/play/default-language.txt index ffdd217..ffdd217 100644 --- a/sample/src/main/play/defaultLanguage +++ b/sample/src/main/play/default-language.txt diff --git a/sample/src/main/play/en-CA/listing/fulldescription b/sample/src/main/play/listings/en-CA/listing/full-description.txt index 2d9fe89..2d9fe89 100644 --- a/sample/src/main/play/en-CA/listing/fulldescription +++ b/sample/src/main/play/listings/en-CA/listing/full-description.txt diff --git a/sample/src/main/play/en-CA/listing/shortdescription b/sample/src/main/play/listings/en-CA/listing/short-description.txt index 9424ee8..9424ee8 100644 --- a/sample/src/main/play/en-CA/listing/shortdescription +++ b/sample/src/main/play/listings/en-CA/listing/short-description.txt diff --git a/sample/src/main/play/en-CA/listing/title b/sample/src/main/play/listings/en-CA/listing/title-txt index c3c5422..c3c5422 100644 --- a/sample/src/main/play/en-CA/listing/title +++ b/sample/src/main/play/listings/en-CA/listing/title-txt diff --git a/sample/src/main/play/en-CA/whatsnew b/sample/src/main/play/release-notes/en-CA/default.txt index 1d15ce2..1d15ce2 100644 --- a/sample/src/main/play/en-CA/whatsnew +++ b/sample/src/main/play/release-notes/en-CA/default.txt diff --git a/sample/src/main/res/xml/kau_changelog.xml b/sample/src/main/res/xml/kau_changelog.xml index 53265d0..62614ed 100644 --- a/sample/src/main/res/xml/kau_changelog.xml +++ b/sample/src/main/res/xml/kau_changelog.xml @@ -6,12 +6,21 @@ <item text="" /> --> + <version title="v5.1.0" /> + <item text=":adapter: Moved fastadapter elements to new module, :fastadapter:. To migrate, simply rename the dependency. If you don't use fast adapter, no changes are necessary" /> + <item text=":adapter: Make NoAnimatorChange an object; previously a class" /> + <item text=":core: KPref now supports in memory only variants for testing; pass KPrefBuilderInMemory to KPref constructor" /> + <item text=":core: KPref initializer takes in SharedPreferences so user can configure it" /> + <item text="" /> + <version title="v5.0.0" /> + <item text="Update Android SDK to 29 and Kotlin to 1.3.31" /> + <item text="Update translations" /> <item text=":core: Update Material Dialogs to 3.x" /> + <item text=":core: Change ProgressAnimator API" /> + <item text=":core: Remove cursor tinting in EditText as it used reflection" /> <item text=":colorpicker: Strip down to just the interface; unless you require the accent palette, it may be fine to just use MD's color extension" /> - <item text="" /> - <item text="" /> - <item text="" /> + <item text=":gradle-plugin: Convert to kotlin, rework dependencies, and remove extension hooks" /> <item text="" /> <version title="v4.1.0" /> diff --git a/searchview/build.gradle b/searchview/build.gradle index 39a3662..f9e83fc 100644 --- a/searchview/build.gradle +++ b/searchview/build.gradle @@ -4,7 +4,7 @@ apply from: '../android-lib.gradle' dependencies { implementation project(':core-ui') - implementation project(':adapter') + implementation project(':fastadapter') } apply from: '../artifacts.gradle' diff --git a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchItem.kt b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchItem.kt index 98921bb..7747d81 100644 --- a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchItem.kt +++ b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchItem.kt @@ -32,7 +32,7 @@ import ca.allanwang.kau.utils.setIcon import ca.allanwang.kau.utils.setRippleBackground import ca.allanwang.kau.utils.visible import com.mikepenz.iconics.typeface.IIcon -import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial +import com.mikepenz.google_material_typeface_library.GoogleMaterial /** * Created by Allan Wang on 2017-06-23. diff --git a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt index 39e0d28..18eb675 100644 --- a/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt +++ b/searchview/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt @@ -64,7 +64,7 @@ import ca.allanwang.kau.utils.visible import ca.allanwang.kau.utils.withLinearAdapter import com.mikepenz.fastadapter.adapters.FastItemAdapter import com.mikepenz.iconics.typeface.IIcon -import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial +import com.mikepenz.google_material_typeface_library.GoogleMaterial import kotlinx.android.synthetic.main.kau_search_view.view.* /** diff --git a/settings.gradle b/settings.gradle index 2bd5947..42d498e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,6 +3,7 @@ include ':core', ':about', ':adapter', + ':fastadapter', ':colorpicker', ':mediapicker', ':kpref-activity', |