Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DittoToolsAndroid/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
alias(libs.plugins.com.android.library)
alias(libs.plugins.org.jetbrains.kotlin.android)
alias(libs.plugins.jreleaser)
kotlin("plugin.serialization") version "1.9.25"
}

val libraryArtifactId by extra("ditto-tools-android")
Expand Down Expand Up @@ -41,6 +42,9 @@ dependencies {

implementation(libs.live.ditto.ditto)

// Kotlin Serialization
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")

testImplementation(libs.junit.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package live.ditto.tools.data

data class LogConfiguration(
val maxAge : Int,
val maxFilesOnDisk: Int,
val maxSize: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package live.ditto.tools.logviewer

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
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
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.DensitySmall
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
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
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import live.ditto.Ditto
import live.ditto.tools.R

@Composable
fun LogDetailsScreen(
onButtonClick: () -> Unit,
ditto: Ditto,
logDetailsScreenViewModel: LogDetailsScreenViewModel = viewModel(
factory = LogDetailsScreenViewModelFactory(
ditto,
filesDir = LocalContext.current.applicationContext.filesDir
)
)
) {

val logConfiguration = logDetailsScreenViewModel.logConfiguration
val logDirectoryInfo = logDetailsScreenViewModel.logDirectoryInfo

LaunchedEffect(logConfiguration) {
logDetailsScreenViewModel.getLogConfigurationInfo()
}

LaunchedEffect(logDirectoryInfo) {
logDetailsScreenViewModel.getLogDirInfo()
}

Column(
modifier = Modifier
.fillMaxSize()
.fillMaxHeight()
.padding(all = 16.dp)
) {
LogInfoCard(stringResource(R.string.log_config), logConfiguration.value)
LogInfoCard(stringResource(R.string.log_dir_info), logDirectoryInfo.value)

Button(
modifier = Modifier.fillMaxWidth(),
onClick = { onButtonClick() }
) {
Icon(Icons.Default.DensitySmall, contentDescription = "Logs")
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.log_view))
}
}
}

@Composable
fun LogInfoCard(title: String, info: AnnotatedString){
ElevatedCard(
elevation = CardDefaults.cardElevation(
defaultElevation = 6.dp
),
modifier = Modifier
.padding(vertical = 8.dp)
.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(all = 16.dp)
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = title,
fontSize = 16.sp,
textAlign = TextAlign.Center,
style = TextStyle(color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
)
Spacer(modifier = Modifier.height(3.dp))
Text(text = info) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package live.ditto.tools.logviewer

import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import live.ditto.Ditto
import live.ditto.tools.utils.LogUtils
import live.ditto.tools.utils.Utils
import java.io.File

class LogDetailsScreenViewModel(val ditto : Ditto, val filesDir: File) : ViewModel(){

private val dittoLogUtils = LogUtils(
ditto = ditto,
filesDir = filesDir
)

private val _logConfiguration = mutableStateOf<AnnotatedString>(AnnotatedString(""))
val logConfiguration = _logConfiguration

private val _logDirectoryInfo = mutableStateOf<AnnotatedString>(AnnotatedString(""))
val logDirectoryInfo = _logDirectoryInfo

fun getLogConfigurationInfo(){
viewModelScope.launch(Dispatchers.IO) {
val config = dittoLogUtils.getLogConfiguration()

_logConfiguration.value = buildAnnotatedString {
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)){
append("Max File Age: ")
}
append("${config.maxAge} Hours")
append("\n")

withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)){
append("Max File Size: ")
}
append("${config.maxSize} MB")
append("\n")

withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)){
append("Max Files On Disk: ")
}
append("${config.maxFilesOnDisk}")
}
}
}

fun getLogDirInfo(){

viewModelScope.launch(Dispatchers.IO) {
val fileSize = Utils.formatFileSize(dittoLogUtils.getLogFileDirSize())

_logDirectoryInfo.value = buildAnnotatedString {

withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append("Log Directory Size: ")
}
append("$fileSize\n")

withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append("Log File Count: ")
}
append("${dittoLogUtils.getLogFileCount()}\n")

withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append("Current Log File Error Count: ")
}
append("${dittoLogUtils.logErrorCount()}")
}
}
}
}

class LogDetailsScreenViewModelFactory(
private val ditto: Ditto,
private val filesDir: File
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LogDetailsScreenViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return LogDetailsScreenViewModel(ditto, filesDir = filesDir) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
Loading