FileViewer: fix coloration issue for logs files.
This commit is contained in:
parent
8a2490f1e8
commit
feed0ada86
5 changed files with 75 additions and 11 deletions
|
|
@ -49,6 +49,7 @@ class ViewFilePresenter @AssistedInject constructor(
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): ViewFileState {
|
override fun present(): ViewFileState {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val colorationMode = remember { name.toColorationMode() }
|
||||||
|
|
||||||
fun handleEvent(event: ViewFileEvents) {
|
fun handleEvent(event: ViewFileEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
|
|
@ -67,6 +68,7 @@ class ViewFilePresenter @AssistedInject constructor(
|
||||||
return ViewFileState(
|
return ViewFileState(
|
||||||
name = name,
|
name = name,
|
||||||
lines = lines,
|
lines = lines,
|
||||||
|
colorationMode = colorationMode,
|
||||||
eventSink = ::handleEvent,
|
eventSink = ::handleEvent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -79,3 +81,11 @@ class ViewFilePresenter @AssistedInject constructor(
|
||||||
fileSave.save(path)
|
fileSave.save(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.toColorationMode(): ColorationMode {
|
||||||
|
return when {
|
||||||
|
equals("logcat.log") -> ColorationMode.Logcat
|
||||||
|
startsWith("logs.") -> ColorationMode.Logs
|
||||||
|
else -> ColorationMode.None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,5 +21,12 @@ import io.element.android.libraries.architecture.AsyncData
|
||||||
data class ViewFileState(
|
data class ViewFileState(
|
||||||
val name: String,
|
val name: String,
|
||||||
val lines: AsyncData<List<String>>,
|
val lines: AsyncData<List<String>>,
|
||||||
|
val colorationMode: ColorationMode,
|
||||||
val eventSink: (ViewFileEvents) -> Unit,
|
val eventSink: (ViewFileEvents) -> Unit,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class ColorationMode {
|
||||||
|
Logcat,
|
||||||
|
Logs,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,5 +51,6 @@ fun aViewFileState(
|
||||||
) = ViewFileState(
|
) = ViewFileState(
|
||||||
name = name,
|
name = name,
|
||||||
lines = lines,
|
lines = lines,
|
||||||
|
colorationMode = ColorationMode.Logcat,
|
||||||
eventSink = {},
|
eventSink = {},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ fun ViewFileView(
|
||||||
is AsyncData.Success -> FileContent(
|
is AsyncData.Success -> FileContent(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
lines = state.lines.data.toImmutableList(),
|
lines = state.lines.data.toImmutableList(),
|
||||||
|
colorationMode = state.colorationMode,
|
||||||
)
|
)
|
||||||
is AsyncData.Failure -> AsyncFailure(throwable = state.lines.error, onRetry = null)
|
is AsyncData.Failure -> AsyncFailure(throwable = state.lines.error, onRetry = null)
|
||||||
}
|
}
|
||||||
|
|
@ -125,6 +126,7 @@ fun ViewFileView(
|
||||||
@Composable
|
@Composable
|
||||||
private fun FileContent(
|
private fun FileContent(
|
||||||
lines: ImmutableList<String>,
|
lines: ImmutableList<String>,
|
||||||
|
colorationMode: ColorationMode,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
|
|
@ -147,6 +149,7 @@ private fun FileContent(
|
||||||
LineRow(
|
LineRow(
|
||||||
lineNumber = index + 1,
|
lineNumber = index + 1,
|
||||||
line = line,
|
line = line,
|
||||||
|
colorationMode = colorationMode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,6 +160,7 @@ private fun FileContent(
|
||||||
private fun LineRow(
|
private fun LineRow(
|
||||||
lineNumber: Int,
|
lineNumber: Int,
|
||||||
line: String,
|
line: String,
|
||||||
|
colorationMode: ColorationMode,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -195,25 +199,41 @@ private fun LineRow(
|
||||||
}
|
}
|
||||||
.padding(horizontal = 4.dp),
|
.padding(horizontal = 4.dp),
|
||||||
text = line,
|
text = line,
|
||||||
color = line.toColor(),
|
color = line.toColor(colorationMode),
|
||||||
style = ElementTheme.typography.fontBodyMdRegular
|
style = ElementTheme.typography.fontBodyMdRegular
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a logcat line to a color.
|
* Convert a line to a color.
|
||||||
* Ex: `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81`
|
* Ex for logcat:
|
||||||
|
* `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81`
|
||||||
|
* ^ use this char to determine the color
|
||||||
|
* Ex for logs:
|
||||||
|
* `2024-01-26T10:22:26.947416Z WARN elementx: Restore with non-empty map | MatrixClientsHolder.kt:68`
|
||||||
|
* ^ use this char to determine the color, see [LogLevel]
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
private fun String.toColor(): Color {
|
private fun String.toColor(colorationMode: ColorationMode): Color {
|
||||||
return when (getOrNull(31)) {
|
return when (colorationMode) {
|
||||||
'D' -> Color(0xFF299999)
|
ColorationMode.Logcat -> when (getOrNull(31)) {
|
||||||
'I' -> Color(0xFFABC023)
|
'D' -> Color(0xFF299999)
|
||||||
'W' -> Color(0xFFBBB529)
|
'I' -> Color(0xFFABC023)
|
||||||
'E' -> Color(0xFFFF6B68)
|
'W' -> Color(0xFFBBB529)
|
||||||
'A' -> Color(0xFFFF6B68)
|
'E' -> Color(0xFFFF6B68)
|
||||||
else -> ElementTheme.colors.textPrimary
|
'A' -> Color(0xFFFF6B68)
|
||||||
|
else -> ElementTheme.colors.textPrimary
|
||||||
|
}
|
||||||
|
ColorationMode.Logs -> when (getOrNull(32)) {
|
||||||
|
'E' -> ElementTheme.colors.textPrimary
|
||||||
|
'G' -> Color(0xFF299999)
|
||||||
|
'0' -> Color(0xFFABC023)
|
||||||
|
'N' -> Color(0xFFBBB529)
|
||||||
|
'R' -> Color(0xFFFF6B68)
|
||||||
|
else -> ElementTheme.colors.textPrimary
|
||||||
|
}
|
||||||
|
ColorationMode.None -> ElementTheme.colors.textPrimary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionMode
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.features.viewfolder.impl.file.ColorationMode
|
||||||
import io.element.android.features.viewfolder.impl.file.FileContentReader
|
import io.element.android.features.viewfolder.impl.file.FileContentReader
|
||||||
import io.element.android.features.viewfolder.impl.file.FileSave
|
import io.element.android.features.viewfolder.impl.file.FileSave
|
||||||
import io.element.android.features.viewfolder.impl.file.FileShare
|
import io.element.android.features.viewfolder.impl.file.FileShare
|
||||||
|
|
@ -48,6 +49,7 @@ class ViewFilePresenterTest {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.name).isEqualTo("aName")
|
assertThat(initialState.name).isEqualTo("aName")
|
||||||
assertThat(initialState.lines).isInstanceOf(AsyncData.Loading::class.java)
|
assertThat(initialState.lines).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
|
assertThat(initialState.colorationMode).isEqualTo(ColorationMode.None)
|
||||||
val loadedState = awaitItem()
|
val loadedState = awaitItem()
|
||||||
val lines = (loadedState.lines as AsyncData.Success).data
|
val lines = (loadedState.lines as AsyncData.Success).data
|
||||||
assertThat(lines.size).isEqualTo(1)
|
assertThat(lines.size).isEqualTo(1)
|
||||||
|
|
@ -55,6 +57,30 @@ class ViewFilePresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - coloration mode for logcat`() = runTest {
|
||||||
|
val presenter = createPresenter(name = "logcat.log")
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
assertThat(initialState.colorationMode).isEqualTo(ColorationMode.Logcat)
|
||||||
|
cancelAndConsumeRemainingEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - coloration mode for logs`() = runTest {
|
||||||
|
val presenter = createPresenter(name = "logs.date")
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
assertThat(initialState.colorationMode).isEqualTo(ColorationMode.Logs)
|
||||||
|
cancelAndConsumeRemainingEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - share should not have any side effect`() = runTest {
|
fun `present - share should not have any side effect`() = runTest {
|
||||||
val fileContentReader = FakeFileContentReader().apply {
|
val fileContentReader = FakeFileContentReader().apply {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue