├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── io │ │ └── github │ │ └── armcha │ │ ├── MainActivity.kt │ │ ├── RecyclerViewActivity.kt │ │ └── StaticTextActivity.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── github_circle.xml │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_recycler_view.xml │ ├── activity_static_text.xml │ └── recycler_item.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── autolinklibrary ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── io │ │ └── github │ │ └── armcha │ │ └── autolink │ │ ├── AutoLinkItem.kt │ │ ├── AutoLinkTextView.kt │ │ ├── LinkTouchMovementMethod.kt │ │ ├── Mode.kt │ │ ├── Regex.kt │ │ └── TouchableSpan.kt │ └── res │ └── values │ └── colors.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screens ├── AutoLinkTextView.apk ├── custom.png ├── gmail.png ├── hashtag.png ├── mention.png ├── phone.png ├── recycler.png ├── recycler_gif.gif ├── static.png ├── static_gif.gif ├── transformation_after.png ├── transformation_before.png └── url.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | /.idea/ 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoLinkTextView V2 2 | 3 | [1]: https://github.com/armcha/AutoLinkTextView 4 | AutoLinkTextViewV2 is the new version of the [AutoLinkTextView][1]. 5 | 6 | **The main differences between the old and new version are** 7 | - Fully migration to Kotlin 8 | - Added several new features 9 | - Some improvements and fixes 10 | 11 | **It supports automatic detection and click handling for** 12 | * Hashtags (#) 13 | * Mentions (@) 14 | * URLs (https://) 15 | * Phone Numbers 16 | * Emails 17 | * Multiple Custom Regex 18 | 19 | . 20 | 21 | 22 | The current minSDK version is API level 16. 23 | 24 | ### Download sample [apk][77] 25 | [77]: https://github.com/armcha/AutoLinkTextViewV2/blob/master/screens/AutoLinkTextView.apk 26 | 27 | ### Features 28 | 29 | * Default support for **Hashtag, Mention, Link, Phone number and Email** 30 | * Support for **custom types** via regex 31 | * Transform url to short clickable text 32 | * Ability to apply **multiple spans** to any mode 33 | * Ability to set specific text color 34 | * Ability to set pressed state color 35 | 36 | ----------------------- 37 | 38 | ### Download 39 | 40 | Gradle: 41 | ```groovy 42 | implementation 'com.github.armcha:AutoLinkTextViewV2:3.0.0' 43 | ``` 44 | 45 | ### Setup and Usage 46 | 47 | Add AutoLinkTextView to your layout 48 | ```xml 49 | 53 | ``` 54 | 55 | ```kotlin 56 | val autoLinkTextView = findViewById(R.id.autolinkTextView); 57 | ``` 58 | 59 | Add one or multiple modes 60 | ```kotlin 61 | autoLinkTextView.addAutoLinkMode( 62 | MODE_HASHTAG, 63 | MODE_URL) 64 | ``` 65 | ----------------------- 66 | Add url transformations for transforming them to short clickable text 67 | ```kotlin 68 | autoLinkTextView.addUrlTransformations( 69 | "https://google.com" to "Google", 70 | "https://en.wikipedia.org/wiki/Wear_OS" to "Wear OS") 71 | ``` 72 | 73 | Or you can attach urlProcessor and transform it 74 | ```kotlin 75 | autoLinkTextView.attachUrlProcessor { originalUrl: String -> 76 | when { 77 | originalUrl.startsWith("https://en.wikipedia") -> "Wiki" 78 | originalUrl.contains("android") -> "Android" 79 | else -> originalUrl 80 | } 81 | } 82 | ``` 83 | 84 | 85 | ----------------------- 86 | Add one or multiple spans to specific mode 87 | ```kotlin 88 | autoLinkTextView.addSpan(MODE_URL, StyleSpan(Typeface.ITALIC), UnderlineSpan()) 89 | autoLinkTextView.addSpan(MODE_HASHTAG, UnderlineSpan(), TypefaceSpan("monospace")) 90 | ``` 91 | ----------------------- 92 | Set AutoLinkTextView click listener 93 | ```kotlin 94 | autoLinkTextView.onAutoLinkClick { item: AutoLinkItem -> 95 | } 96 | ``` 97 | ----------------------- 98 | Set text to AutoLinkTextView 99 | ```kotlin 100 | autoLinkTextView.text = getString(R.string.android_text) 101 | ``` 102 | 103 | 104 | Customizing 105 | --------- 106 | 107 | All possible modes 108 | 109 | #### MODE_PHONE 110 | 111 | 112 | 113 | #### MODE_HASHTAG 114 | 115 | 116 | 117 | #### MODE_URL 118 | 119 | 120 | 121 | #### MODE_MENTION 122 | 123 | 124 | 125 | #### MODE_EMAIL 126 | 127 | 128 | 129 | #### MODE_CUSTOM 130 | 131 | 132 | 133 | For use of custom mode you can add multiple custom regex 134 | 135 | ```kotlin 136 | val custom = MODE_CUSTOM("\\sAndroid\\b", "\\sGoogle\\b") 137 | ``` 138 | ------------------------- 139 | You can change text color for the specific mode 140 | ```kotlin 141 | autoLinkTextView.hashTagModeColor = ContextCompat.getColor(this, R.color.color2) 142 | autoLinkTextView.phoneModeColor = ContextCompat.getColor(this, R.color.color3) 143 | ``` 144 | ------------------------- 145 | You can also change pressed text color 146 | ```kotlin 147 | autoLinkTextView.pressedTextColor = ContextCompat.getColor(this, R.color.pressedTextColor) 148 | ``` 149 | 150 | ### Contact :book: 151 | 152 | :arrow_forward: **Email**: chatikyana@gmail.com 153 | 154 | :arrow_forward: **LinkedIn**: https://www.linkedin.com/in/chatikyan 155 | 156 | :arrow_forward: **Medium**: https://medium.com/@chatikyan 157 | 158 | :arrow_forward: **Twitter**: https://twitter.com/ChatikyanArman 159 | 160 | License 161 | -------- 162 | 163 | 164 | Auto Link TextView V2 library for Android 165 | Copyright (c) 2021 Arman Chatikyan (https://github.com/armcha/AutoLinkTextViewV2). 166 | 167 | Licensed under the Apache License, Version 2.0 (the "License"); 168 | you may not use this file except in compliance with the License. 169 | You may obtain a copy of the License at 170 | 171 | http://www.apache.org/licenses/LICENSE-2.0 172 | 173 | Unless required by applicable law or agreed to in writing, software 174 | distributed under the License is distributed on an "AS IS" BASIS, 175 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 176 | See the License for the specific language governing permissions and 177 | limitations under the License. 178 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android-extensions' 3 | apply plugin: 'kotlin-android' 4 | 5 | android { 6 | compileSdkVersion 29 7 | buildToolsVersion "29.0.2" 8 | 9 | defaultConfig { 10 | applicationId "io.github.armcha" 11 | minSdkVersion 16 12 | targetSdkVersion 29 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 29 | androidTestCompile('androidx.test.espresso:espresso-core:3.1.0', { 30 | exclude group: 'com.android.support', module: 'support-annotations' 31 | }) 32 | implementation 'androidx.appcompat:appcompat:1.1.0' 33 | implementation project(':autolinklibrary') 34 | testImplementation 'junit:junit:4.12' 35 | implementation 'androidx.core:core-ktx:+' 36 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 37 | implementation 'androidx.recyclerview:recyclerview:1.0.0' 38 | implementation 'androidx.cardview:cardview:1.0.0' 39 | } 40 | repositories { 41 | mavenCentral() 42 | } 43 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Chatikyan\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/armcha/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package io.github.armcha 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import androidx.appcompat.app.AlertDialog 8 | import androidx.appcompat.app.AppCompatActivity 9 | import kotlinx.android.synthetic.main.activity_main.* 10 | 11 | 12 | class MainActivity : AppCompatActivity() { 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | setContentView(R.layout.activity_main) 17 | 18 | staticTextButton.setOnClickListener { 19 | startActivity(Intent(this, StaticTextActivity::class.java)) 20 | } 21 | recyclerViewButton.setOnClickListener { 22 | startActivity(Intent(this, RecyclerViewActivity::class.java)) 23 | } 24 | githubIcon.setOnClickListener { 25 | browse("https://github.com/armcha/AutoLinkTextViewV2") 26 | } 27 | } 28 | } 29 | 30 | fun Context.showDialog(title: String, message: String, url: String? = null) { 31 | val builder = AlertDialog.Builder(this) 32 | .setMessage(message) 33 | .setTitle(title) 34 | .setPositiveButton("OK") { dialog, _ -> dialog.dismiss() } 35 | if (url != null) { 36 | builder.setNegativeButton("Browse") { dialog, _ -> browse(url);dialog.dismiss() } 37 | } 38 | builder.create().show() 39 | } 40 | 41 | fun Context.browse(url: String) { 42 | val intent = Intent(Intent.ACTION_VIEW) 43 | intent.data = Uri.parse(url) 44 | startActivity(intent) 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/armcha/RecyclerViewActivity.kt: -------------------------------------------------------------------------------- 1 | package io.github.armcha 2 | 3 | import android.graphics.Color 4 | import android.graphics.Typeface 5 | import android.os.Bundle 6 | import android.text.style.BackgroundColorSpan 7 | import android.text.style.ForegroundColorSpan 8 | import android.text.style.StyleSpan 9 | import android.text.style.UnderlineSpan 10 | import android.view.ViewGroup 11 | import android.widget.Toast 12 | import androidx.appcompat.app.AppCompatActivity 13 | import androidx.core.content.ContextCompat 14 | import androidx.recyclerview.widget.RecyclerView 15 | import io.github.armcha.autolink.* 16 | import kotlinx.android.synthetic.main.activity_recycler_view.* 17 | import kotlinx.android.synthetic.main.recycler_item.view.* 18 | 19 | 20 | class RecyclerViewActivity : AppCompatActivity() { 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | setContentView(R.layout.activity_recycler_view) 25 | 26 | recyclerView.adapter = object : RecyclerView.Adapter() { 27 | 28 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 29 | val view = layoutInflater.inflate(R.layout.recycler_item, parent, false) 30 | return object : RecyclerView.ViewHolder(view) {} 31 | } 32 | 33 | override fun getItemCount() = 200 34 | 35 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 36 | 37 | val autoLinkTextView = holder.itemView.autoLinkTextView 38 | val context = holder.itemView.context 39 | val custom = MODE_CUSTOM("\\sAndroid\\b") 40 | 41 | autoLinkTextView.addAutoLinkMode( 42 | MODE_HASHTAG, 43 | MODE_URL, 44 | MODE_PHONE, 45 | MODE_EMAIL, 46 | custom, 47 | MODE_MENTION) 48 | 49 | autoLinkTextView.addUrlTransformations( 50 | "https://google.com" to "Google", 51 | "https://en.wikipedia.org/wiki/Cyberpunk_2077" to "Cyberpunk", 52 | "https://en.wikipedia.org/wiki/Fire_OS" to "FIRE", 53 | "https://en.wikipedia.org/wiki/Wear_OS" to "Wear OS") 54 | 55 | autoLinkTextView.addSpan(MODE_URL, StyleSpan(Typeface.BOLD_ITALIC), UnderlineSpan()) 56 | autoLinkTextView.addSpan(custom, StyleSpan(Typeface.BOLD)) 57 | autoLinkTextView.addSpan(MODE_HASHTAG, BackgroundColorSpan(Color.GRAY), UnderlineSpan(), ForegroundColorSpan(Color.WHITE)) 58 | 59 | autoLinkTextView.hashTagModeColor = ContextCompat.getColor(context, R.color.color2) 60 | autoLinkTextView.customModeColor = ContextCompat.getColor(context, R.color.color1) 61 | autoLinkTextView.mentionModeColor = ContextCompat.getColor(context, R.color.color3) 62 | autoLinkTextView.emailModeColor = ContextCompat.getColor(context, R.color.colorPrimary) 63 | autoLinkTextView.phoneModeColor = ContextCompat.getColor(context, R.color.colorAccent) 64 | 65 | val text = when { 66 | position % 3 == 1 -> R.string.android_text_short 67 | position % 3 == 2 -> R.string.android_text_short_second 68 | else -> R.string.text_third 69 | } 70 | 71 | autoLinkTextView.text = getString(text) 72 | 73 | autoLinkTextView.onAutoLinkClick { 74 | val message = if (it.originalText == it.transformedText) it.originalText 75 | else "Original text - ${it.originalText} \n\nTransformed text - ${it.transformedText}" 76 | val url = if (it.mode is MODE_URL) it.originalText else null 77 | showDialog(it.mode.modeName, message, url) 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/armcha/StaticTextActivity.kt: -------------------------------------------------------------------------------- 1 | package io.github.armcha 2 | 3 | import android.graphics.Typeface 4 | import android.os.Bundle 5 | import android.text.style.StyleSpan 6 | import android.text.style.TypefaceSpan 7 | import android.text.style.UnderlineSpan 8 | import androidx.appcompat.app.AppCompatActivity 9 | import androidx.core.content.ContextCompat 10 | import io.github.armcha.autolink.* 11 | import kotlinx.android.synthetic.main.activity_static_text.* 12 | 13 | class StaticTextActivity : AppCompatActivity() { 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.activity_static_text) 18 | 19 | val custom = MODE_CUSTOM("\\sAndroid\\b", "\\smobile\\b") 20 | autoLinkTextView.addAutoLinkMode( 21 | MODE_HASHTAG, 22 | MODE_EMAIL, 23 | MODE_URL, 24 | MODE_PHONE, 25 | custom, 26 | MODE_MENTION) 27 | 28 | autoLinkTextView.addUrlTransformations( 29 | "https://en.wikipedia.org/wiki/Wear_OS" to "Wear OS", 30 | "https://en.wikipedia.org/wiki/Fire_OS" to "FIRE") 31 | 32 | autoLinkTextView.attachUrlProcessor { 33 | when { 34 | it.contains("google") -> "Google" 35 | it.contains("github") -> "Github" 36 | else -> it 37 | } 38 | } 39 | 40 | autoLinkTextView.addSpan(MODE_URL, StyleSpan(Typeface.ITALIC), UnderlineSpan()) 41 | autoLinkTextView.addSpan(MODE_HASHTAG, UnderlineSpan(), TypefaceSpan("monospace")) 42 | autoLinkTextView.addSpan(custom, StyleSpan(Typeface.BOLD)) 43 | 44 | autoLinkTextView.hashTagModeColor = ContextCompat.getColor(this, R.color.color5) 45 | autoLinkTextView.phoneModeColor = ContextCompat.getColor(this, R.color.color3) 46 | autoLinkTextView.customModeColor = ContextCompat.getColor(this, R.color.color1) 47 | autoLinkTextView.mentionModeColor = ContextCompat.getColor(this, R.color.color6) 48 | autoLinkTextView.emailModeColor = ContextCompat.getColor(this, R.color.colorPrimary) 49 | 50 | autoLinkTextView.text = getString(R.string.android_text) 51 | 52 | autoLinkTextView.onAutoLinkClick { 53 | val message = if (it.originalText == it.transformedText) it.originalText 54 | else "Original text - ${it.originalText} \n\nTransformed text - ${it.transformedText}" 55 | val url = if (it.mode is MODE_URL) it.originalText else null 56 | showDialog(it.mode.modeName, message, url) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/github_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |