From ac104741f475c8b1b693ee462c5437aa121874da Mon Sep 17 00:00:00 2001 From: rumboalla Date: Wed, 16 Aug 2023 00:17:40 +0200 Subject: [PATCH] Added What's New F-Droid source will check apk signature --- .../data/apkmirror/AppExistsResponseApk.kt | 7 +++-- .../com/apkupdater/data/fdroid/FdroidApp.kt | 4 ++- .../apkupdater/data/fdroid/FdroidLocalized.kt | 7 +++++ .../apkupdater/data/fdroid/FdroidUpdate.kt | 3 +- .../apkupdater/data/github/GitHubRelease.kt | 3 +- .../java/com/apkupdater/data/ui/AppUpdate.kt | 3 +- .../repository/ApkMirrorRepository.kt | 2 +- .../apkupdater/repository/FdroidRepository.kt | 8 +++++ .../apkupdater/repository/GitHubRepository.kt | 6 ++-- .../java/com/apkupdater/ui/component/Text.kt | 27 ++++++++++++++++- .../apkupdater/ui/component/TvComponents.kt | 16 ++++++++++ .../apkupdater/ui/component/UiComponents.kt | 4 +-- .../com/apkupdater/ui/screen/AppsScreen.kt | 8 ++++- .../com/apkupdater/ui/screen/SearchScreen.kt | 6 ++-- .../apkupdater/ui/screen/SettingsScreen.kt | 5 ++-- .../com/apkupdater/ui/screen/UpdatesScreen.kt | 8 ++++- .../java/com/apkupdater/util/Extensions.kt | 30 +++++++++++++++++++ 17 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/apkupdater/data/fdroid/FdroidLocalized.kt diff --git a/app/src/main/java/com/apkupdater/data/apkmirror/AppExistsResponseApk.kt b/app/src/main/java/com/apkupdater/data/apkmirror/AppExistsResponseApk.kt index 2ad58eaa..f7fd661a 100644 --- a/app/src/main/java/com/apkupdater/data/apkmirror/AppExistsResponseApk.kt +++ b/app/src/main/java/com/apkupdater/data/apkmirror/AppExistsResponseApk.kt @@ -20,14 +20,15 @@ data class AppExistsResponseApk( val signaturesSha256: List? = emptyList() ) -fun AppExistsResponseApk.toAppUpdate(app: AppInstalled, version: String) = AppUpdate( +fun AppExistsResponseApk.toAppUpdate(app: AppInstalled, release: AppExistsResponseRelease) = AppUpdate( app.name, app.packageName, - version, + release.version, app.version, versionCode, app.versionCode, ApkMirrorSource, app.iconUri, - "https://www.apkmirror.com$link" + "https://www.apkmirror.com$link", + release.whatsNew.orEmpty() ) diff --git a/app/src/main/java/com/apkupdater/data/fdroid/FdroidApp.kt b/app/src/main/java/com/apkupdater/data/fdroid/FdroidApp.kt index ac142ac0..6648d097 100644 --- a/app/src/main/java/com/apkupdater/data/fdroid/FdroidApp.kt +++ b/app/src/main/java/com/apkupdater/data/fdroid/FdroidApp.kt @@ -8,5 +8,7 @@ data class FdroidApp( val suggestedVersionCode: String = "", val suggestedVersionName: String = "", val added: Long = 0L, - val lastUpdated: Long = 0L + val lastUpdated: Long = 0L, + val allowedAPKSigningKeys: List = emptyList(), + val localized: Map = emptyMap() ) diff --git a/app/src/main/java/com/apkupdater/data/fdroid/FdroidLocalized.kt b/app/src/main/java/com/apkupdater/data/fdroid/FdroidLocalized.kt new file mode 100644 index 00000000..a21328cd --- /dev/null +++ b/app/src/main/java/com/apkupdater/data/fdroid/FdroidLocalized.kt @@ -0,0 +1,7 @@ +package com.apkupdater.data.fdroid + + +data class FdroidLocalized( + val summary: String = "", + val whatsNew: String = "" +) diff --git a/app/src/main/java/com/apkupdater/data/fdroid/FdroidUpdate.kt b/app/src/main/java/com/apkupdater/data/fdroid/FdroidUpdate.kt index c61b4121..53392e6e 100644 --- a/app/src/main/java/com/apkupdater/data/fdroid/FdroidUpdate.kt +++ b/app/src/main/java/com/apkupdater/data/fdroid/FdroidUpdate.kt @@ -22,5 +22,6 @@ fun FdroidUpdate.toAppUpdate(current: AppInstalled?, source: Source) = AppUpdate "https://f-droid.org/assets/ic_repo_app_default.png".toUri() else "https://f-droid.org/repo/icons-640/${app.icon}".toUri(), - "https://f-droid.org/repo/${apk.apkName}" + "https://f-droid.org/repo/${apk.apkName}", + if (current != null) app.localized["en-US"]?.whatsNew.orEmpty() else app.localized["en-US"]?.summary.orEmpty() ) diff --git a/app/src/main/java/com/apkupdater/data/github/GitHubRelease.kt b/app/src/main/java/com/apkupdater/data/github/GitHubRelease.kt index 099c94c6..2d85cbf7 100644 --- a/app/src/main/java/com/apkupdater/data/github/GitHubRelease.kt +++ b/app/src/main/java/com/apkupdater/data/github/GitHubRelease.kt @@ -5,6 +5,7 @@ data class GitHubRelease( val name: String, val prerelease: Boolean, val assets: List, - val tag_name: String + val tag_name: String, + val body: String = "" ) diff --git a/app/src/main/java/com/apkupdater/data/ui/AppUpdate.kt b/app/src/main/java/com/apkupdater/data/ui/AppUpdate.kt index 5c8df511..b280981c 100644 --- a/app/src/main/java/com/apkupdater/data/ui/AppUpdate.kt +++ b/app/src/main/java/com/apkupdater/data/ui/AppUpdate.kt @@ -12,8 +12,9 @@ data class AppUpdate( val source: Source, val iconUri: Uri = Uri.EMPTY, val link: String = "", + val whatsNew: String = "", val isInstalling: Boolean = false, - val id: Int = "${source.name}.$packageName.$versionCode".hashCode() + val id: Int = "${source.name}.$packageName.$versionCode.$version".hashCode() ) fun List.indexOf(id: Int) = indexOfFirst { it.id == id } diff --git a/app/src/main/java/com/apkupdater/repository/ApkMirrorRepository.kt b/app/src/main/java/com/apkupdater/repository/ApkMirrorRepository.kt index 7d4f7684..859cdfe0 100644 --- a/app/src/main/java/com/apkupdater/repository/ApkMirrorRepository.kt +++ b/app/src/main/java/com/apkupdater/repository/ApkMirrorRepository.kt @@ -99,7 +99,7 @@ class ApkMirrorRepository( .filter { filterAndroidTv(it) } .filter { filterWearOS(it) } .maxByOrNull { it.versionCode } - ?.toAppUpdate(apps.getApp(data.pname)!!, data.release.version) + ?.toAppUpdate(apps.getApp(data.pname)!!, data.release) } private fun filterSignature(apk: AppExistsResponseApk, signature: String?) = when { diff --git a/app/src/main/java/com/apkupdater/repository/FdroidRepository.kt b/app/src/main/java/com/apkupdater/repository/FdroidRepository.kt index 98686046..ba88cc8f 100644 --- a/app/src/main/java/com/apkupdater/repository/FdroidRepository.kt +++ b/app/src/main/java/com/apkupdater/repository/FdroidRepository.kt @@ -2,6 +2,7 @@ package com.apkupdater.repository import android.os.Build import android.util.Log +import com.apkupdater.data.fdroid.FdroidApp import com.apkupdater.data.fdroid.FdroidData import com.apkupdater.data.fdroid.FdroidUpdate import com.apkupdater.data.fdroid.toAppUpdate @@ -34,6 +35,7 @@ class FdroidRepository( val updates = data.apps .asSequence() .filter { appNames.contains(it.packageName) } + .filter { filterSignature(apps.getApp(it.packageName)!!, it) } .map { FdroidUpdate(data.packages[it.packageName]!![0], it) } .filter { it.apk.versionCode > apps.getVersionCode(it.app.packageName) } .parseUpdates(apps) @@ -65,6 +67,12 @@ class FdroidRepository( .map { it.toAppUpdate(apps?.getApp(it.app.packageName), source) } .toList() + private fun filterSignature(installed: AppInstalled, update: FdroidApp) = when { + update.allowedAPKSigningKeys.isEmpty() -> true + update.allowedAPKSigningKeys.contains(installed.signature) -> true + else -> false + } + private fun filterAlpha(update: FdroidUpdate) = when { prefs.ignoreAlpha.get() && update.apk.versionName.contains("alpha") -> false else -> true diff --git a/app/src/main/java/com/apkupdater/repository/GitHubRepository.kt b/app/src/main/java/com/apkupdater/repository/GitHubRepository.kt index 2d3f3eac..d25602f3 100644 --- a/app/src/main/java/com/apkupdater/repository/GitHubRepository.kt +++ b/app/src/main/java/com/apkupdater/repository/GitHubRepository.kt @@ -51,7 +51,8 @@ class GitHubRepository( versionCode = versions.second, oldVersionCode = BuildConfig.VERSION_CODE.toLong(), source = GitHubSource, - link = releases[0].assets[0].browser_download_url + link = releases[0].assets[0].browser_download_url, + whatsNew = releases[0].body ))) } else { // We need to emit empty so it can be combined later @@ -80,7 +81,8 @@ class GitHubRepository( versionCode = 0L, oldVersionCode = app?.versionCode ?: 0L, source = GitHubSource, - link = release.assets[0].browser_download_url + link = release.assets[0].browser_download_url, + whatsNew = release.body ))) } else { emit(emptyList()) diff --git a/app/src/main/java/com/apkupdater/ui/component/Text.kt b/app/src/main/java/com/apkupdater/ui/component/Text.kt index e375325e..890e4e54 100644 --- a/app/src/main/java/com/apkupdater/ui/component/Text.kt +++ b/app/src/main/java/com/apkupdater/ui/component/Text.kt @@ -1,11 +1,13 @@ package com.apkupdater.ui.component +import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.RepeatMode import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.tween import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope @@ -19,10 +21,13 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -46,7 +51,8 @@ fun TextBubble(text: String, modifier: Modifier = Modifier) = Text( .background( color = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.7f), shape = RoundedCornerShape(16.dp) - ).then(modifier), + ) + .then(modifier), text = " $text " ) @@ -146,3 +152,22 @@ fun BadgeText(number: String) { } } } + +@Composable +fun ExpandingAnnotatedText( + text: AnnotatedString, + modifier: Modifier = Modifier, + minLines: Int = 2, + style: TextStyle = MaterialTheme.typography.bodySmall, +) { + var isExpanded by remember { mutableStateOf(false) } + Text( + text = if (text.text.last() == '\n') text.subSequence(0, text.length - 1) else text, + maxLines = if (isExpanded) Int.MAX_VALUE else minLines, + style = style, + overflow = TextOverflow.Ellipsis, + modifier = modifier + .clickable(true) { isExpanded = !isExpanded } + .animateContentSize(), + ) +} diff --git a/app/src/main/java/com/apkupdater/ui/component/TvComponents.kt b/app/src/main/java/com/apkupdater/ui/component/TvComponents.kt index cde4f9f6..820788c3 100644 --- a/app/src/main/java/com/apkupdater/ui/component/TvComponents.kt +++ b/app/src/main/java/com/apkupdater/ui/component/TvComponents.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -22,10 +23,12 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.core.text.HtmlCompat import com.apkupdater.R import com.apkupdater.data.ui.AppInstalled import com.apkupdater.data.ui.AppUpdate import com.apkupdater.util.getAppName +import com.apkupdater.util.toAnnotatedString @Composable @@ -110,6 +113,7 @@ fun TvInstalledItem(app: AppInstalled, onIgnore: (String) -> Unit = {}) = Card( fun TvUpdateItem(app: AppUpdate, onInstall: (String) -> Unit = {}) = Card { Column { TvCommonItem(app.packageName, app.name, app.version, app.oldVersion, app.versionCode, app.oldVersionCode) + WhatsNew(app.whatsNew) Box { TvSourceIcon(app) Row(modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.End) { @@ -123,6 +127,7 @@ fun TvUpdateItem(app: AppUpdate, onInstall: (String) -> Unit = {}) = Card { fun TvSearchItem(app: AppUpdate, onInstall: (String) -> Unit = {}) = Card { Column { TvCommonItem(app.packageName, app.name, app.version, app.oldVersion, app.versionCode, app.oldVersionCode, app.iconUri, true) + WhatsNew(app.whatsNew) Box { TvSourceIcon(app) Row(modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.End) { @@ -131,3 +136,14 @@ fun TvSearchItem(app: AppUpdate, onInstall: (String) -> Unit = {}) = Card { } } } + +@Composable +fun WhatsNew(whatsNew: String) { + if (whatsNew.isNotEmpty()) { + val spanned = HtmlCompat.fromHtml(whatsNew.trim(), HtmlCompat.FROM_HTML_MODE_COMPACT) + ExpandingAnnotatedText( + spanned.toAnnotatedString(), + Modifier.padding(8.dp).fillMaxWidth() + ) + } +} diff --git a/app/src/main/java/com/apkupdater/ui/component/UiComponents.kt b/app/src/main/java/com/apkupdater/ui/component/UiComponents.kt index 3062835f..fe2bd6ee 100644 --- a/app/src/main/java/com/apkupdater/ui/component/UiComponents.kt +++ b/app/src/main/java/com/apkupdater/ui/component/UiComponents.kt @@ -41,7 +41,7 @@ fun UpdateImage(app: AppUpdate, onInstall: (String) -> Unit = {}) = Box { Modifier .align(Alignment.TopStart) .padding(4.dp) - .size(32.dp) + .size(28.dp) ) } @@ -56,7 +56,7 @@ fun SearchImage(app: AppUpdate, onInstall: (String) -> Unit = {}) = Box { Modifier .align(Alignment.TopStart) .padding(4.dp) - .size(32.dp) + .size(28.dp) ) } diff --git a/app/src/main/java/com/apkupdater/ui/screen/AppsScreen.kt b/app/src/main/java/com/apkupdater/ui/screen/AppsScreen.kt index fa963c95..47f89291 100644 --- a/app/src/main/java/com/apkupdater/ui/screen/AppsScreen.kt +++ b/app/src/main/java/com/apkupdater/ui/screen/AppsScreen.kt @@ -1,6 +1,8 @@ package com.apkupdater.ui.screen +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Home @@ -11,8 +13,12 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.tv.foundation.lazy.grid.items import com.apkupdater.R @@ -92,7 +98,7 @@ fun AppsTopBar( } }, navigationIcon = { - IconButton(onClick = {}) { + Box(Modifier.minimumInteractiveComponentSize().size(40.dp), Alignment.Center) { Icon(Icons.Filled.Home, "Tab Icon") } } diff --git a/app/src/main/java/com/apkupdater/ui/screen/SearchScreen.kt b/app/src/main/java/com/apkupdater/ui/screen/SearchScreen.kt index 4f45b09b..7ea5b70a 100644 --- a/app/src/main/java/com/apkupdater/ui/screen/SearchScreen.kt +++ b/app/src/main/java/com/apkupdater/ui/screen/SearchScreen.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -11,19 +12,20 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester @@ -99,7 +101,7 @@ fun SearchTopBar(viewModel: SearchViewModel) = TopAppBar( colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.statusBarColor()), actions = {}, navigationIcon = { - IconButton(onClick = {}) { + Box(Modifier.minimumInteractiveComponentSize().size(40.dp), Alignment.Center) { Icon(Icons.Filled.Search, "Tab Icon") } } diff --git a/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt b/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt index cb9c5376..3b5f75ac 100644 --- a/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt +++ b/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt @@ -19,6 +19,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.CenterHorizontally @@ -213,7 +214,7 @@ fun SettingsTopBar(viewModel: SettingsViewModel) = TopAppBar( } }, navigationIcon = { - IconButton(onClick = {}) { + Box(Modifier.minimumInteractiveComponentSize().size(40.dp), Alignment.Center) { Icon(Icons.Filled.Settings, "Tab Icon") } } @@ -230,7 +231,7 @@ fun AboutTopBar(viewModel: SettingsViewModel) = TopAppBar( } }, navigationIcon = { - IconButton(onClick = {}) { + Box(Modifier.minimumInteractiveComponentSize().size(40.dp), Alignment.Center) { Icon(Icons.Filled.Info, "Tab Icon") } } diff --git a/app/src/main/java/com/apkupdater/ui/screen/UpdatesScreen.kt b/app/src/main/java/com/apkupdater/ui/screen/UpdatesScreen.kt index 153fd640..1cf27372 100644 --- a/app/src/main/java/com/apkupdater/ui/screen/UpdatesScreen.kt +++ b/app/src/main/java/com/apkupdater/ui/screen/UpdatesScreen.kt @@ -1,6 +1,8 @@ package com.apkupdater.ui.screen +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ThumbUp @@ -11,10 +13,14 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.UriHandler import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.tv.foundation.lazy.grid.items import com.apkupdater.R @@ -57,7 +63,7 @@ fun UpdatesTopBar(viewModel: UpdatesViewModel) = TopAppBar( } }, navigationIcon = { - IconButton(onClick = {}) { + Box(Modifier.minimumInteractiveComponentSize().size(40.dp), Alignment.Center) { Icon(Icons.Filled.ThumbUp, "Tab Icon") } } diff --git a/app/src/main/java/com/apkupdater/util/Extensions.kt b/app/src/main/java/com/apkupdater/util/Extensions.kt index c90cfb19..04fcae81 100644 --- a/app/src/main/java/com/apkupdater/util/Extensions.kt +++ b/app/src/main/java/com/apkupdater/util/Extensions.kt @@ -6,10 +6,22 @@ import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.content.res.Configuration import android.content.res.Resources +import android.graphics.Typeface import android.os.Build +import android.text.Spanned +import android.text.style.ForegroundColorSpan +import android.text.style.StyleSpan +import android.text.style.UnderlineSpan import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -97,3 +109,21 @@ fun Context.isAndroidTv() = packageManager.isAndroidTv() fun randomUUID() = UUID.randomUUID().toString() fun isDark() = Resources.getSystem().configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES + +fun Spanned.toAnnotatedString(): AnnotatedString = buildAnnotatedString { + val spanned = this@toAnnotatedString + append(spanned.toString()) + getSpans(0, spanned.length, Any::class.java).forEach { span -> + val start = getSpanStart(span) + val end = getSpanEnd(span) + when (span) { + is StyleSpan -> when (span.style) { + Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end) + Typeface.ITALIC -> addStyle(SpanStyle(fontStyle = FontStyle.Italic), start, end) + Typeface.BOLD_ITALIC -> addStyle(SpanStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic), start, end) + } + is UnderlineSpan -> addStyle(SpanStyle(textDecoration = TextDecoration.Underline), start, end) + is ForegroundColorSpan -> addStyle(SpanStyle(color = Color(span.foregroundColor)), start, end) + } + } +}