Crash screen tweak

master
Zakhar Timoshenko 2 years ago
parent 746934d421
commit 44b6f1b52f
Signed by: Xtimms
SSH Key Fingerprint: SHA256:wH6spYepK/A5erBh7ZyAnr1ru9H4eaMVBEuiw6DSpxI

@ -4,8 +4,10 @@ import android.app.Application
import android.content.Context import android.content.Context
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.os.Build import android.os.Build
import android.os.StrictMode import android.os.StrictMode
import androidx.core.content.getSystemService
import androidx.hilt.work.HiltWorkerFactory import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration import androidx.work.Configuration
import androidx.work.WorkManager import androidx.work.WorkManager
@ -21,9 +23,10 @@ import org.acra.ktx.initAcra
import org.acra.sender.HttpSender import org.acra.sender.HttpSender
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.xtimms.shirizu.core.database.ShirizuDatabase import org.xtimms.shirizu.core.database.ShirizuDatabase
import org.xtimms.shirizu.core.prefs.AppSettings
import org.xtimms.shirizu.core.prefs.KotatsuAppSettings import org.xtimms.shirizu.core.prefs.KotatsuAppSettings
import org.xtimms.shirizu.core.updates.Updater import org.xtimms.shirizu.core.updates.Updater
import org.xtimms.shirizu.crash.CrashActivity
import org.xtimms.shirizu.crash.GlobalExceptionHandler
import org.xtimms.shirizu.utils.lang.processLifecycleScope import org.xtimms.shirizu.utils.lang.processLifecycleScope
import org.xtimms.shirizu.work.WorkScheduleManager import org.xtimms.shirizu.work.WorkScheduleManager
import javax.inject.Inject import javax.inject.Inject
@ -61,6 +64,7 @@ class App : Application(), Configuration.Provider {
) else getPackageInfo(packageName, 0) ) else getPackageInfo(packageName, 0)
} }
DynamicColors.applyToActivitiesIfAvailable(this) DynamicColors.applyToActivitiesIfAvailable(this)
connectivityManager = getSystemService()!!
processLifecycleScope.launch(Dispatchers.IO) { processLifecycleScope.launch(Dispatchers.IO) {
try { try {
@ -70,30 +74,29 @@ class App : Application(), Configuration.Provider {
} }
} }
// GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java) initAcra {
if (AppSettings.isACRAEnabled()) { buildConfigClass = BuildConfig::class.java
initAcra { reportFormat = StringFormat.JSON
buildConfigClass = BuildConfig::class.java httpSender {
reportFormat = StringFormat.JSON uri = BuildConfig.ACRA_URI
httpSender { basicAuthLogin = BuildConfig.ACRA_AUTH_LOGIN
uri = BuildConfig.ACRA_URI basicAuthPassword = BuildConfig.ACRA_AUTH_PASSWORD
basicAuthLogin = BuildConfig.ACRA_AUTH_LOGIN httpMethod = HttpSender.Method.POST
basicAuthPassword = BuildConfig.ACRA_AUTH_PASSWORD
httpMethod = HttpSender.Method.POST
}
reportContent = listOf(
ReportField.PACKAGE_NAME,
ReportField.INSTALLATION_ID,
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.ANDROID_VERSION,
ReportField.PHONE_MODEL,
ReportField.STACK_TRACE,
ReportField.CRASH_CONFIGURATION,
ReportField.CUSTOM_DATA,
)
} }
reportContent = listOf(
ReportField.PACKAGE_NAME,
ReportField.INSTALLATION_ID,
ReportField.APP_VERSION_CODE,
ReportField.APP_VERSION_NAME,
ReportField.ANDROID_VERSION,
ReportField.PHONE_MODEL,
ReportField.STACK_TRACE,
ReportField.CRASH_CONFIGURATION,
ReportField.CUSTOM_DATA,
)
} }
GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java)
workScheduleManager.init() workScheduleManager.init()
} }
@ -123,8 +126,8 @@ class App : Application(), Configuration.Provider {
companion object { companion object {
lateinit var packageInfo: PackageInfo lateinit var packageInfo: PackageInfo
lateinit var connectivityManager: ConnectivityManager
@Suppress("DEPRECATION")
fun getVersionReport(): String { fun getVersionReport(): String {
val versionName = packageInfo.versionName val versionName = packageInfo.versionName
val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {

@ -1,12 +1,21 @@
package org.xtimms.shirizu.core.screens package org.xtimms.shirizu.core.screens
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateValue
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.absoluteOffset
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
@ -21,20 +30,34 @@ import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.Modifier
import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import org.xtimms.shirizu.R
import org.xtimms.shirizu.sections.stats.Size
import org.xtimms.shirizu.ui.theme.ShirizuTheme
import org.xtimms.shirizu.utils.composable.secondaryItemAlpha import org.xtimms.shirizu.utils.composable.secondaryItemAlpha
import org.xtimms.shirizu.utils.material.combineColors
@Composable @Composable
fun InfoScreen( fun InfoScreen(
icon: ImageVector, icon: ImageVector,
headingText: String, headingText1: String,
headingText2: String,
subtitleText: String, subtitleText: String,
acceptText: String, acceptText: String,
onAcceptClick: () -> Unit, onAcceptClick: () -> Unit,
@ -43,6 +66,9 @@ fun InfoScreen(
onRejectClick: (() -> Unit)? = null, onRejectClick: (() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit, content: @Composable ColumnScope.() -> Unit,
) { ) {
val localDensity = LocalDensity.current
Scaffold( Scaffold(
bottomBar = { bottomBar = {
val strokeWidth = Dp.Hairline val strokeWidth = Dp.Hairline
@ -82,15 +108,50 @@ fun InfoScreen(
} }
}, },
) { paddingValues -> ) { paddingValues ->
// Status bar scrim
var headerSize by remember { mutableStateOf(Size(0.dp, 0.dp)) }
Box( Box(
modifier = Modifier modifier = Modifier
.zIndex(2f)
.secondaryItemAlpha()
.background(MaterialTheme.colorScheme.background)
.fillMaxWidth() .fillMaxWidth()
.height(paddingValues.calculateTopPadding()), .onGloballyPositioned {
) headerSize = Size(
width = with(localDensity) { it.size.width.toDp() },
height = with(localDensity) { it.size.height.toDp() }
)
},
contentAlignment = Alignment.Center,
) {
val halfWidth = headerSize.width / 2
val halfHeight = headerSize.height / 2
val starColor1 = combineColors(
MaterialTheme.colorScheme.primaryContainer,
MaterialTheme.colorScheme.surface,
0.5f,
)
val angleStar1 by rememberInfiniteTransition("angleStar1").animateFloat(
label = "angleStar1",
initialValue = -20f,
targetValue = 20f,
animationSpec = infiniteRepeatable(tween(5000), RepeatMode.Reverse)
)
Icon(
modifier = Modifier
.requiredSize(256.dp)
.absoluteOffset(
x = halfWidth * 0.7f,
y = -halfHeight * 0.6f
)
.rotate(angleStar1)
.zIndex(-1f),
painter = painterResource(R.drawable.shape_soft_star_1),
tint = starColor1,
contentDescription = null,
)
}
Column( Column(
modifier = Modifier modifier = Modifier
@ -108,10 +169,24 @@ fun InfoScreen(
.size(48.dp), .size(48.dp),
tint = MaterialTheme.colorScheme.primary, tint = MaterialTheme.colorScheme.primary,
) )
Text( val infiniteTransition by rememberInfiniteTransition("infiniteTransition").animateValue(
text = headingText, label = "infiniteTransition",
style = MaterialTheme.typography.headlineLarge, initialValue = 0,
targetValue = 2,
typeConverter = Int.VectorConverter,
animationSpec = infiniteRepeatable(tween(15000), RepeatMode.Restart)
) )
val heading = when (infiniteTransition) {
0 -> headingText1
1 -> headingText2
else -> headingText2
}
AnimatedContent(targetState = heading, label = "heading animation") {
Text(
text = it,
style = MaterialTheme.typography.headlineLarge,
)
}
Text( Text(
text = subtitleText, text = subtitleText,
modifier = Modifier modifier = Modifier
@ -128,15 +203,18 @@ fun InfoScreen(
@PreviewLightDark @PreviewLightDark
@Composable @Composable
private fun InfoScaffoldPreview() { private fun InfoScaffoldPreview() {
InfoScreen( ShirizuTheme {
icon = Icons.Outlined.Newspaper, InfoScreen(
headingText = "Heading", icon = Icons.Outlined.Newspaper,
subtitleText = "Subtitle", headingText1 = "Heading 1",
acceptText = "Accept", headingText2 = "Heading 2",
onAcceptClick = {}, subtitleText = "Subtitle",
rejectText = "Reject", acceptText = "Accept",
onRejectClick = {}, onAcceptClick = {},
) { rejectText = "Reject",
Text("Hello world") onRejectClick = {},
) {
Text("Hello world")
}
} }
} }

@ -8,6 +8,7 @@ import androidx.activity.enableEdgeToEdge
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.xtimms.shirizu.LocalDarkTheme import org.xtimms.shirizu.LocalDarkTheme
import org.xtimms.shirizu.LocalDynamicColorSwitch import org.xtimms.shirizu.LocalDynamicColorSwitch
import org.xtimms.shirizu.LocalWindowWidthState
import org.xtimms.shirizu.MainActivity import org.xtimms.shirizu.MainActivity
import org.xtimms.shirizu.SettingsProvider import org.xtimms.shirizu.SettingsProvider
import org.xtimms.shirizu.ui.theme.ShirizuTheme import org.xtimms.shirizu.ui.theme.ShirizuTheme
@ -21,7 +22,7 @@ class CrashActivity : ComponentActivity() {
val exception = GlobalExceptionHandler.getThrowableFromIntent(intent) val exception = GlobalExceptionHandler.getThrowableFromIntent(intent)
setContent { setContent {
SettingsProvider { SettingsProvider(LocalWindowWidthState.current) {
ShirizuTheme( ShirizuTheme(
darkTheme = LocalDarkTheme.current.isDarkTheme(), darkTheme = LocalDarkTheme.current.isDarkTheme(),
isDynamicColorEnabled = LocalDynamicColorSwitch.current, isDynamicColorEnabled = LocalDynamicColorSwitch.current,

@ -1,5 +1,6 @@
package org.xtimms.shirizu.crash package org.xtimms.shirizu.crash
import android.app.Activity
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -9,7 +10,6 @@ import androidx.compose.material.icons.outlined.BugReport
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@ -17,29 +17,30 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch import org.acra.ktx.sendWithAcra
import org.xtimms.shirizu.R import org.xtimms.shirizu.R
import org.xtimms.shirizu.core.screens.InfoScreen import org.xtimms.shirizu.core.screens.InfoScreen
import org.xtimms.shirizu.ui.theme.ShirizuTheme import org.xtimms.shirizu.ui.theme.ShirizuTheme
import org.xtimms.shirizu.utils.CrashLogUtil import org.xtimms.shirizu.utils.system.toast
@Composable @Composable
fun CrashScreen( fun CrashScreen(
exception: Throwable?, exception: Throwable?,
onRestartClick: () -> Unit, onRestartClick: () -> Unit,
) { ) {
val scope = rememberCoroutineScope()
val context = LocalContext.current val context = LocalContext.current
val activity = (context as? Activity)
InfoScreen( InfoScreen(
icon = Icons.Outlined.BugReport, icon = Icons.Outlined.BugReport,
headingText = stringResource(R.string.crash_screen_title), headingText1 = stringResource(R.string.crash_screen_title),
headingText2 = stringResource(id = R.string.crash_screen_something_went_wrong),
subtitleText = stringResource(R.string.crash_screen_description, stringResource(R.string.app_name)), subtitleText = stringResource(R.string.crash_screen_description, stringResource(R.string.app_name)),
acceptText = stringResource(R.string.pref_dump_crash_logs), acceptText = stringResource(R.string.pref_send_crash_logs),
onAcceptClick = { onAcceptClick = {
scope.launch { exception?.sendWithAcra()
CrashLogUtil(context).dumpLogs() context.toast(context.resources.getString(R.string.crash_screen_toast))
} activity?.finishAndRemoveTask()
}, },
rejectText = stringResource(R.string.crash_screen_restart_application), rejectText = stringResource(R.string.crash_screen_restart_application),
onRejectClick = onRestartClick, onRejectClick = onRestartClick,

Loading…
Cancel
Save