diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt index 91cc59ec05..4af90a83ed 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt @@ -49,6 +49,7 @@ class ViewFilePresenter @AssistedInject constructor( @Composable override fun present(): ViewFileState { val coroutineScope = rememberCoroutineScope() + val colorationMode = remember { name.toColorationMode() } fun handleEvent(event: ViewFileEvents) { when (event) { @@ -67,6 +68,7 @@ class ViewFilePresenter @AssistedInject constructor( return ViewFileState( name = name, lines = lines, + colorationMode = colorationMode, eventSink = ::handleEvent, ) } @@ -79,3 +81,11 @@ class ViewFilePresenter @AssistedInject constructor( fileSave.save(path) } } + +private fun String.toColorationMode(): ColorationMode { + return when { + equals("logcat.log") -> ColorationMode.Logcat + startsWith("logs.") -> ColorationMode.RustLogs + else -> ColorationMode.None + } +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt index 9fb531c478..35ed0991ad 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt @@ -21,5 +21,12 @@ import io.element.android.libraries.architecture.AsyncData data class ViewFileState( val name: String, val lines: AsyncData>, + val colorationMode: ColorationMode, val eventSink: (ViewFileEvents) -> Unit, ) + +enum class ColorationMode { + Logcat, + RustLogs, + None, +} diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt index f0612c0714..3213036d4d 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt @@ -27,6 +27,7 @@ open class ViewFileStateProvider : PreviewParameterProvider { aViewFileState(lines = AsyncData.Failure(Exception("A failure"))), aViewFileState(lines = AsyncData.Success(emptyList())), aViewFileState( + name = "logcat.log", lines = AsyncData.Success( listOf( "Line 1", @@ -40,7 +41,25 @@ open class ViewFileStateProvider : PreviewParameterProvider { "01-23 13:14:50.740 25818 25818 E error", "01-23 13:14:50.740 25818 25818 A assertion", ) - ) + ), + colorationMode = ColorationMode.Logcat, + ), + aViewFileState( + name = "logs.2024-01-26", + lines = AsyncData.Success( + listOf( + "Line 1", + "Line 2", + "Line 3 lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor" + + " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,", + "2024-01-26T10:22:26.947416Z TRACE trace", + "2024-01-26T10:22:26.947416Z DEBUG debug", + "2024-01-26T10:22:26.947416Z INFO info", + "2024-01-26T10:22:26.947416Z WARN warn", + "2024-01-26T10:22:26.947416Z ERROR error", + ) + ), + colorationMode = ColorationMode.RustLogs, ) ) } @@ -48,8 +67,10 @@ open class ViewFileStateProvider : PreviewParameterProvider { fun aViewFileState( name: String = "aName", lines: AsyncData> = AsyncData.Uninitialized, + colorationMode: ColorationMode = ColorationMode.None, ) = ViewFileState( name = name, lines = lines, + colorationMode = colorationMode, eventSink = {}, ) diff --git a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt index f58f5399d7..d5b3818227 100644 --- a/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt +++ b/features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt @@ -114,6 +114,7 @@ fun ViewFileView( is AsyncData.Success -> FileContent( modifier = Modifier.weight(1f), lines = state.lines.data.toImmutableList(), + colorationMode = state.colorationMode, ) is AsyncData.Failure -> AsyncFailure(throwable = state.lines.error, onRetry = null) } @@ -125,6 +126,7 @@ fun ViewFileView( @Composable private fun FileContent( lines: ImmutableList, + colorationMode: ColorationMode, modifier: Modifier = Modifier, ) { LazyColumn( @@ -147,6 +149,7 @@ private fun FileContent( LineRow( lineNumber = index + 1, line = line, + colorationMode = colorationMode, ) } } @@ -157,6 +160,7 @@ private fun FileContent( private fun LineRow( lineNumber: Int, line: String, + colorationMode: ColorationMode, ) { val context = LocalContext.current Row( @@ -195,28 +199,49 @@ private fun LineRow( } .padding(horizontal = 4.dp), text = line, - color = line.toColor(), + color = line.toColor(colorationMode), style = ElementTheme.typography.fontBodyMdRegular ) } } /** - * Convert a logcat line to a color. - * Ex: `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81` + * Convert a line to a color. + * 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 Rust 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 -private fun String.toColor(): Color { - return when (getOrNull(31)) { - 'D' -> Color(0xFF299999) - 'I' -> Color(0xFFABC023) - 'W' -> Color(0xFFBBB529) - 'E' -> Color(0xFFFF6B68) - 'A' -> Color(0xFFFF6B68) - else -> ElementTheme.colors.textPrimary +private fun String.toColor(colorationMode: ColorationMode): Color { + return when (colorationMode) { + ColorationMode.Logcat -> when (getOrNull(31)) { + 'D' -> colorDebug + 'I' -> colorInfo + 'W' -> colorWarning + 'E' -> colorError + 'A' -> colorError + else -> ElementTheme.colors.textPrimary + } + ColorationMode.RustLogs -> when (getOrNull(32)) { + 'E' -> ElementTheme.colors.textPrimary + 'G' -> colorDebug + 'O' -> colorInfo + 'N' -> colorWarning + 'R' -> colorError + else -> ElementTheme.colors.textPrimary + } + ColorationMode.None -> ElementTheme.colors.textPrimary } } +private val colorDebug = Color(0xFF299999) +private val colorInfo = Color(0xFFABC023) +private val colorWarning = Color(0xFFBBB529) +private val colorError = Color(0xFFFF6B68) + @PreviewsDayNight @Composable internal fun ViewFileViewPreview(@PreviewParameter(ViewFileStateProvider::class) state: ViewFileState) = ElementPreview { diff --git a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt index 3b593410b2..6cef49a72d 100644 --- a/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt +++ b/features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt @@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test 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.FileSave import io.element.android.features.viewfolder.impl.file.FileShare @@ -48,6 +49,7 @@ class ViewFilePresenterTest { val initialState = awaitItem() assertThat(initialState.name).isEqualTo("aName") assertThat(initialState.lines).isInstanceOf(AsyncData.Loading::class.java) + assertThat(initialState.colorationMode).isEqualTo(ColorationMode.None) val loadedState = awaitItem() val lines = (loadedState.lines as AsyncData.Success).data 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.RustLogs) + cancelAndConsumeRemainingEvents() + } + } + @Test fun `present - share should not have any side effect`() = runTest { val fileContentReader = FakeFileContentReader().apply { diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png index f5be6b5490..862b48dfc9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:52ea44b4be9b858f64a886ded5427f8ef5c2149914e348166a2fbb333ffc41f8 -size 70418 +oid sha256:726f55e0bd89f429e351b070bda57be081c01a42240ba53e8d87bdfdcf84a1c6 +size 71385 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..1a3a882cc9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Day-0_1_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:839bdc36f80481351c63b66e358a0f68537a8cc1cdf75ee9dcaed35338573e92 +size 66140 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png index 339e893381..8bd6eb3b3b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:304c5c94e3b408c744f0b6c86d35ac781f368e6e0d5742d5b2ff36ac1682538a -size 67297 +oid sha256:684fec6dc2c15767195b79d6c4c5996ab9cdb03386b5fcfc3400622ad4e03008 +size 68115 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..c6eca13a72 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.viewfolder.impl.file_ViewFileView_null_ViewFileView-Night-0_2_null_5,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1813c8906a75315d691faf5fe7ede66ab7e56e52e779408a2a4fcd6829c113b1 +size 61642