forked from geode-sdk/android-launcher
275 lines
9.7 KiB
Kotlin
275 lines
9.7 KiB
Kotlin
package com.geode.launcher
|
|
|
|
import android.content.ClipData
|
|
import android.content.ClipboardManager
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.widget.Toast
|
|
import androidx.activity.ComponentActivity
|
|
import androidx.activity.OnBackPressedDispatcher
|
|
import androidx.activity.compose.setContent
|
|
import androidx.compose.foundation.gestures.detectTapGestures
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
import androidx.compose.foundation.layout.Column
|
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
import androidx.compose.foundation.lazy.items
|
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
import androidx.compose.material.icons.Icons
|
|
import androidx.compose.material.icons.filled.ArrowBack
|
|
import androidx.compose.material.icons.filled.Share
|
|
import androidx.compose.material3.Divider
|
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
import androidx.compose.material3.Icon
|
|
import androidx.compose.material3.IconButton
|
|
import androidx.compose.material3.LinearProgressIndicator
|
|
import androidx.compose.material3.MaterialTheme
|
|
import androidx.compose.material3.Scaffold
|
|
import androidx.compose.material3.Surface
|
|
import androidx.compose.material3.Text
|
|
import androidx.compose.material3.TopAppBar
|
|
import androidx.compose.material3.TopAppBarDefaults
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.CompositionLocalProvider
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
import androidx.compose.runtime.collectAsState
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.rememberCoroutineScope
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.graphics.Color
|
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|
import androidx.compose.ui.input.pointer.pointerInput
|
|
import androidx.compose.ui.platform.LocalContext
|
|
import androidx.compose.ui.res.painterResource
|
|
import androidx.compose.ui.res.stringResource
|
|
import androidx.compose.ui.text.font.FontFamily
|
|
import androidx.compose.ui.text.style.TextAlign
|
|
import androidx.compose.ui.text.style.TextOverflow
|
|
import androidx.compose.ui.tooling.preview.Preview
|
|
import androidx.compose.ui.unit.dp
|
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
import com.geode.launcher.log.LogLine
|
|
import com.geode.launcher.log.LogPriority
|
|
import com.geode.launcher.log.LogViewModel
|
|
import com.geode.launcher.ui.theme.GeodeLauncherTheme
|
|
import com.geode.launcher.ui.theme.LocalTheme
|
|
import com.geode.launcher.ui.theme.Theme
|
|
import com.geode.launcher.ui.theme.Typography
|
|
import com.geode.launcher.utils.PreferenceUtils
|
|
import kotlinx.coroutines.launch
|
|
|
|
class ApplicationLogsActivity : ComponentActivity() {
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
setContent {
|
|
val themeOption by PreferenceUtils.useIntPreference(PreferenceUtils.Key.THEME)
|
|
val theme = Theme.fromInt(themeOption)
|
|
|
|
val backgroundOption by PreferenceUtils.useBooleanPreference(PreferenceUtils.Key.BLACK_BACKGROUND)
|
|
|
|
CompositionLocalProvider(LocalTheme provides theme) {
|
|
GeodeLauncherTheme(theme = theme, blackBackground = backgroundOption) {
|
|
Surface(
|
|
modifier = Modifier.fillMaxSize(),
|
|
color = MaterialTheme.colorScheme.background
|
|
) {
|
|
ApplicationLogsScreen(onBackPressedDispatcher)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
fun getLogColor(priority: LogPriority): Color {
|
|
val isDark = LocalTheme.current != Theme.LIGHT
|
|
|
|
// i just copied these from my ide tbh
|
|
return if (isDark) {
|
|
when (priority) {
|
|
LogPriority.ERROR -> Color(0xffdf5151)
|
|
LogPriority.WARN -> Color(0xffbcb500)
|
|
LogPriority.FATAL -> Color(0xffb8b6fc)
|
|
else -> Color.Unspecified
|
|
}
|
|
} else {
|
|
when (priority) {
|
|
LogPriority.ERROR -> Color(0xffdf5151)
|
|
LogPriority.WARN -> Color(0xffeab700)
|
|
LogPriority.FATAL -> Color(0xffa142f4)
|
|
else -> Color.Unspecified
|
|
}
|
|
}
|
|
}
|
|
|
|
fun copyLogText(context: Context, logMessage: String) {
|
|
val clipboardManager =
|
|
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
|
clipboardManager.setPrimaryClip(
|
|
ClipData.newPlainText(
|
|
context.getString(R.string.application_log_copy_label),
|
|
logMessage
|
|
)
|
|
)
|
|
|
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
|
Toast.makeText(
|
|
context,
|
|
context.getString(R.string.text_copied),
|
|
Toast.LENGTH_SHORT
|
|
).show()
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
fun LogCard(logLine: LogLine, modifier: Modifier = Modifier) {
|
|
val context = LocalContext.current
|
|
|
|
Column(
|
|
modifier = modifier
|
|
.padding(8.dp)
|
|
.pointerInput(Unit) {
|
|
detectTapGestures(
|
|
onLongPress = {
|
|
copyLogText(context, logLine.asSimpleString)
|
|
}
|
|
)
|
|
},
|
|
) {
|
|
Text(
|
|
"[${logLine.priority.toChar()}] ${logLine.formattedTime}",
|
|
style = Typography.labelSmall,
|
|
color = getLogColor(logLine.priority),
|
|
fontFamily = FontFamily.Monospace
|
|
)
|
|
|
|
Text(
|
|
"[${logLine.tag}]: ${logLine.message}",
|
|
fontFamily = FontFamily.Monospace,
|
|
style = Typography.bodyMedium
|
|
)
|
|
}
|
|
}
|
|
|
|
@OptIn(ExperimentalMaterial3Api::class)
|
|
@Composable
|
|
fun ApplicationLogsScreen(
|
|
onBackPressedDispatcher: OnBackPressedDispatcher?,
|
|
logViewModel: LogViewModel = viewModel()
|
|
) {
|
|
val logLines = logViewModel.lineState
|
|
val isLoading by logViewModel.isLoading.collectAsState()
|
|
|
|
val context = LocalContext.current
|
|
|
|
val coroutineScope = rememberCoroutineScope()
|
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
|
val listState = rememberLazyListState()
|
|
|
|
LaunchedEffect(logLines.size) {
|
|
listState.scrollToItem(logLines.size)
|
|
}
|
|
|
|
Scaffold(
|
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
|
topBar = {
|
|
Column {
|
|
TopAppBar(
|
|
navigationIcon = {
|
|
IconButton(onClick = { onBackPressedDispatcher?.onBackPressed() }) {
|
|
Icon(
|
|
imageVector = Icons.Filled.ArrowBack,
|
|
contentDescription = stringResource(R.string.back_icon_alt)
|
|
)
|
|
}
|
|
},
|
|
actions = {
|
|
IconButton(onClick = {
|
|
if (!logLines.isEmpty()) {
|
|
coroutineScope.launch {
|
|
val data = logViewModel.getLogData()
|
|
|
|
val sendIntent = Intent(Intent.ACTION_SEND).apply {
|
|
putExtra(Intent.EXTRA_TEXT, data)
|
|
type = "text/plain"
|
|
}
|
|
|
|
val shareIntent = Intent.createChooser(sendIntent, null)
|
|
|
|
context.startActivity(shareIntent)
|
|
}
|
|
}
|
|
}) {
|
|
Icon(
|
|
Icons.Filled.Share,
|
|
contentDescription = stringResource(R.string.application_logs_share)
|
|
)
|
|
}
|
|
IconButton(onClick = {
|
|
logViewModel.clearLogs()
|
|
onBackPressedDispatcher?.onBackPressed()
|
|
}) {
|
|
Icon(
|
|
painterResource(R.drawable.icon_delete),
|
|
contentDescription = stringResource(R.string.application_logs_delete)
|
|
)
|
|
}
|
|
},
|
|
title = {
|
|
Text(
|
|
stringResource(R.string.title_activity_application_logs),
|
|
maxLines = 1,
|
|
overflow = TextOverflow.Ellipsis
|
|
)
|
|
},
|
|
scrollBehavior = scrollBehavior,
|
|
)
|
|
|
|
if (isLoading) {
|
|
LinearProgressIndicator(
|
|
modifier = Modifier.fillMaxWidth()
|
|
)
|
|
}
|
|
}
|
|
}
|
|
) { innerPadding ->
|
|
LazyColumn(
|
|
Modifier
|
|
.padding(innerPadding)
|
|
.fillMaxWidth(),
|
|
verticalArrangement = Arrangement.SpaceEvenly,
|
|
state = listState
|
|
) {
|
|
if (!isLoading && logLines.isEmpty()) {
|
|
item {
|
|
Text(
|
|
stringResource(R.string.application_logs_no_logs),
|
|
textAlign = TextAlign.Center,
|
|
style = Typography.bodyLarge,
|
|
modifier = Modifier.fillMaxSize()
|
|
)
|
|
}
|
|
}
|
|
|
|
items(
|
|
logLines
|
|
) { line ->
|
|
LogCard(line)
|
|
Divider()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Preview(showSystemUi = true)
|
|
@Composable
|
|
fun LogsPreview() {
|
|
GeodeLauncherTheme {
|
|
ApplicationLogsScreen(null)
|
|
}
|
|
} |