Skip to content

Commit 0d9fe68

Browse files
Merge pull request #14 from Omega-R/develop
Add textstyle
2 parents 9b45fb8 + 8c29ed4 commit 0d9fe68

File tree

5 files changed

+198
-57
lines changed

5 files changed

+198
-57
lines changed
-28 Bytes
Binary file not shown.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class MainActivity : BaseActivity() {
1616
override fun onCreate(savedInstanceState: Bundle?) {
1717
super.onCreate(savedInstanceState)
1818
setContentView(R.layout.activity_main)
19-
val text = Text.from(R.string.hello_world)
19+
val text = Text.from("test ") + Text.from(R.string.hello_world, textStyle = TextStyle.bold())
2020
text.applyTo(exampleTextView) // or exampleTextView.setText(text)
2121
val image = Image.from("https://avatars1.githubusercontent.com/u/28600571")
2222

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

Lines changed: 100 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,63 +3,89 @@ package com.omega_r.libs.omegatypes
33
import android.app.Activity
44
import android.content.Context
55
import android.content.res.Resources
6+
import android.os.Build
7+
import android.text.SpannableString
8+
import android.text.SpannableStringBuilder
9+
import android.text.style.ForegroundColorSpan
610
import android.widget.EditText
711
import android.widget.TextView
812
import android.widget.Toast
913
import java.io.Serializable
1014
import java.util.*
1115
import kotlin.text.StringBuilder
1216

13-
open class Text : Serializable {
14-
15-
open fun isEmpty(): Boolean = true
16-
open fun getString(resources: Resources): String? = null
17-
18-
override fun equals(other: Any?): Boolean {
19-
if (this === other) return true
20-
if (javaClass != other?.javaClass) return false
21-
22-
other as Text
23-
24-
return other.isEmpty()
25-
}
26-
27-
override fun hashCode(): Int {
28-
return 31 * 17
29-
}
17+
open class Text(protected val defaultTextStyle: TextStyle? ) : Serializable {
3018

3119
companion object {
3220
@JvmStatic
33-
fun empty(): Text = Text()
21+
fun empty(): Text = Text(null)
3422

3523
@JvmStatic
36-
fun from(string: String): Text = StringText(string)
24+
@JvmOverloads
25+
fun from(string: String, textStyle: TextStyle? = null): Text = StringText(string, textStyle)
3726

3827
@JvmStatic
39-
fun from(stringRes: Int): Text = ResourceText(stringRes)
28+
@JvmOverloads
29+
fun from(stringRes: Int, textStyle: TextStyle? = null): Text = ResourceText(stringRes, textStyle)
4030

4131
@JvmStatic
42-
fun from(stringRes: Int, vararg formatArgs: Any): Text = FormatResourceText(stringRes, *formatArgs)
32+
@JvmOverloads
33+
fun from(stringRes: Int, vararg formatArgs: Any, textStyle: TextStyle? = null): Text = FormatResourceText(stringRes, *formatArgs, textStyle = textStyle)
4334

4435
@JvmStatic
45-
fun from(stringHolder: StringHolder): Text = stringHolder.getStringText()?.let { StringText(it) } ?: empty()
36+
@JvmOverloads
37+
fun from(stringHolder: StringHolder, textStyle: TextStyle? = null): Text = stringHolder.getStringText()?.let { from(it, textStyle) } ?: empty()
4638

4739
@JvmStatic
48-
fun from(throwable: Throwable): Text = StringText(throwable.message)
40+
@JvmOverloads
41+
fun from(throwable: Throwable, textStyle: TextStyle? = null): Text = StringText(throwable.message, textStyle)
4942

5043
@JvmStatic
51-
fun from(vararg texts: Text): Text = ArrayText(*texts)
44+
@JvmOverloads
45+
fun from(vararg texts: Text, textStyle: TextStyle? = null): Text = ArrayText(*texts, textStyle = textStyle)
5246

5347
@JvmStatic
54-
fun from(texts: List<Text>): Text = ArrayText(*texts.toTypedArray())
48+
@JvmOverloads
49+
fun from(texts: List<Text>, textStyle: TextStyle? = null): Text = ArrayText(*texts.toTypedArray(), textStyle = textStyle)
50+
51+
}
52+
53+
open fun isEmpty(): Boolean = true
54+
55+
open fun getString(context: Context): String? = null
56+
57+
open fun getCharSequence(context: Context, textStyle: TextStyle? = null): CharSequence? {
58+
return getString(context)?.let {
59+
(defaultTextStyle + textStyle)?.applyStyle(context, it) ?: it
60+
}
61+
}
62+
63+
open fun applyTo(textView: TextView, textStyle: TextStyle? = null) {
64+
textView.text = getCharSequence(textView.context, textStyle)
65+
}
66+
67+
override fun equals(other: Any?): Boolean {
68+
if (this === other) return true
69+
if (javaClass != other?.javaClass) return false
70+
71+
other as Text
72+
73+
return other.isEmpty()
74+
}
5575

76+
override fun hashCode(): Int {
77+
return 31 * 17
5678
}
5779

58-
private class StringText internal constructor(private val string: String?) : Text() {
80+
81+
private class StringText internal constructor(
82+
private val string: String?,
83+
textStyle: TextStyle?
84+
) : Text(textStyle) {
5985

6086
override fun isEmpty(): Boolean = string.isNullOrEmpty()
6187

62-
override fun getString(resources: Resources): String? {
88+
override fun getString(context: Context): String? {
6389
return string
6490
}
6591

@@ -80,12 +106,16 @@ open class Text : Serializable {
80106

81107
}
82108

83-
private class ResourceText internal constructor(private val stringRes: Int) : Text() {
109+
private class ResourceText internal constructor(
110+
private val stringRes: Int,
111+
textStyle: TextStyle?
112+
113+
) : Text(textStyle) {
84114

85115
override fun isEmpty(): Boolean = stringRes <= 0
86116

87-
override fun getString(resources: Resources): String {
88-
return resources.getString(stringRes)
117+
override fun getString(context: Context): String {
118+
return context.getString(stringRes)
89119
}
90120

91121
override fun equals(other: Any?): Boolean {
@@ -106,12 +136,13 @@ open class Text : Serializable {
106136
}
107137

108138
private class FormatResourceText internal constructor(private val stringRes: Int,
109-
private vararg val formatArgs: Any) : Text() {
139+
private vararg val formatArgs: Any,
140+
textStyle: TextStyle?) : Text(textStyle) {
110141

111142
override fun isEmpty(): Boolean = stringRes <= 0
112143

113-
override fun getString(resources: Resources): String {
114-
return resources.getString(stringRes, *formatArgs)
144+
override fun getString(context: Context): String {
145+
return context.getString(stringRes, *formatArgs)
115146
}
116147

117148
override fun equals(other: Any?): Boolean {
@@ -131,7 +162,10 @@ open class Text : Serializable {
131162

132163
}
133164

134-
private class ArrayText internal constructor(private vararg val texts: Text): Text() {
165+
private class ArrayText internal constructor(
166+
private vararg val texts: Text,
167+
textStyle: TextStyle?
168+
): Text(textStyle) {
135169

136170
override fun isEmpty(): Boolean {
137171
if (texts.isEmpty()) return false
@@ -143,14 +177,23 @@ open class Text : Serializable {
143177
return true
144178
}
145179

146-
override fun getString(resources: Resources): String? {
180+
override fun getString(context: Context): String? {
147181
val stringBuilder = StringBuilder()
148182
for (text in texts) {
149-
stringBuilder.append(text.getString(resources))
183+
stringBuilder.append(text.getString(context))
150184
}
151185
return stringBuilder.toString()
152186
}
153187

188+
override fun getCharSequence(context: Context, textStyle: TextStyle?): CharSequence? {
189+
val stringBuilder = SpannableStringBuilder()
190+
val newTextStyle = defaultTextStyle + textStyle
191+
for (text in texts) {
192+
stringBuilder.append(text.getCharSequence(context, newTextStyle))
193+
}
194+
return stringBuilder
195+
}
196+
154197
override fun equals(other: Any?): Boolean {
155198
if (this === other) return true
156199
if (javaClass != other?.javaClass) return false
@@ -180,32 +223,36 @@ open class Text : Serializable {
180223

181224
}
182225

183-
fun TextView.setText(text: Text?) {
184-
this.text = text?.getString(this.resources)
226+
fun TextView.setText(text: Text?, textStyle: TextStyle? = null) {
227+
if (text == null) {
228+
this.text = null
229+
} else {
230+
text.applyTo(this, textStyle)
231+
}
185232
}
186233

187-
fun EditText.setError(text: Text?) {
188-
this.error = text?.getString(this.resources)
234+
fun EditText.setError(text: Text?, textStyle: TextStyle? = null) {
235+
this.error = text?.getCharSequence(context, textStyle)
189236
}
190237

191-
fun EditText.setHint(text: Text?) {
192-
this.hint = text?.getString(this.resources)
238+
fun EditText.setHint(text: Text?, textStyle: TextStyle? = null) {
239+
this.hint = text?.getCharSequence(context, textStyle)
193240
}
194241

195-
fun Text?.applyTo(textView: TextView) {
196-
textView.setText(this)
242+
fun Text?.applyTo(textView: TextView, textStyle: TextStyle? = null) {
243+
textView.setText(this, textStyle)
197244
}
198245

199-
fun Text?.applyErrorTo(editText: EditText) {
200-
editText.setError(this)
246+
fun Text?.applyErrorTo(editText: EditText, textStyle: TextStyle? = null) {
247+
editText.setError(this, textStyle)
201248
}
202249

203-
fun Activity.setTitle(text: Text?) {
204-
title = text?.getString(resources)
250+
fun Activity.setTitle(text: Text?, textStyle: TextStyle? = null) {
251+
title = text?.getCharSequence(this, textStyle)
205252
}
206253

207-
fun Context.toast(text: Text, duration: Int = Toast.LENGTH_SHORT): Toast {
208-
return Toast.makeText(this, text.getString(resources), duration).apply { show() }
254+
fun Context.toast(text: Text, duration: Int = Toast.LENGTH_SHORT, textStyle: TextStyle? = null): Toast {
255+
return Toast.makeText(this, text.getCharSequence(this, textStyle), duration).apply { show() }
209256
}
210257

211258
operator fun Text.plus(text: Text) : Text {
@@ -222,4 +269,6 @@ operator fun Text.plus(string: String) : Text {
222269
return TextBuilder.BuilderText(this) + string
223270
}
224271

225-
fun String.toText() = Text.from(this)
272+
fun String.toText(textStyle: TextStyle? = null) = Text.from(this, textStyle)
273+
274+
operator fun Text.plus(textStyle: TextStyle) = Text.from(this, textStyle = textStyle)

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.omega_r.libs.omegatypes
22

3+
import android.content.Context
34
import android.content.res.Resources
45

56
/**
@@ -62,7 +63,7 @@ class TextBuilder(capacity: Int) {
6263
}
6364

6465

65-
class BuilderText(private val textBuilder: TextBuilder): Text() {
66+
class BuilderText(private val textBuilder: TextBuilder): Text(null) {
6667

6768
constructor(text: Text) : this(TextBuilder(text))
6869

@@ -74,8 +75,12 @@ class TextBuilder(capacity: Int) {
7475
return true
7576
}
7677

77-
override fun getString(resources: Resources): String? {
78-
return textBuilder.toText().getString(resources)
78+
override fun getString(context: Context): String? {
79+
return textBuilder.toText().getString(context)
80+
}
81+
82+
override fun getCharSequence(context: Context, textStyle: TextStyle?): CharSequence? {
83+
return textBuilder.toText().getCharSequence(context, textStyle)
7984
}
8085

8186
override fun equals(other: Any?): Boolean {
@@ -110,7 +115,6 @@ class TextBuilder(capacity: Int) {
110115
textBuilder.append(string)
111116
return this
112117
}
113-
114-
115118
}
119+
116120
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.omega_r.libs.omegatypes
2+
3+
import android.content.Context
4+
import android.graphics.*
5+
import android.os.Build
6+
import android.text.SpannableString
7+
import android.text.style.ForegroundColorSpan
8+
import android.text.style.StyleSpan
9+
10+
/**
11+
* Created by Anton Knyazev on 25.04.2019.
12+
*/
13+
abstract class TextStyle {
14+
15+
companion object {
16+
fun color(colorRes: Int): TextStyle = Color(colorRes)
17+
18+
fun bold(): TextStyle = TypeFaceStyle(Typeface.BOLD)
19+
20+
fun italic(): TextStyle = TypeFaceStyle(Typeface.ITALIC)
21+
22+
}
23+
24+
operator fun plus(textStyle: TextStyle?):TextStyle {
25+
val list = mutableListOf<TextStyle>().apply {
26+
addTextStyle(this@TextStyle)
27+
addTextStyle(textStyle)
28+
}
29+
30+
return Array(*list.toTypedArray())
31+
}
32+
33+
private fun MutableList<TextStyle>.addTextStyle(textStyle: TextStyle?) {
34+
if (textStyle is Array) {
35+
addAll(textStyle.textStyleArray)
36+
} else {
37+
textStyle?.let { add(textStyle) }
38+
}
39+
}
40+
41+
fun applyStyle(context: Context, charSequence: CharSequence): CharSequence {
42+
return getSpannableString(charSequence).apply {
43+
applyStyle(context)
44+
}
45+
}
46+
47+
protected abstract fun SpannableString.applyStyle(context: Context)
48+
49+
private fun getSpannableString(charSequence: CharSequence): SpannableString {
50+
return if (charSequence is SpannableString) charSequence else SpannableString(charSequence)
51+
}
52+
53+
private class Array(internal vararg val textStyleArray: TextStyle) : TextStyle() {
54+
55+
override fun SpannableString.applyStyle(context: Context) {
56+
textStyleArray.forEach {
57+
it.apply {
58+
applyStyle(context)
59+
}
60+
}
61+
}
62+
}
63+
64+
private class Color(private val colorRes: Int) : TextStyle() {
65+
66+
override fun SpannableString.applyStyle(context: Context) {
67+
val color = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
68+
context.getColor(colorRes)
69+
} else {
70+
context.resources.getColor(colorRes)
71+
}
72+
setSpan(ForegroundColorSpan(color), 0, length, 0)
73+
}
74+
75+
}
76+
77+
private class TypeFaceStyle(private val typeFaceStyle: Int) : TextStyle() {
78+
79+
override fun SpannableString.applyStyle(context: Context) {
80+
setSpan(StyleSpan(typeFaceStyle), 0, length, 0)
81+
}
82+
}
83+
84+
}
85+
86+
operator fun TextStyle?.plus(textStyle: TextStyle?): TextStyle? {
87+
return if (this == null) textStyle else this + textStyle
88+
}

0 commit comments

Comments
 (0)