diff --git a/build.gradle b/build.gradle
index ee4dceb..716f076 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ buildscript {
ext {
organization = 'twocoders'
- projectWebsite = 'https://github.com/Two-Coders/android-dynamic-componets/'
+ projectWebsite = 'https://github.com/Two-Coders/android-dynamic-components/'
projectDescription = 'Project containing useful Dynamic components.'
projectLicences = ['MIT']
@@ -11,14 +11,21 @@ buildscript {
androidTargerSdkVersion = androidCompileSdkVersion
libDynamicColorVersion = '1.0.0'
+ libDynamicImageCoilVersion = '1.0.0'
+ libDynamicImageGlideVersion = '1.0.0'
+ libDynamicImagePicassoVersion = '1.0.0'
libDynamicTextVersion = '3.0.0'
kotlinVersion = '1.4.21'
androidXCoreVersion = '1.3.2'
annotationVersion = '1.1.0'
commonExtensionsVersion = '1.0.0'
+ coilVersion = '1.1.0'
+ glideVersion = '4.11.0'
+ picassoVersion = '2.71828'
junitVersion = '4.13.1'
+ mockitoVersion = '3.7.0'
androidTestRunnerVersion = '1.3.0'
androidJunitVersion = '1.1.2'
}
diff --git a/dynamic/color/build.gradle b/dynamic/color/build.gradle
index ca88d4c..b0cb286 100644
--- a/dynamic/color/build.gradle
+++ b/dynamic/color/build.gradle
@@ -17,12 +17,6 @@ android {
consumerProguardFiles 'consumer-rules.pro'
}
- buildTypes {
- release {
- minifyEnabled false
- }
- }
-
buildFeatures {
dataBinding = true
}
diff --git a/dynamic/color/src/main/java/com/twocoders/dynamic/color/DynamicColor.kt b/dynamic/color/src/main/java/com/twocoders/dynamic/color/DynamicColor.kt
index 26af110..e3c4014 100644
--- a/dynamic/color/src/main/java/com/twocoders/dynamic/color/DynamicColor.kt
+++ b/dynamic/color/src/main/java/com/twocoders/dynamic/color/DynamicColor.kt
@@ -91,9 +91,7 @@ open class DynamicColor : Parcelable {
parcel.writeInt(attrRes ?: NO_ID)
}
- override fun describeContents(): Int {
- return 0
- }
+ override fun describeContents() = 0
override fun equals(other: Any?): Boolean {
if (this === other) return true
diff --git a/dynamic/color/src/main/res/values/strings.xml b/dynamic/color/src/main/res/values/strings.xml
deleted file mode 100644
index 3b233f0..0000000
--- a/dynamic/color/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Dynamic Color
-
\ No newline at end of file
diff --git a/dynamic/image-base/.gitignore b/dynamic/image-base/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/dynamic/image-base/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/dynamic/image-base/build.gradle b/dynamic/image-base/build.gradle
new file mode 100644
index 0000000..0ee0421
--- /dev/null
+++ b/dynamic/image-base/build.gradle
@@ -0,0 +1,26 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
+
+android {
+ compileSdkVersion androidCompileSdkVersion
+
+ defaultConfig {
+ minSdkVersion androidMinSdkVersion
+ targetSdkVersion androidTargerSdkVersion
+
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
+ implementation "androidx.annotation:annotation:$annotationVersion"
+ implementation "com.twocoders.extensions:common:$commonExtensionsVersion"
+}
diff --git a/dynamic/image-base/consumer-rules.pro b/dynamic/image-base/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/dynamic/image-base/src/main/AndroidManifest.xml b/dynamic/image-base/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ae67ed8
--- /dev/null
+++ b/dynamic/image-base/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/BaseDynamicImage.kt b/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/BaseDynamicImage.kt
new file mode 100644
index 0000000..60f3e8a
--- /dev/null
+++ b/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/BaseDynamicImage.kt
@@ -0,0 +1,139 @@
+package com.twocoders.dynamic.image.base
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.os.Parcel
+import android.os.Parcelable
+import android.widget.ImageView
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import com.twocoders.dynamic.image.base.component.UriComponent
+import com.twocoders.extensions.common.NO_ID
+import com.twocoders.extensions.common.getDrawable
+import com.twocoders.extensions.common.logd
+
+/**
+ *
+ * Handy class which can be used to bind image data to views.
+ * Data can be in [DrawableRes], [Drawable], or [UriComponent] format.
+ */
+@Suppress("unused", "MemberVisibilityCanBePrivate")
+abstract class BaseDynamicImage : Parcelable {
+
+ @DrawableRes protected val imageRes: Int?
+ protected val imageDrawable: Drawable?
+ protected val imageUri: UriComponent?
+
+ protected constructor(
+ @ColorInt imageRes: Int? = null,
+ imageDrawable: Drawable? = null,
+ imageUri: UriComponent? = null
+ ) {
+ this.imageRes = imageRes
+ this.imageDrawable = imageDrawable
+ this.imageUri = imageUri
+ }
+
+ protected constructor(parcel: Parcel) : this(
+ parcel.readInt(),
+ parcel.readDrawable(),
+ parcel.readParcelable(UriComponent::class.java.classLoader)
+ )
+
+ protected abstract suspend fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent
+ ): Drawable?
+
+ protected abstract fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent,
+ callback: (drawable: Drawable) -> Unit
+ )
+
+ open suspend fun getDrawable(context: Context): Drawable? {
+ imageUri?.let { imageUriComponent ->
+ return getDrawableFromUri(context, imageUriComponent)
+ }
+
+ imageDrawable?.let { drawable ->
+ return drawable
+ }
+
+ imageRes?.let { res ->
+ return context.getDrawable(drawableResId = res)
+ }
+
+ return null
+ }
+
+ open fun getDrawable(context: Context, callback: (drawable: Drawable?) -> Unit) {
+ if (isEmpty()) {
+ callback(null)
+ return
+ }
+
+ imageUri?.let { imageUriComponent ->
+ getDrawableFromUri(context, imageUriComponent, callback)
+ }
+
+ imageDrawable?.let { drawable ->
+ callback(drawable)
+ }
+
+ imageRes?.let { res ->
+ context.getDrawable(drawableResId = res)?.let { callback(it) }
+ }
+ }
+
+ abstract fun loadDrawableInto(imageView: ImageView, withCrossFade: Boolean = false)
+
+ fun isEmpty() = imageRes == null && imageDrawable == null && imageUri == null
+
+ fun isNotEmpty() = !isEmpty()
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(imageRes ?: NO_ID)
+ parcel.writeParcelable(imageDrawable.getParcelable(), flags)
+ parcel.writeParcelable(imageUri, flags)
+ }
+
+ override fun describeContents() = 0
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as BaseDynamicImage
+
+ if (imageRes != other.imageRes) return false
+ if (imageDrawable != other.imageDrawable) return false
+ if (imageUri != other.imageUri) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = imageRes ?: NO_ID
+ result = 31 * result + imageDrawable.hashCode()
+ result = 31 * result + imageUri.hashCode()
+ return result
+ }
+}
+
+private fun Parcel.readDrawable(): Drawable? =
+ when (val parcelDrawable = readParcelable(BaseDynamicImage::class.java.classLoader)) {
+ is Bitmap -> @Suppress("DEPRECATION") BitmapDrawable(parcelDrawable)
+ else -> null
+ }
+
+private fun Drawable?.getParcelable(): Parcelable? = when (this) {
+ is BitmapDrawable -> bitmap
+ is Drawable -> {
+ logd("Unsupported $this in imageDrawable for parcel, only BitmapDrawable is supported now.")
+ null
+ }
+ else -> null
+}
\ No newline at end of file
diff --git a/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/DynamicImageBindingAdapter.kt b/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/DynamicImageBindingAdapter.kt
new file mode 100644
index 0000000..a9bce11
--- /dev/null
+++ b/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/DynamicImageBindingAdapter.kt
@@ -0,0 +1,8 @@
+package com.twocoders.dynamic.image.base
+
+import android.widget.ImageView
+import androidx.databinding.BindingAdapter
+
+@BindingAdapter(value = ["android:src", "loadWithCrossFade"], requireAll = false)
+fun ImageView.loadDynamicImage(image: BaseDynamicImage, withCrossFade: Boolean = false) =
+ image.loadDrawableInto(this, withCrossFade)
\ No newline at end of file
diff --git a/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/component/UriComponent.kt b/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/component/UriComponent.kt
new file mode 100755
index 0000000..00a68a7
--- /dev/null
+++ b/dynamic/image-base/src/main/java/com/twocoders/dynamic/image/base/component/UriComponent.kt
@@ -0,0 +1,33 @@
+package com.twocoders.dynamic.image.base.component
+
+import android.net.Uri
+import android.os.Parcel
+import android.os.Parcelable
+import androidx.annotation.DrawableRes
+import com.twocoders.extensions.common.NO_ID
+
+data class UriComponent(
+ val image: Uri,
+ @DrawableRes val errorImage: Int? = null,
+ @DrawableRes val placeholderImage: Int? = null
+) : Parcelable {
+
+ constructor(parcel: Parcel) : this(
+ parcel.readParcelable(Uri::class.java.classLoader)!!,
+ parcel.readInt(),
+ parcel.readInt()
+ )
+
+ companion object CREATOR : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel) = UriComponent(parcel)
+ override fun newArray(size: Int): Array = arrayOfNulls(size)
+ }
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeParcelable(image, flags)
+ parcel.writeInt(errorImage ?: NO_ID)
+ parcel.writeInt(placeholderImage ?: NO_ID)
+ }
+
+ override fun describeContents() = 0
+}
\ No newline at end of file
diff --git a/dynamic/image-coil/.gitignore b/dynamic/image-coil/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/dynamic/image-coil/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/dynamic/image-coil/build.gradle b/dynamic/image-coil/build.gradle
new file mode 100644
index 0000000..509a121
--- /dev/null
+++ b/dynamic/image-coil/build.gradle
@@ -0,0 +1,58 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
+
+ext.bintrayPublishVersion = libDynamicImageCoilVersion
+apply from: '../../bintray-publish-config.gradle'
+
+android {
+ compileSdkVersion androidCompileSdkVersion
+
+ defaultConfig {
+ minSdkVersion androidMinSdkVersion
+ targetSdkVersion androidTargerSdkVersion
+ versionName libDynamicImageCoilVersion
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8.toString()
+ }
+
+ testOptions {
+ unitTests {
+ returnDefaultValues = true
+ includeAndroidResources = true
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ api project(':dynamic:image-base')
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
+ implementation "androidx.annotation:annotation:$annotationVersion"
+ implementation "androidx.core:core-ktx:$androidXCoreVersion"
+ implementation "com.twocoders.extensions:common:$commonExtensionsVersion"
+
+ implementation "io.coil-kt:coil:$coilVersion"
+
+ androidTestImplementation "androidx.test:runner:$androidTestRunnerVersion"
+ androidTestImplementation "androidx.test.ext:junit:$androidJunitVersion"
+ androidTestImplementation "org.mockito:mockito-android:$mockitoVersion"
+
+ testImplementation "junit:junit:$junitVersion"
+}
diff --git a/dynamic/image-coil/consumer-rules.pro b/dynamic/image-coil/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/dynamic/image-coil/src/androidTest/java/com/twocoders/dynamic/image/coil/DynamicImageCoilTest.kt b/dynamic/image-coil/src/androidTest/java/com/twocoders/dynamic/image/coil/DynamicImageCoilTest.kt
new file mode 100644
index 0000000..e54d2ef
--- /dev/null
+++ b/dynamic/image-coil/src/androidTest/java/com/twocoders/dynamic/image/coil/DynamicImageCoilTest.kt
@@ -0,0 +1,58 @@
+package com.twocoders.dynamic.image.coil
+
+import android.content.Context
+import android.graphics.drawable.BitmapDrawable
+import android.widget.ImageView
+import androidx.annotation.DrawableRes
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.twocoders.extensions.common.getDrawable
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.*
+
+@RunWith(AndroidJUnit4::class)
+class DynamicImageCoilTest {
+
+ private lateinit var context: Context
+
+ @Before
+ fun setUp() {
+ context = InstrumentationRegistry.getInstrumentation().context
+ }
+
+ @Test
+ fun emptyDynamicImageReturnsNullDrawable() {
+ val emptyDynamicImage = DynamicImage.EMPTY
+
+ emptyDynamicImage.getDrawable(context) { assertNull(it) }
+
+ GlobalScope.launch { assertNull(emptyDynamicImage.getDrawable(context)) }
+
+ val imageViewMock = mock(ImageView::class.java)
+ emptyDynamicImage.loadDrawableInto(imageViewMock)
+ verify(imageViewMock, never()).setImageDrawable(any())
+ }
+
+ @Test
+ fun dynamicImageFromDrawableRes() {
+ @DrawableRes val testedImageRes = android.R.drawable.ic_delete
+ val testedDynamicImage = DynamicImage.from(testedImageRes)
+ val expectedDrawable = context.getDrawable(drawableResId = testedImageRes) as BitmapDrawable
+ val expectedBitmap = expectedDrawable.bitmap
+
+ testedDynamicImage.getDrawable(context) { assertEquals(expectedBitmap, (it as BitmapDrawable).bitmap ) }
+
+ GlobalScope.launch { assertEquals(expectedBitmap, (testedDynamicImage.getDrawable(context) as BitmapDrawable).bitmap) }
+
+ val imageViewMock = mock(ImageView::class.java)
+ `when`(imageViewMock.context).thenReturn(context)
+ testedDynamicImage.loadDrawableInto(imageViewMock)
+ verify(imageViewMock).setImageDrawable(expectedDrawable)
+ }
+}
\ No newline at end of file
diff --git a/dynamic/image-coil/src/main/AndroidManifest.xml b/dynamic/image-coil/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ea98b05
--- /dev/null
+++ b/dynamic/image-coil/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dynamic/image-coil/src/main/java/com/twocoders/dynamic/image/coil/DynamicImage.kt b/dynamic/image-coil/src/main/java/com/twocoders/dynamic/image/coil/DynamicImage.kt
new file mode 100644
index 0000000..cbff9e2
--- /dev/null
+++ b/dynamic/image-coil/src/main/java/com/twocoders/dynamic/image/coil/DynamicImage.kt
@@ -0,0 +1,123 @@
+package com.twocoders.dynamic.image.coil
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.VectorDrawable
+import android.os.Parcel
+import android.os.Parcelable
+import android.widget.ImageView
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import coil.Coil
+import coil.ImageLoader
+import coil.load
+import coil.request.ImageRequest
+import com.twocoders.dynamic.image.base.BaseDynamicImage
+import com.twocoders.dynamic.image.base.component.UriComponent
+
+/**
+ *
+ * Handy class which can be used to bind image data to views.
+ * Data can be in [DrawableRes], [Drawable], or [UriComponent] format.
+ *
+ * Use one of [DynamicImage.from] creator methods to create the data
+ * and [DynamicImage.getDrawable] to obtain the final [Drawable] output. Or you can
+ * provide target [ImageView] class into the [DynamicImage.loadDrawableInto] method.
+ *
+ * This [DynamicImage] implementation uses [Coil], for other implementations please visit our GitHub:
+ * [Android Dynamic Components](https://github.com/Two-Coders/android-dynamic-components)
+ *
+ */
+@Suppress("unused", "MemberVisibilityCanBePrivate")
+open class DynamicImage : BaseDynamicImage {
+
+ protected constructor(
+ @ColorInt imageRes: Int? = null,
+ imageDrawable: Drawable? = null,
+ imageUri: UriComponent? = null
+ ) : super(imageRes, imageDrawable, imageUri)
+
+ protected constructor(parcel: Parcel) : super(parcel)
+
+ companion object {
+
+ val EMPTY = DynamicImage()
+
+ @JvmStatic
+ fun from(@DrawableRes imageRes: Int) = DynamicImage(imageRes = imageRes)
+
+ @JvmStatic
+ fun from(imageDrawable: Drawable) = DynamicImage(imageDrawable = imageDrawable)
+
+ @JvmStatic
+ fun from(imageUri: UriComponent) = DynamicImage(imageUri = imageUri)
+
+ @JvmField
+ val CREATOR = object : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel) = DynamicImage(parcel)
+ override fun newArray(size: Int): Array = arrayOfNulls(size)
+ }
+ }
+
+ override suspend fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent
+ ): Drawable? {
+ val request = ImageRequest.Builder(context)
+ .data(imageUriComponent.image)
+ .build()
+ return ImageLoader(context).execute(request).drawable
+ }
+
+ override fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent,
+ callback: (drawable: Drawable) -> Unit
+ ) {
+ ImageLoader(context).enqueue(
+ ImageRequest.Builder(context)
+ .data(imageUriComponent.image)
+ .target { callback(it) }
+ .build()
+ )
+ }
+
+ override fun loadDrawableInto(
+ imageView: ImageView,
+ withCrossFade: Boolean
+ ) {
+ imageUri?.let { imageUriComponent ->
+ imageView.load(imageUriComponent.image) {
+ crossfade(withCrossFade)
+ imageUriComponent.placeholderImage?.let { placeholder(it) }
+ imageUriComponent.errorImage?.let { error(it) }
+ }
+ }
+
+ imageDrawable?.let {
+ // Note: Coil has currently issue with loading vectors
+ if (it is VectorDrawable) {
+ imageView.setImageDrawable(it)
+ } else {
+ imageView.load(it) {
+ crossfade(withCrossFade)
+ }
+ }
+ }
+
+ imageRes?.let {
+ // We need to get drawable before setting it to imageView through Coil,
+ // there is a problem with background tint from theme attribute
+ getDrawable(imageView.context) { drawable ->
+ // Note: Coil has currently issue with loading vectors
+ if (drawable is VectorDrawable) {
+ imageView.setImageDrawable(drawable)
+ } else {
+ imageView.load(drawable) {
+ crossfade(withCrossFade)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dynamic/image-glide/.gitignore b/dynamic/image-glide/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/dynamic/image-glide/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/dynamic/image-glide/build.gradle b/dynamic/image-glide/build.gradle
new file mode 100644
index 0000000..51c9bd4
--- /dev/null
+++ b/dynamic/image-glide/build.gradle
@@ -0,0 +1,50 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
+
+ext.bintrayPublishVersion = libDynamicImageGlideVersion
+apply from: '../../bintray-publish-config.gradle'
+
+android {
+ compileSdkVersion androidCompileSdkVersion
+
+ defaultConfig {
+ minSdkVersion androidMinSdkVersion
+ targetSdkVersion androidTargerSdkVersion
+ versionName libDynamicImageGlideVersion
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8.toString()
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ api project(':dynamic:image-base')
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
+ implementation "androidx.annotation:annotation:$annotationVersion"
+ implementation "androidx.core:core-ktx:$androidXCoreVersion"
+ implementation "com.twocoders.extensions:common:$commonExtensionsVersion"
+
+ implementation "com.github.bumptech.glide:glide:$glideVersion"
+
+ androidTestImplementation "androidx.test:runner:$androidTestRunnerVersion"
+ androidTestImplementation "androidx.test.ext:junit:$androidJunitVersion"
+
+ testImplementation "junit:junit:$junitVersion"
+}
diff --git a/dynamic/image-glide/consumer-rules.pro b/dynamic/image-glide/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/dynamic/image-glide/src/main/AndroidManifest.xml b/dynamic/image-glide/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8f373ac
--- /dev/null
+++ b/dynamic/image-glide/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dynamic/image-glide/src/main/java/com/twocoders/dynamic/image/glide/DynamicImage.kt b/dynamic/image-glide/src/main/java/com/twocoders/dynamic/image/glide/DynamicImage.kt
new file mode 100644
index 0000000..dcad5e1
--- /dev/null
+++ b/dynamic/image-glide/src/main/java/com/twocoders/dynamic/image/glide/DynamicImage.kt
@@ -0,0 +1,124 @@
+package com.twocoders.dynamic.image.glide
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.os.Parcel
+import android.os.Parcelable
+import android.widget.ImageView
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
+import com.bumptech.glide.request.target.CustomTarget
+import com.bumptech.glide.request.transition.Transition
+import com.twocoders.dynamic.image.base.BaseDynamicImage
+import com.twocoders.dynamic.image.base.component.UriComponent
+
+/**
+ *
+ * Handy class which can be used to bind image data to views.
+ * Data can be in [DrawableRes], [Drawable], or [UriComponent] format.
+ *
+ * Use one of [DynamicImage.from] creator methods to create the data
+ * and [DynamicImage.getDrawable] to obtain the final [Drawable] output. Or you can
+ * provide target [ImageView] class into the [DynamicImage.loadDrawableInto] method.
+ *
+ * This [DynamicImage] implementation uses [Glide], for other implementations please visit our GitHub:
+ * [Android Dynamic Components](https://github.com/Two-Coders/android-dynamic-components)
+ *
+ */
+@Suppress("unused", "MemberVisibilityCanBePrivate")
+open class DynamicImage : BaseDynamicImage {
+
+ protected constructor(
+ @ColorInt imageRes: Int? = null,
+ imageDrawable: Drawable? = null,
+ imageUri: UriComponent? = null
+ ) : super(imageRes, imageDrawable, imageUri)
+
+ protected constructor(parcel: Parcel) : super(parcel)
+
+ companion object {
+
+ val EMPTY = DynamicImage()
+
+ @JvmStatic
+ fun from(@DrawableRes imageRes: Int) = DynamicImage(imageRes = imageRes)
+
+ @JvmStatic
+ fun from(imageDrawable: Drawable) = DynamicImage(imageDrawable = imageDrawable)
+
+ @JvmStatic
+ fun from(imageUri: UriComponent) = DynamicImage(imageUri = imageUri)
+
+ @JvmField
+ val CREATOR = object : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel) = DynamicImage(parcel)
+ override fun newArray(size: Int): Array = arrayOfNulls(size)
+ }
+ }
+
+ override suspend fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent
+ ) = BitmapDrawable(
+ context.resources,
+ Glide.with(context)
+ .asBitmap()
+ .load(imageUriComponent.image)
+ .submit()
+ .get()
+ )
+
+ override fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent,
+ callback: (drawable: Drawable) -> Unit
+ ) {
+ Glide.with(context)
+ .asBitmap()
+ .load(imageUriComponent.image)
+ .into(object : CustomTarget() {
+ override fun onResourceReady(resource: Bitmap, transition: Transition?) {
+ callback(BitmapDrawable(context.resources, resource))
+ }
+ override fun onLoadCleared(placeholder: Drawable?) {}
+ })
+ }
+
+ override fun loadDrawableInto(
+ imageView: ImageView,
+ withCrossFade: Boolean
+ ) {
+ imageUri?.let { imageUriComponent ->
+ Glide.with(imageView.context)
+ .load(imageUriComponent.image)
+ .apply {
+ if (withCrossFade) transition(DrawableTransitionOptions.withCrossFade())
+ imageUriComponent.placeholderImage?.let { placeholder(it) }
+ imageUriComponent.errorImage?.let { error(it) }
+ }
+ .into(imageView)
+ }
+
+ imageDrawable?.let {
+ Glide.with(imageView.context)
+ .load(it)
+ .apply {
+ if (withCrossFade) transition(DrawableTransitionOptions.withCrossFade())
+ }
+ .into(imageView)
+ }
+
+ imageRes?.let {
+ Glide.with(imageView.context)
+ .load(it)
+ .apply {
+ if (withCrossFade) transition(DrawableTransitionOptions.withCrossFade())
+ }
+ .into(imageView)
+ }
+ }
+}
\ No newline at end of file
diff --git a/dynamic/image-picasso/.gitignore b/dynamic/image-picasso/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/dynamic/image-picasso/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/dynamic/image-picasso/build.gradle b/dynamic/image-picasso/build.gradle
new file mode 100644
index 0000000..8ed39b7
--- /dev/null
+++ b/dynamic/image-picasso/build.gradle
@@ -0,0 +1,53 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
+
+ext.bintrayPublishVersion = libDynamicImagePicassoVersion
+apply from: '../../bintray-publish-config.gradle'
+
+android {
+ compileSdkVersion androidCompileSdkVersion
+
+ defaultConfig {
+ minSdkVersion androidMinSdkVersion
+ targetSdkVersion androidTargerSdkVersion
+ versionName libDynamicImagePicassoVersion
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles 'consumer-rules.pro'
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8.toString()
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ api project(':dynamic:image-base')
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
+ implementation "androidx.annotation:annotation:$annotationVersion"
+ implementation "androidx.core:core-ktx:$androidXCoreVersion"
+ implementation "com.twocoders.extensions:common:$commonExtensionsVersion"
+
+ implementation ("com.squareup.picasso:picasso:$picassoVersion") {
+ exclude group: 'com.android.support'
+ exclude module: ['exifinterface', 'support-annotations']
+ }
+
+ androidTestImplementation "androidx.test:runner:$androidTestRunnerVersion"
+ androidTestImplementation "androidx.test.ext:junit:$androidJunitVersion"
+
+ testImplementation "junit:junit:$junitVersion"
+}
diff --git a/dynamic/image-picasso/consumer-rules.pro b/dynamic/image-picasso/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/dynamic/image-picasso/src/main/AndroidManifest.xml b/dynamic/image-picasso/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..08f73e3
--- /dev/null
+++ b/dynamic/image-picasso/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/dynamic/image-picasso/src/main/java/com/twocoders/dynamic/image/picasso/DynamicImage.kt b/dynamic/image-picasso/src/main/java/com/twocoders/dynamic/image/picasso/DynamicImage.kt
new file mode 100644
index 0000000..eee0afe
--- /dev/null
+++ b/dynamic/image-picasso/src/main/java/com/twocoders/dynamic/image/picasso/DynamicImage.kt
@@ -0,0 +1,109 @@
+package com.twocoders.dynamic.image.picasso
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.os.Parcel
+import android.os.Parcelable
+import android.widget.ImageView
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import com.squareup.picasso.Picasso
+import com.squareup.picasso.Target
+import com.twocoders.dynamic.image.base.BaseDynamicImage
+import com.twocoders.dynamic.image.base.component.UriComponent
+
+/**
+ *
+ * Handy class which can be used to bind image data to views.
+ * Data can be in [DrawableRes], [Drawable], or [UriComponent] format.
+ *
+ * Use one of [DynamicImage.from] creator methods to create the data
+ * and [DynamicImage.getDrawable] to obtain the final [Drawable] output. Or you can
+ * provide target [ImageView] class into the [DynamicImage.loadDrawableInto] method.
+ *
+ * This [DynamicImage] implementation uses [Picasso], for other implementations please visit our GitHub:
+ * [Android Dynamic Components](https://github.com/Two-Coders/android-dynamic-components)
+ *
+ */
+@Suppress("unused", "MemberVisibilityCanBePrivate")
+open class DynamicImage : BaseDynamicImage {
+
+ protected constructor(
+ @ColorInt imageRes: Int? = null,
+ imageDrawable: Drawable? = null,
+ imageUri: UriComponent? = null
+ ) : super(imageRes, imageDrawable, imageUri)
+
+ protected constructor(parcel: Parcel) : super(parcel)
+
+ companion object {
+
+ val EMPTY = DynamicImage()
+
+ @JvmStatic
+ fun from(@DrawableRes imageRes: Int) = DynamicImage(imageRes = imageRes)
+
+ @JvmStatic
+ fun from(imageDrawable: Drawable) = DynamicImage(imageDrawable = imageDrawable)
+
+ @JvmStatic
+ fun from(imageUri: UriComponent) = DynamicImage(imageUri = imageUri)
+
+ @JvmField
+ val CREATOR = object : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel) = DynamicImage(parcel)
+ override fun newArray(size: Int): Array = arrayOfNulls(size)
+ }
+ }
+
+ override suspend fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent
+ ) = BitmapDrawable(
+ context.resources,
+ Picasso.get()
+ .load(imageUriComponent.image)
+ .get()
+ )
+
+ override fun getDrawableFromUri(
+ context: Context,
+ imageUriComponent: UriComponent,
+ callback: (drawable: Drawable) -> Unit
+ ) {
+ Picasso.get()
+ .load(imageUriComponent.image)
+ .into(object : Target {
+ override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
+ callback(BitmapDrawable(context.resources, bitmap))
+ }
+ override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) {}
+ override fun onPrepareLoad(placeHolderDrawable: Drawable?) {}
+ })
+ }
+
+ override fun loadDrawableInto(
+ imageView: ImageView,
+ withCrossFade: Boolean
+ ) {
+ imageUri?.let { imageUriComponent ->
+ Picasso.get()
+ .load(imageUriComponent.image)
+ .apply {
+ imageUriComponent.placeholderImage?.let { placeholder(it) }
+ imageUriComponent.errorImage?.let { error(it) }
+ }
+ .into(imageView)
+ }
+
+ imageDrawable?.let {
+ imageView.setImageDrawable(it)
+ }
+
+ imageRes?.let {
+ Picasso.get().load(it).into(imageView)
+ }
+ }
+}
\ No newline at end of file
diff --git a/dynamic/text/build.gradle b/dynamic/text/build.gradle
index e2711d8..9d8e019 100644
--- a/dynamic/text/build.gradle
+++ b/dynamic/text/build.gradle
@@ -17,12 +17,6 @@ android {
consumerProguardFiles 'consumer-rules.pro'
}
- buildTypes {
- release {
- minifyEnabled false
- }
- }
-
buildFeatures {
dataBinding = true
}
diff --git a/dynamic/text/src/main/java/com/twocoders/dynamic/text/Quantity.kt b/dynamic/text/src/main/java/com/twocoders/dynamic/text/Quantity.kt
index 5484166..e68c9ee 100644
--- a/dynamic/text/src/main/java/com/twocoders/dynamic/text/Quantity.kt
+++ b/dynamic/text/src/main/java/com/twocoders/dynamic/text/Quantity.kt
@@ -37,7 +37,7 @@ data class Quantity(val number: Int, val useInText: Boolean = false) : Parcelabl
ParcelCompat.writeBoolean(dest, useInText)
}
- override fun describeContents(): Int = 0
+ override fun describeContents() = 0
companion object {
@JvmField
diff --git a/dynamic/text/src/main/res/values/strings.xml b/dynamic/text/src/main/res/values/strings.xml
deleted file mode 100644
index 9cacc32..0000000
--- a/dynamic/text/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- Dynamic Text
-
diff --git a/settings.gradle b/settings.gradle
index 996b560..80fd82c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,6 @@
include ':dynamic:text',
- ':dynamic:color'
+ ':dynamic:color',
+ ':dynamic:image-base',
+ ':dynamic:image-coil',
+ ':dynamic:image-glide',
+ ':dynamic:image-picasso'