Skip to content

Commit

Permalink
v5.546
Browse files Browse the repository at this point in the history
  • Loading branch information
tateisu committed Mar 17, 2024
1 parent 6cd8839 commit 50d0139
Show file tree
Hide file tree
Showing 7 changed files with 442 additions and 2 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ android {
defaultConfig {
targetSdk = Vers.stTargetSdkVersion
minSdk = Vers.stMinSdkVersion
versionCode = 545
versionName = "5.545"
versionCode = 546
versionName = "5.546"
applicationId = "jp.juggler.subwaytooter"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package jp.juggler.subwaytooter.ui.ossLicense

import android.app.Application
import android.content.Context
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.util.StColorScheme
import jp.juggler.util.coroutine.AppDispatchers
import jp.juggler.util.data.decodeJsonObject
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class ActOSSLicenseViewModel(
application: Application,
) : AndroidViewModel(application) {
val context: Context
get() = getApplication<Application>().applicationContext

private val loadError = Channel<Throwable>(capacity = Channel.CONFLATED)

private val _libraries = MutableStateFlow<List<LibText>>(emptyList())
val libraries = _libraries.asStateFlow()

private val _isProgressShown = MutableStateFlow(false)
val isProgressShown = _isProgressShown.asStateFlow()

fun load(stColorScheme: StColorScheme) = viewModelScope.launch {
try {
_isProgressShown.value = true
_libraries.value = withContext(AppDispatchers.IO) {
val root = context.resources.openRawResource(R.raw.dep_list)
.use { it.readBytes() }
.decodeToString()
.decodeJsonObject()
val licenses = root.jsonArray("licenses")
?.objectList()
?.associateBy { it.string("shortName") }
?: emptyMap()
root.jsonArray("libs")
?.objectList()
?.map {
parseLibText(
it,
licenses,
stColorScheme = stColorScheme,
)
}
?.sortedBy { it.nameSort }
?: emptyList()
}
} catch (ex: Throwable) {
if (ex is CancellationException) return@launch
loadError.send(ex)
} finally {
_isProgressShown.value = false
}
}
}
92 changes: 92 additions & 0 deletions app/src/main/java/jp/juggler/subwaytooter/ui/ossLicense/LibText.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package jp.juggler.subwaytooter.ui.ossLicense

import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.buildAnnotatedString
import jp.juggler.subwaytooter.util.StColorScheme
import jp.juggler.subwaytooter.util.annotateUrl
import jp.juggler.subwaytooter.util.isNotEmpty
import jp.juggler.subwaytooter.util.joinAnnotatedString
import jp.juggler.subwaytooter.util.toAnnotatedString
import jp.juggler.util.data.JsonObject
import jp.juggler.util.data.notEmpty
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

/**
* 依存ライブラリの装飾付きテキスト
*/
class LibText(
val nameBig: AnnotatedString,
val nameSmall: AnnotatedString?,
val desc: AnnotatedString,
) {
val nameSort = nameBig.toString().lowercase()
}

/**
* レシーバの文字列がカラでなければdstに追加する
* @receiver 追加先
* @param text 装飾付き文字列
* @param prefix nullや空でなければtextより先に追加される
*/
private fun AnnotatedString.Builder.appendLine(
text: CharSequence?,
prefix: CharSequence? = null,
) {
if (text.isNullOrBlank()) return
if (isNotEmpty()) append("\n")
if (!prefix.isNullOrBlank()) append(prefix)
append(text)
}

/**
* ライブラリ情報をLibTextに変換する
*/
fun parseLibText(
lib: JsonObject,
licenses: Map<String?, JsonObject>,
stColorScheme: StColorScheme,
): LibText {
val colorLink = stColorScheme.colorTextLink

val webSite = lib.string("website")?.toHttpUrlOrNull()?.toString()
val name = lib.string("name")?.notEmpty()
val id = lib.string("id")?.notEmpty()

val nameBig: CharSequence
val nameSmall: CharSequence?
if (name.isNullOrBlank()) {
// nameがない場合はnameBigはidを大きく表示する
nameBig = (id ?: "(no name, no id)").annotateUrl(webSite, colorLink)
nameSmall = null
} else {
nameBig = name.annotateUrl(webSite, colorLink)
nameSmall = id
// idがない場合はnameSmallはnullとなる
}

val licenseText = lib.jsonArray("licenses")?.stringList()
?.asSequence()
?.mapNotNull { licenses[it] }
?.map {
val uri =
it.jsonArray("urls")?.stringList()?.firstOrNull()?.toHttpUrlOrNull()?.toString()
it.string("name")!!.annotateUrl(uri, colorLink)
}
?.toList()?.joinAnnotatedString(AnnotatedString(", "))

val devNames = lib.jsonArray("developers")?.objectList()
?.map { it.string("name") }
?.filter { !it.isNullOrBlank() }
?.joinToString(", ")

val libDesc = buildAnnotatedString {
appendLine(lib.string("description")?.takeIf { it != name })
appendLine(devNames, "- Developers: ")
appendLine(licenseText, "- License: ")
}
return LibText(
nameBig = nameBig.toAnnotatedString(),
nameSmall = nameSmall?.toAnnotatedString(),
desc = libDesc.toAnnotatedString(),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package jp.juggler.subwaytooter.util

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.TextUnit

fun CharSequence.toAnnotatedString() = when (this) {
is AnnotatedString -> this
else -> AnnotatedString(toString())
}

fun AnnotatedString.Builder.isEmpty() = length == 0
fun AnnotatedString.Builder.isNotEmpty() = length != 0

/**
* 装飾付き文字列のリストを連結する
* @receiver 装飾付き文字列のリスト
* @param separator 文字列と文字列の間に挿入される区切り
*/
fun List<CharSequence>.joinAnnotatedString(
separator: CharSequence,
): AnnotatedString = AnnotatedString.Builder().also { dst ->
for (item in this) {
if (dst.isNotEmpty()) dst.append(separator)
dst.append(item)
}
}.toAnnotatedString()

/**
* クリック可能な装飾付き文字列を作る
* @receiver 表示文字列
* @param uri クリックしたら開くUri。nullなら装飾しない
* @return CharSequence, 実際には Stringまたは AnnotatedString
*/
fun String.annotateUrl(
uri: String?,
colorLink: Color,
fontSize: TextUnit = TextUnit.Unspecified,
): CharSequence = when (uri) {
null -> this
else -> AnnotatedString.Builder().apply {
append(this@annotateUrl)
addStyle(
style = SpanStyle(
color = colorLink,
fontSize = fontSize,
textDecoration = TextDecoration.Underline
), start = 0, end = length
)
addStringAnnotation(
tag = "URL",
annotation = uri.toString(),
start = 0,
end = length,
)
}.toAnnotatedString()
}
116 changes: 116 additions & 0 deletions app/src/main/java/jp/juggler/subwaytooter/util/ComposeUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package jp.juggler.subwaytooter.util

import android.app.Activity
import android.content.Context
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.ui.graphics.Color
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.pref.PrefI
import jp.juggler.util.ui.resColor

class StColorScheme(
val materialColorScheme: ColorScheme,
val colorTextLink: Color,
)

fun Context.createStColorSchemeLight(): StColorScheme {
val colorTextContent = Color(resColor(R.color.Light_colorTextContent))
val colorTextError = Color(resColor(R.color.Light_colorRegexFilterError))
val colorTextLink = Color(resColor(R.color.Light_colorLink))
return StColorScheme(
materialColorScheme = lightColorScheme(
error = colorTextError,

background = Color.White,
onBackground = colorTextContent,

primary = colorTextLink,
onPrimary = Color.White,

secondary = colorTextLink,
onSecondary = Color.White,

surface = Color(resColor(R.color.Light_colorColumnSettingBackground)),
onSurface = colorTextContent,
onTertiary = colorTextContent,

onSurfaceVariant = Color(resColor(R.color.Light_colorTextHint)),
),
colorTextLink = colorTextLink,
)
}

fun Context.createStColorSchemeDark(): StColorScheme {
val colorBackground = Color(resColor(R.color.Dark_colorBackground))
val colorTextContent = Color(resColor(R.color.Dark_colorTextContent))
val colorTextError = Color(resColor(R.color.Dark_colorRegexFilterError))
val colorTextLink = Color(resColor(R.color.Dark_colorLink))
return StColorScheme(
materialColorScheme = darkColorScheme(
error = colorTextError,

background = colorBackground,
onBackground = colorTextContent,

primary = colorTextLink,
onPrimary = colorTextContent,

secondary = colorTextLink,
onSecondary = colorTextContent,

surface = Color(resColor(R.color.Dark_colorColumnSettingBackground)),
onSurface = colorTextContent,
onTertiary = colorTextContent,

onSurfaceVariant = Color(resColor(R.color.Dark_colorTextHint)),
),
colorTextLink = colorTextLink,
)
}

fun Context.createStColorSchemeMastodonDark(): StColorScheme {
val colorBackground = Color(resColor(R.color.Mastodon_colorBackground))
val colorTextContent = Color(resColor(R.color.Mastodon_colorTextContent))
val colorTextError = Color(resColor(R.color.Mastodon_colorRegexFilterError))
val colorTextLink = Color(resColor(R.color.Mastodon_colorLink))
return StColorScheme(
materialColorScheme = darkColorScheme(
error = colorTextError,

background = colorBackground,
onBackground = colorTextContent,

primary = Color(resColor(R.color.Mastodon_colorAppCompatAccent)),
onPrimary = colorTextContent,

secondary = colorTextLink,
onSecondary = colorTextContent,

surface = Color(resColor(R.color.Mastodon_colorColumnSettingBackground)),
onSurface = colorTextContent,
onTertiary = colorTextContent,

onSurfaceVariant = Color(resColor(R.color.Mastodon_colorTextHint)),
),
colorTextLink = colorTextLink,
)
}

fun Activity.getStColorTheme(forceDark: Boolean = false): StColorScheme {
App1.prepare(applicationContext, "getStColorTheme")
var nTheme = PrefI.ipUiTheme.value
if (forceDark && nTheme == 0) nTheme = 1
return when (nTheme) {
2 -> createStColorSchemeMastodonDark()
1 -> createStColorSchemeDark()
else -> createStColorSchemeLight()
}
}

fun dummyStColorTheme() = StColorScheme(
materialColorScheme = darkColorScheme(),
colorTextLink = Color.Cyan,
)
Loading

0 comments on commit 50d0139

Please sign in to comment.