OSSライセンス画面の書き直し

This commit is contained in:
tateisu 2024-03-18 00:54:05 +09:00
parent 15f54bdf00
commit 6cd8839bbd
14 changed files with 91 additions and 68 deletions

View File

@ -164,8 +164,8 @@ dependencies {
implementation(project(":apng_android")) implementation(project(":apng_android"))
implementation(project(":anko")) implementation(project(":anko"))
implementation("androidx.activity:activity-compose:${Vers.androidxActivity}") implementation("androidx.activity:activity-compose:${Vers.androidxActivity}")
implementation("androidx.activity:activity-ktx:${Vers.androidxActivity}")
implementation("androidx.appcompat:appcompat:${Vers.androidxAppcompat}") implementation("androidx.appcompat:appcompat:${Vers.androidxAppcompat}")
implementation("androidx.browser:browser:1.8.0") implementation("androidx.browser:browser:1.8.0")
implementation("androidx.compose.material3:material3:1.2.1") implementation("androidx.compose.material3:material3:1.2.1")

View File

@ -98,7 +98,6 @@
android:label="@string/app_name" android:label="@string/app_name"
android:largeHeap="true" android:largeHeap="true"
android:localeConfig="@xml/locales_config" android:localeConfig="@xml/locales_config"
android:maxAspectRatio="100"
android:resizeableActivity="true" android:resizeableActivity="true"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.App.Starting" android:theme="@style/Theme.App.Starting"

View File

@ -22,7 +22,6 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.jrummyapps.android.colorpicker.ColorPickerDialogType
import com.jrummyapps.android.colorpicker.dialogColorPicker import com.jrummyapps.android.colorpicker.dialogColorPicker
import jp.juggler.subwaytooter.api.TootApiClient import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.TootApiResult import jp.juggler.subwaytooter.api.TootApiResult

View File

@ -36,7 +36,6 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.jrummyapps.android.colorpicker.ColorPickerDialogType
import com.jrummyapps.android.colorpicker.dialogColorPicker import com.jrummyapps.android.colorpicker.dialogColorPicker
import jp.juggler.subwaytooter.appsetting.AppDataExporter import jp.juggler.subwaytooter.appsetting.AppDataExporter
import jp.juggler.subwaytooter.appsetting.AppSettingItem import jp.juggler.subwaytooter.appsetting.AppSettingItem

View File

@ -7,7 +7,6 @@ import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Handler import android.os.Handler
import android.util.Log import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.emoji2.bundled.BundledEmojiCompatConfig import androidx.emoji2.bundled.BundledEmojiCompatConfig
import androidx.emoji2.text.EmojiCompat import androidx.emoji2.text.EmojiCompat
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
@ -29,16 +28,21 @@ import jp.juggler.subwaytooter.util.CustomEmojiCache
import jp.juggler.subwaytooter.util.CustomEmojiLister import jp.juggler.subwaytooter.util.CustomEmojiLister
import jp.juggler.subwaytooter.util.ProgressResponseBody import jp.juggler.subwaytooter.util.ProgressResponseBody
import jp.juggler.subwaytooter.util.getUserAgent import jp.juggler.subwaytooter.util.getUserAgent
import jp.juggler.util.*
import jp.juggler.util.data.notEmpty import jp.juggler.util.data.notEmpty
import jp.juggler.util.log.LogCategory import jp.juggler.util.log.LogCategory
import jp.juggler.util.log.initializeToastUtils import jp.juggler.util.log.initializeToastUtils
import jp.juggler.util.network.MySslSocketFactory import jp.juggler.util.network.MySslSocketFactory
import jp.juggler.util.network.toPostRequestBuilder import jp.juggler.util.network.toPostRequestBuilder
import jp.juggler.util.os.applicationContextSafe import jp.juggler.util.os.applicationContextSafe
import jp.juggler.util.ui.* import okhttp3.Cache
import okhttp3.* import okhttp3.CacheControl
import okhttp3.ConnectionSpec
import okhttp3.CookieJar
import okhttp3.Interceptor
import okhttp3.JavaNetCookieJar
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
import ru.gildor.coroutines.okhttp.await import ru.gildor.coroutines.okhttp.await
import java.io.File import java.io.File
@ -47,7 +51,7 @@ import java.net.CookieHandler
import java.net.CookieManager import java.net.CookieManager
import java.net.CookiePolicy import java.net.CookiePolicy
import java.security.Security import java.security.Security
import java.util.* import java.util.Collections
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.logging.Level import java.util.logging.Level
import java.util.logging.Logger import java.util.logging.Logger

View File

@ -16,7 +16,6 @@ import android.view.WindowManager
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat import androidx.appcompat.widget.SwitchCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import jp.juggler.subwaytooter.api.entity.TootAccount import jp.juggler.subwaytooter.api.entity.TootAccount
@ -28,10 +27,14 @@ import jp.juggler.subwaytooter.pref.lazyContext
import jp.juggler.subwaytooter.span.EmojiImageSpan import jp.juggler.subwaytooter.span.EmojiImageSpan
import jp.juggler.subwaytooter.span.createSpan import jp.juggler.subwaytooter.span.createSpan
import jp.juggler.subwaytooter.table.UserRelation import jp.juggler.subwaytooter.table.UserRelation
import jp.juggler.util.*
import jp.juggler.util.data.notZero import jp.juggler.util.data.notZero
import jp.juggler.util.log.LogCategory import jp.juggler.util.log.LogCategory
import jp.juggler.util.ui.* import jp.juggler.util.ui.attrColor
import jp.juggler.util.ui.mixColor
import jp.juggler.util.ui.scan
import jp.juggler.util.ui.setIconDrawableId
import jp.juggler.util.ui.setNavigationBarColorCompat
import jp.juggler.util.ui.setStatusBarColorCompat
import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParser
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -68,6 +71,7 @@ fun TootVisibility.getVisibilityIconId(isMisskeyData: Boolean): Int {
TootVisibility.Limited -> R.drawable.ic_account_circle TootVisibility.Limited -> R.drawable.ic_account_circle
TootVisibility.Mutual -> R.drawable.ic_bidirectional TootVisibility.Mutual -> R.drawable.ic_bidirectional
} }
else -> when (this) { else -> when (this) {
TootVisibility.Public -> R.drawable.ic_public TootVisibility.Public -> R.drawable.ic_public
TootVisibility.UnlistedHome -> R.drawable.ic_lock_open TootVisibility.UnlistedHome -> R.drawable.ic_lock_open
@ -113,6 +117,7 @@ fun TootVisibility.getVisibilityString(isMisskeyData: Boolean): String {
TootVisibility.Limited -> R.string.visibility_limited TootVisibility.Limited -> R.string.visibility_limited
TootVisibility.Mutual -> R.string.visibility_mutual TootVisibility.Mutual -> R.string.visibility_mutual
} }
else -> when (this) { else -> when (this) {
TootVisibility.Public -> R.string.visibility_public TootVisibility.Public -> R.string.visibility_public
TootVisibility.UnlistedHome -> R.string.visibility_unlisted TootVisibility.UnlistedHome -> R.string.visibility_unlisted
@ -316,6 +321,7 @@ fun fixHorizontalPadding(v: View, dpDelta: Float = 12f) {
v.setPaddingRelative(padLr + dm.widthPixels / 2, padT, padLr, padB) v.setPaddingRelative(padLr + dm.widthPixels / 2, padT, padLr, padB)
return return
} }
else -> Unit else -> Unit
} }
} }
@ -403,6 +409,7 @@ fun SpannableStringBuilder.appendMisskeyReaction(
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
) )
} }
else -> else ->
this.append(emoji.unifiedCode) this.append(emoji.unifiedCode)
} }

View File

@ -1,6 +1,7 @@
package jp.juggler.subwaytooter.ui.ossLicense package jp.juggler.subwaytooter.ui.ossLicense
import android.os.Bundle import android.os.Bundle
import android.view.Window
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -38,6 +39,9 @@ import androidx.compose.ui.unit.dp
import jp.juggler.subwaytooter.App1 import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.databinding.ActOssLicenseBinding import jp.juggler.subwaytooter.databinding.ActOssLicenseBinding
import jp.juggler.subwaytooter.util.StColorScheme
import jp.juggler.subwaytooter.util.dummyStColorTheme
import jp.juggler.subwaytooter.util.getStColorTheme
import jp.juggler.subwaytooter.util.openBrowser import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.subwaytooter.util.provideViewModel import jp.juggler.subwaytooter.util.provideViewModel
import jp.juggler.subwaytooter.util.toAnnotatedString import jp.juggler.subwaytooter.util.toAnnotatedString
@ -64,16 +68,20 @@ class ActOSSLicense : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
// ステータスバーの色にattr色を使っているので、テーマの指定は必要
App1.setActivityTheme(this) App1.setActivityTheme(this)
val stColorScheme = getStColorTheme()
setContent { setContent {
Screen( Screen(
stColorScheme = stColorScheme,
librariesFlow = viewModel.libraries, librariesFlow = viewModel.libraries,
isProgressShownFlow = viewModel.isProgressShown, isProgressShownFlow = viewModel.isProgressShown,
) )
} }
try { try {
viewModel.load() viewModel.load(stColorScheme = stColorScheme)
} catch (ex: Throwable) { } catch (ex: Throwable) {
log.e(ex, "dependency in fo loading failed.") log.e(ex, "dependency in fo loading failed.")
} }
@ -83,6 +91,7 @@ class ActOSSLicense : ComponentActivity() {
@Composable @Composable
fun DefaultPreview() { fun DefaultPreview() {
Screen( Screen(
stColorScheme = dummyStColorTheme(),
isProgressShownFlow = MutableStateFlow(false), isProgressShownFlow = MutableStateFlow(false),
librariesFlow = MutableStateFlow( librariesFlow = MutableStateFlow(
listOf( listOf(
@ -109,56 +118,50 @@ class ActOSSLicense : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun Screen( private fun Screen(
stColorScheme: StColorScheme,
librariesFlow: Flow<List<LibText>>, librariesFlow: Flow<List<LibText>>,
isProgressShownFlow: Flow<Boolean>, isProgressShownFlow: Flow<Boolean>,
) { ) {
val isProgressShown = isProgressShownFlow.collectAsState(false) val isProgressShown = isProgressShownFlow.collectAsState(false)
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold( MaterialTheme(colorScheme = stColorScheme.materialColorScheme) {
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), Scaffold(
topBar = { modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
TopAppBar( topBar = {
title = { TopAppBar(
Text(stringResource(R.string.oss_license)) title = {
}, Text(stringResource(R.string.oss_license))
navigationIcon = { },
IconButton( navigationIcon = {
onClick = { finish() } IconButton(
) { onClick = { finish() }
Icon( ) {
// imageVector = AutoMirrored.Outlined.ArrowBack, Icon(
imageVector = Icons.Outlined.Close, // imageVector = AutoMirrored.Outlined.ArrowBack,
contentDescription = stringResource(R.string.close) imageVector = Icons.Outlined.Close,
) contentDescription = stringResource(R.string.close)
} )
}, }
scrollBehavior = scrollBehavior, },
colors = TopAppBarDefaults.topAppBarColors( scrollBehavior = scrollBehavior,
// containerColor = : Color = Color.Unspecified, colors = TopAppBarDefaults.topAppBarColors(),
// scrolledContainerColor: Color = Color.Unspecified,
// navigationIconContentColor: Color = Color.Unspecified,
// titleContentColor: Color = Color.Unspecified,
// actionIconContentColor: Color = Color.Unspecified,
containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.primary,
),
)
},
) { innerPadding ->
when (isProgressShown.value) {
true -> Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
color = MaterialTheme.colorScheme.secondary,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
) )
} },
) { innerPadding ->
when (isProgressShown.value) {
true -> Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
color = MaterialTheme.colorScheme.secondary,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
)
}
else -> ScrollContent(innerPadding, librariesFlow) else -> ScrollContent(innerPadding, librariesFlow)
}
} }
} }
} }
@ -188,7 +191,9 @@ class ActOSSLicense : ComponentActivity() {
src.nameBig.notEmpty()?.let { src.nameBig.notEmpty()?.let {
ClickableText( ClickableText(
text = it, text = it,
style = MaterialTheme.typography.headlineMedium, style = MaterialTheme.typography.headlineSmall.copy(
color = MaterialTheme.colorScheme.onBackground,
),
) { offset -> ) { offset ->
it.getStringAnnotations( it.getStringAnnotations(
tag = "URL", tag = "URL",
@ -202,7 +207,9 @@ class ActOSSLicense : ComponentActivity() {
src.nameSmall.notEmpty()?.let { src.nameSmall.notEmpty()?.let {
ClickableText( ClickableText(
text = it, text = it,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall.copy(
color = MaterialTheme.colorScheme.onBackground,
),
) { offset -> ) { offset ->
it.getStringAnnotations( it.getStringAnnotations(
tag = "URL", tag = "URL",
@ -217,7 +224,9 @@ class ActOSSLicense : ComponentActivity() {
src.desc.notEmpty()?.let { src.desc.notEmpty()?.let {
ClickableText( ClickableText(
text = it, text = it,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium.copy(
color = MaterialTheme.colorScheme.onBackground,
),
) { offset -> ) { offset ->
it.getStringAnnotations( it.getStringAnnotations(
tag = "URL", tag = "URL",

View File

@ -63,7 +63,7 @@ class PermissionRequester(
) )
} }
fun hasPermissions() :Boolean{ fun hasPermissions(): Boolean {
val activity = activity ?: error("missing activity.") val activity = activity ?: error("missing activity.")
val listNotGranted = spec.listNotGranded(activity) val listNotGranted = spec.listNotGranded(activity)
return listNotGranted.isEmpty() return listNotGranted.isEmpty()

View File

@ -19,7 +19,7 @@
<color name="Light_colorColumnSettingBackground">#bbb</color> <color name="Light_colorColumnSettingBackground">#bbb</color>
<color name="Light_colorColumnStripBackground">#fff</color> <color name="Light_colorColumnStripBackground">#fff</color>
<color name="Light_colorConversationMainTootBg">#200088ff</color> <color name="Light_colorConversationMainTootBg">#200088ff</color>
<color name="Light_colorLink">#00a2ff</color> <color name="Light_colorLink">#0080ff</color>
<color name="Light_colorPostFormBackground">#eee</color> <color name="Light_colorPostFormBackground">#eee</color>
<color name="Light_colorActionBarBg">#ccc</color> <color name="Light_colorActionBarBg">#ccc</color>
<color name="Light_colorActionBarBgStacked">#ddd</color> <color name="Light_colorActionBarBgStacked">#ddd</color>

View File

@ -25,7 +25,7 @@ class ByteRangeTest {
val kotlinBase64UrlSafe = Base64.UrlSafe val kotlinBase64UrlSafe = Base64.UrlSafe
// kotlin.io の Base64.UrlSafe は 末尾の = パディングを残すので後から除去する必要がある // kotlin.io の Base64.UrlSafe は 末尾の = パディングを残すので後から除去する必要がある
val encodedByKotlinIo = kotlinBase64UrlSafe.encode(src).trimEnd { it=='=' } val encodedByKotlinIo = kotlinBase64UrlSafe.encode(src).trimEnd { it == '=' }
// ByteRange().encodeBase64Url() はパディングを含まない // ByteRange().encodeBase64Url() はパディングを含まない
val encodeByByteRange = src.toByteRange().encodeBase64Url() val encodeByByteRange = src.toByteRange().encodeBase64Url()
// StringUtils の encodeBase64Url() はパディングを含まない // StringUtils の encodeBase64Url() はパディングを含まない

View File

@ -84,11 +84,11 @@ fun AppCompatActivity.launchAndShowError(
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
suspend fun <T:Any?> AppCompatActivity.withProgress( suspend fun <T : Any?> AppCompatActivity.withProgress(
caption:String, caption: String,
progressInitializer: suspend (ProgressDialogEx) -> Unit = {}, progressInitializer: suspend (ProgressDialogEx) -> Unit = {},
block: suspend (progress :ProgressDialogEx)->T, block: suspend (progress: ProgressDialogEx) -> T,
):T { ): T {
val activity = this val activity = this
var progress: ProgressDialogEx? = null var progress: ProgressDialogEx? = null
try { try {

View File

@ -25,6 +25,7 @@ import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.annotation.ColorRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -53,6 +54,9 @@ fun Context.attrColor(attrId: Int): Int {
return color return color
} }
fun Context.resColor(@ColorRes resId: Int): Int =
ContextCompat.getColor(this, resId)
fun <T> TypedArray.use(block: (TypedArray) -> T): T = fun <T> TypedArray.use(block: (TypedArray) -> T): T =
try { try {
block(this) block(this)
@ -352,6 +356,7 @@ fun AppCompatActivity.setNavigationBack(toolbar: Toolbar) =
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
onBackPressedDispatcher.onBackPressed() onBackPressedDispatcher.onBackPressed()
} }
fun ComponentActivity.setNavigationBack(toolbar: Toolbar) = fun ComponentActivity.setNavigationBack(toolbar: Toolbar) =
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
onBackPressedDispatcher.onBackPressed() onBackPressedDispatcher.onBackPressed()

View File

@ -12,7 +12,6 @@ import android.view.inputmethod.InputMethodManager
import android.widget.CompoundButton import android.widget.CompoundButton
import android.widget.TextView import android.widget.TextView
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import jp.juggler.util.log.LogCategory import jp.juggler.util.log.LogCategory
import kotlin.math.pow import kotlin.math.pow
@ -44,6 +43,7 @@ fun View.hideKeyboard() {
when (val imm = this.context?.getSystemService(Context.INPUT_METHOD_SERVICE)) { when (val imm = this.context?.getSystemService(Context.INPUT_METHOD_SERVICE)) {
is InputMethodManager -> is InputMethodManager ->
imm.hideSoftInputFromWindow(this.windowToken, InputMethodManager.HIDE_NOT_ALWAYS) imm.hideSoftInputFromWindow(this.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
else -> log.e("hideKeyboard: can't get InputMethodManager") else -> log.e("hideKeyboard: can't get InputMethodManager")
} }
} catch (ex: Throwable) { } catch (ex: Throwable) {
@ -148,6 +148,7 @@ fun Activity.setStatusBarColorCompat(@ColorInt c: Int) {
//Dark Text to show up on your light status bar //Dark Text to show up on your light status bar
decorView.systemUiVisibility or bit decorView.systemUiVisibility or bit
} }
else -> { else -> {
//Light Text to show up on your dark status bar //Light Text to show up on your dark status bar
decorView.systemUiVisibility and bit.inv() decorView.systemUiVisibility and bit.inv()

View File

@ -50,7 +50,7 @@ object Vers {
const val apng4AndroidVersion = "2.25.0" const val apng4AndroidVersion = "2.25.0"
const val conscryptVersion = "2.5.2" const val conscryptVersion = "2.5.2"
const val desugarLibVersion = "2.0.4" const val desugarLibVersion = "2.0.4"
const val detektVersion = "1.23.4" const val detektVersion = "1.23.5"
const val gildorkotlinCoroutinesOkhttp = "1.0" const val gildorkotlinCoroutinesOkhttp = "1.0"
const val googleFlexbox="3.0.0" const val googleFlexbox="3.0.0"
const val googleMaterial = "1.11.0" const val googleMaterial = "1.11.0"