Skip to content

Commit 600e11c

Browse files
Merge pull request #38 from Omega-R/develop
Develop
2 parents 748d835 + 9e6603f commit 600e11c

File tree

11 files changed

+154
-27
lines changed

11 files changed

+154
-27
lines changed

app/src/main/java/omega_r/com/omegatypesexample/MainActivity.kt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@ import android.graphics.Bitmap
55
import android.graphics.BitmapFactory
66
import android.graphics.drawable.BitmapDrawable
77
import android.os.Bundle
8+
import android.util.Log
89
import android.widget.ImageView
910
import android.widget.TextView
1011
import androidx.core.content.res.ResourcesCompat
11-
import com.omega_r.libs.omegatypes.Color
12-
import com.omega_r.libs.omegatypes.Text
13-
import com.omega_r.libs.omegatypes.TextStyle
12+
import com.omega_r.libs.omegatypes.*
1413
import com.omega_r.libs.omegatypes.file.File
1514
import com.omega_r.libs.omegatypes.file.from
1615
import com.omega_r.libs.omegatypes.image.*
17-
import com.omega_r.libs.omegatypes.join
1816
import kotlinx.coroutines.Dispatchers
1917
import kotlinx.coroutines.launch
2018
import kotlinx.coroutines.withContext
@@ -31,16 +29,20 @@ class MainActivity : BaseActivity() {
3129
super.onCreate(savedInstanceState)
3230

3331
setContentView(R.layout.activity_main)
34-
val text = Text.from("test ") +
35-
Text.from(
32+
val text = TextBuilder()
33+
.append(Text.empty())
34+
.append(Text.from("test "))
35+
.append(Text.from(
3636
R.string.hello_world,
3737
Text.from(R.string.app_name),
3838
textStyle = TextStyle.font(ResourcesCompat.getFont(this, R.font.noto_sans_regular)!!)
39-
) +
40-
Text.from(
39+
))
40+
.append(Text.from(
4141
" SEMI BOLD",
4242
textStyle = TextStyle.font(ResourcesCompat.getFont(this, R.font.noto_sans_semi_bold)!!)
43-
)
43+
))
44+
.toText()
45+
4446
text.applyTo(exampleTextView) // or exampleTextView.setText(text)
4547

4648
val list = listOf(Text.from("1", TextStyle.color(Color.fromAttribute(R.attr.colorAccent))), Text.from("2", TextStyle.color(Color.fromAttribute(R.attr.colorAccent))), Text.from("3"))
@@ -74,7 +76,9 @@ class MainActivity : BaseActivity() {
7476
// image
7577
// }
7678

77-
imageView.setImage(image)
79+
imageView.setImage(image, processor = GlideImagesProcessor(ImageProcessors.current), onImageApplied = {
80+
Log.d("TAG","onImageApplied")
81+
})
7882

7983

8084

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ buildscript {
1212
jcenter()
1313
}
1414
dependencies {
15-
classpath 'com.android.tools.build:gradle:3.4.1'
15+
classpath 'com.android.tools.build:gradle:3.6.3'
1616
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1717
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
1818
// NOTE: Do not place your application dependencies here; they belong

glide/src/main/java/com/omega_r/libs/omegatypes/image/GlideImagesProcessor.kt

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ package com.omega_r.libs.omegatypes.image
33
import android.content.Context
44
import android.graphics.Bitmap
55
import android.graphics.drawable.Drawable
6+
import android.util.Log
67
import android.view.View
78
import android.widget.ImageView
89
import com.bumptech.glide.Glide
910
import com.bumptech.glide.RequestBuilder
11+
import com.bumptech.glide.load.DataSource
12+
import com.bumptech.glide.load.engine.GlideException
13+
import com.bumptech.glide.request.RequestListener
1014
import com.bumptech.glide.request.target.CustomViewTarget
15+
import com.bumptech.glide.request.target.Target
1116
import com.bumptech.glide.request.transition.Transition
1217
import com.omega_r.libs.omegatypes.decoders.BitmapDecoders
1318
import com.omega_r.libs.omegatypes.decoders.SimpleBitmapDecoders
@@ -18,8 +23,8 @@ import kotlin.reflect.KClass
1823
/**
1924
* Created by Anton Knyazev on 2019-10-03.
2025
*/
21-
class GlideImagesProcessor(
22-
private val oldImagesProcessor: ImageProcessors,
26+
open class GlideImagesProcessor(
27+
protected val oldImagesProcessor: ImageProcessors,
2328
vararg excludeImageClasses: KClass<out Image>
2429
) : ImageProcessors() {
2530

@@ -37,7 +42,7 @@ class GlideImagesProcessor(
3742

3843
private val excludeImageClasses = listOf(*excludeImageClasses)
3944

40-
private fun <T> RequestBuilder<T>.createRequestBuilder(image: Image): RequestBuilder<T>? {
45+
protected fun <T> RequestBuilder<T>.createRequestBuilder(image: Image): RequestBuilder<T>? {
4146
if (excludeImageClasses.contains(image::class)) {
4247
return null
4348
}
@@ -53,11 +58,12 @@ class GlideImagesProcessor(
5358
}
5459
}
5560

56-
override fun Image.applyImage(imageView: ImageView, placeholderResId: Int) {
61+
override fun Image.applyImage(imageView: ImageView, placeholderResId: Int, onImageApplied: (() -> Unit)?) {
5762
Glide.with(imageView)
5863
.asDrawable()
5964
.createRequestBuilder(this)
6065
?.applyPlaceholder(placeholderResId)
66+
?.listener(GlideImageRequestListener(onImageApplied))
6167
?.into(imageView)
6268
?: applyOld { applyImage(imageView, placeholderResId) }
6369
}
@@ -110,11 +116,45 @@ class GlideImagesProcessor(
110116
?: applyOld { preload(context) }
111117
}
112118

113-
private fun <T> RequestBuilder<T>.applyPlaceholder(placeholderResId: Int): RequestBuilder<T> {
119+
protected fun <T> RequestBuilder<T>.applyPlaceholder(placeholderResId: Int): RequestBuilder<T> {
114120
return if (placeholderResId != NO_PLACEHOLDER_RES) placeholder(placeholderResId) else this
115121
}
116122

117-
private inline fun <R> applyOld(block: ImageProcessors.() -> R): R {
123+
protected inline fun <R> applyOld(block: ImageProcessors.() -> R): R {
118124
return block(oldImagesProcessor)
119125
}
126+
}
127+
128+
class GlideImageRequestListener(private val onImageLoaded: (() -> Unit)?) : RequestListener<Drawable> {
129+
130+
companion object {
131+
private val TAG = GlideImageRequestListener::class.java.name
132+
}
133+
134+
override fun onLoadFailed(
135+
e: GlideException?,
136+
model: Any?,
137+
target: Target<Drawable>?,
138+
isFirstResource: Boolean
139+
): Boolean {
140+
Log.e(TAG, "Image load failed: ", e)
141+
if (isFirstResource) {
142+
onImageLoaded?.invoke()
143+
}
144+
return false
145+
}
146+
147+
override fun onResourceReady(
148+
resource: Drawable,
149+
model: Any?,
150+
target: Target<Drawable>,
151+
dataSource: DataSource,
152+
isFirstResource: Boolean
153+
): Boolean {
154+
target.onResourceReady(resource, null)
155+
if (isFirstResource) {
156+
onImageLoaded?.invoke()
157+
}
158+
return true
159+
}
120160
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Wed May 29 11:12:26 MSK 2019
1+
#Tue Apr 21 10:08:25 MSK 2020
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

omegatypes/src/main/java/com/omega_r/libs/omegatypes/Color.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package com.omega_r.libs.omegatypes
33
import android.content.Context
44
import android.content.res.ColorStateList
55
import android.content.res.Resources
6+
import android.graphics.drawable.ColorDrawable
67
import android.os.Build
78
import android.util.SparseIntArray
89
import android.util.TypedValue
10+
import android.view.View
911
import android.widget.TextView
1012
import java.io.Serializable
1113
import java.util.*
@@ -179,4 +181,11 @@ var TextView.linkTextColor: Color
179181
get() = Color.fromColorList(linkTextColors)
180182
set(value) {
181183
setLinkTextColor(value.getColorStateList(context))
184+
}
185+
186+
var View.backgroundColor: Color?
187+
get() = (background as? ColorDrawable)?.color?.let { Color.fromInt(it) }
188+
set(value) {
189+
value?.let { setBackgroundColor(it.getColorInt(context)) }
190+
?: setBackgroundDrawable(null)
182191
}

omegatypes/src/main/java/com/omega_r/libs/omegatypes/Text.kt

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@ package com.omega_r.libs.omegatypes
22

33
import android.app.Activity
44
import android.content.Context
5+
import android.text.Html
6+
import android.text.SpannableString
57
import android.text.SpannableStringBuilder
8+
import android.text.Spanned
69
import android.widget.EditText
710
import android.widget.TextView
811
import android.widget.Toast
12+
import java.io.IOException
13+
import java.io.ObjectInputStream
14+
import java.io.ObjectOutputStream
915
import java.io.Serializable
1016
import java.util.*
1117

@@ -136,9 +142,14 @@ open class Text(protected val defaultTextStyle: TextStyle?) : Serializable, Text
136142

137143

138144
private class CharSequenceText internal constructor(
139-
private val charSequence: CharSequence,
145+
private var charSequence: CharSequence,
140146
textStyle: TextStyle?) : Text(textStyle) {
141147

148+
companion object {
149+
private const val TYPE_SPANNED = 0.toByte()
150+
private const val TYPE_STRING = 1.toByte()
151+
}
152+
142153
override fun isEmpty(): Boolean = charSequence.isEmpty()
143154

144155
override fun getString(context: Context): String? {
@@ -149,6 +160,34 @@ open class Text(protected val defaultTextStyle: TextStyle?) : Serializable, Text
149160
return (defaultTextStyle + textStyle)?.applyStyle(context, charSequence) ?: charSequence
150161
}
151162

163+
@Throws(IOException::class)
164+
private fun writeObject(stream: ObjectOutputStream) {
165+
charSequence.let { charSequence->
166+
when (charSequence) {
167+
is Spanned -> {
168+
stream.writeByte(TYPE_SPANNED.toInt())
169+
stream.writeObject(Html.toHtml(charSequence))
170+
}
171+
is String -> {
172+
stream.writeByte(TYPE_STRING.toInt())
173+
stream.writeUTF(charSequence)
174+
}
175+
else -> {
176+
throw IOException("Unknown type " + charSequence::class.simpleName)
177+
}
178+
}
179+
}
180+
}
181+
182+
@Throws(IOException::class, ClassNotFoundException::class)
183+
private fun readObject(stream: ObjectInputStream) {
184+
charSequence = when (val type = stream.readByte()) {
185+
TYPE_SPANNED -> Html.fromHtml(stream.readObject() as String)
186+
TYPE_STRING -> stream.readUTF()
187+
else -> throw IOException("Unknown type = $type")
188+
}
189+
}
190+
152191
override fun equals(other: Any?): Boolean {
153192
if (this === other) return true
154193
if (javaClass != other?.javaClass) return false
@@ -297,7 +336,9 @@ open class Text(protected val defaultTextStyle: TextStyle?) : Serializable, Text
297336
val stringBuilder = SpannableStringBuilder()
298337
val newTextStyle = defaultTextStyle + textStyle
299338
for (text in texts) {
300-
stringBuilder.append(text.getCharSequence(context, newTextStyle))
339+
text.getCharSequence(context, newTextStyle)?.let { textCharSequence ->
340+
stringBuilder.append(textCharSequence)
341+
}
301342
}
302343
return stringBuilder
303344
}

omegatypes/src/main/java/com/omega_r/libs/omegatypes/TextBuilder.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ class TextBuilder(capacity: Int) : Serializable {
4848
return Text.from(list)
4949
}
5050

51+
fun isEmpty(): Boolean {
52+
for (text in list) {
53+
if (!text.isEmpty()) {
54+
return false
55+
}
56+
}
57+
return true
58+
}
59+
5160
override fun equals(other: Any?): Boolean {
5261
if (this === other) return true
5362
if (javaClass != other?.javaClass) return false

omegatypes/src/main/java/com/omega_r/libs/omegatypes/image/Image.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,22 @@ suspend fun Image.getStream(
138138
}
139139

140140
@JvmOverloads
141-
fun ImageView.setImage(image: Image?, placeholderResId: Int = Image.NO_PLACEHOLDER_RES, processor: ImageProcessors = ImageProcessors.current) {
141+
fun ImageView.setImage(
142+
image: Image?,
143+
placeholderResId: Int = Image.NO_PLACEHOLDER_RES,
144+
processor: ImageProcessors = ImageProcessors.current,
145+
onImageApplied: (() -> Unit)? = null
146+
) {
142147
with(processor) {
143148
if (image != null) {
144-
image.applyImage(this@setImage, placeholderResId)
149+
image.applyImage(this@setImage, placeholderResId, onImageApplied)
145150
} else {
146151
if (placeholderResId == 0) {
147152
setImageDrawable(null)
148153
} else {
149154
setImageResource(placeholderResId)
150155
}
156+
onImageApplied?.invoke()
151157
}
152158
}
153159
}

omegatypes/src/main/java/com/omega_r/libs/omegatypes/image/ImageProcessors.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ abstract class ImageProcessors : CoroutineScope {
2727
override val coroutineContext: CoroutineContext
2828
get() = Dispatchers.Default
2929

30-
abstract fun Image.applyImage(imageView: ImageView, placeholderResId: Int)
30+
abstract fun Image.applyImage(imageView: ImageView, placeholderResId: Int, onImageApplied: (() -> Unit)? = null)
3131

3232
abstract fun Image.applyBackground(view: View, placeholderResId: Int)
3333

@@ -43,8 +43,9 @@ abstract class ImageProcessors : CoroutineScope {
4343
map[imageClass] = imageProcessor
4444
}
4545

46-
override fun Image.applyImage(imageView: ImageView, placeholderResId: Int) = with(getImageProcessor()) {
46+
override fun Image.applyImage(imageView: ImageView, placeholderResId: Int, onImageApplied: (() -> Unit)?): Unit = with(getImageProcessor()) {
4747
applyImage(imageView, placeholderResId)
48+
onImageApplied?.invoke()
4849
}
4950

5051
override fun Image.applyBackground(view: View, placeholderResId: Int) = with(getImageProcessor()) {

omegatypes/src/main/java/com/omega_r/libs/omegatypes/image/UrlImage.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,37 @@ import com.omega_r.libs.omegatypes.decoders.toBitmap
66
import java.io.IOException
77
import java.net.HttpURLConnection
88
import java.net.URL
9+
import java.util.regex.Pattern
910

1011

1112
/**
1213
* Created by Anton Knyazev on 2019-10-03.
1314
*/
14-
data class UrlImage(val url: String) : BaseBitmapImage() {
15+
data class UrlImage(val baseUrl: String? = null, val relativeUrl: String) : BaseBitmapImage() {
1516

1617
companion object {
18+
private val PATTERN_ABSOLUTE_URL = Pattern.compile("\\A[a-z0-9.+-]+://.*", Pattern.CASE_INSENSITIVE)
19+
20+
var defaultBaseUrl: String? = null
1721

1822
init {
1923
ImageProcessors.default.addImageProcessor(UrlImage::class, Processor())
2024
}
2125

26+
private fun String.isAbsoluteUrl(): Boolean = PATTERN_ABSOLUTE_URL.matcher(this).matches()
27+
2228
}
2329

30+
31+
val url: String
32+
get() = if (relativeUrl.isAbsoluteUrl()) relativeUrl else {
33+
val baseUrl = (baseUrl ?: defaultBaseUrl ?: "").removeSuffix("/")
34+
val relativeUrl = relativeUrl.removePrefix("/")
35+
"$baseUrl/$relativeUrl"
36+
}
37+
38+
constructor(url: String) : this(null, url)
39+
2440
class Processor : BaseBitmapImage.Processor<UrlImage>(true) {
2541

2642

0 commit comments

Comments
 (0)