Skip to content

Commit 0bcd3ba

Browse files
authored
Merge pull request #2299 from element-hq/feature/bma/logViewerImprovement
FileViewer: fix coloration issue for logs files.
2 parents 80270d1 + 6194f2c commit 0bcd3ba

9 files changed

+111
-16
lines changed

features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFilePresenter.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class ViewFilePresenter @AssistedInject constructor(
4949
@Composable
5050
override fun present(): ViewFileState {
5151
val coroutineScope = rememberCoroutineScope()
52+
val colorationMode = remember { name.toColorationMode() }
5253

5354
fun handleEvent(event: ViewFileEvents) {
5455
when (event) {
@@ -67,6 +68,7 @@ class ViewFilePresenter @AssistedInject constructor(
6768
return ViewFileState(
6869
name = name,
6970
lines = lines,
71+
colorationMode = colorationMode,
7072
eventSink = ::handleEvent,
7173
)
7274
}
@@ -79,3 +81,11 @@ class ViewFilePresenter @AssistedInject constructor(
7981
fileSave.save(path)
8082
}
8183
}
84+
85+
private fun String.toColorationMode(): ColorationMode {
86+
return when {
87+
equals("logcat.log") -> ColorationMode.Logcat
88+
startsWith("logs.") -> ColorationMode.RustLogs
89+
else -> ColorationMode.None
90+
}
91+
}

features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileState.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,12 @@ import io.element.android.libraries.architecture.AsyncData
2121
data class ViewFileState(
2222
val name: String,
2323
val lines: AsyncData<List<String>>,
24+
val colorationMode: ColorationMode,
2425
val eventSink: (ViewFileEvents) -> Unit,
2526
)
27+
28+
enum class ColorationMode {
29+
Logcat,
30+
RustLogs,
31+
None,
32+
}

features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileStateProvider.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ open class ViewFileStateProvider : PreviewParameterProvider<ViewFileState> {
2727
aViewFileState(lines = AsyncData.Failure(Exception("A failure"))),
2828
aViewFileState(lines = AsyncData.Success(emptyList())),
2929
aViewFileState(
30+
name = "logcat.log",
3031
lines = AsyncData.Success(
3132
listOf(
3233
"Line 1",
@@ -40,16 +41,36 @@ open class ViewFileStateProvider : PreviewParameterProvider<ViewFileState> {
4041
"01-23 13:14:50.740 25818 25818 E error",
4142
"01-23 13:14:50.740 25818 25818 A assertion",
4243
)
43-
)
44+
),
45+
colorationMode = ColorationMode.Logcat,
46+
),
47+
aViewFileState(
48+
name = "logs.2024-01-26",
49+
lines = AsyncData.Success(
50+
listOf(
51+
"Line 1",
52+
"Line 2",
53+
"Line 3 lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor" +
54+
" incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,",
55+
"2024-01-26T10:22:26.947416Z TRACE trace",
56+
"2024-01-26T10:22:26.947416Z DEBUG debug",
57+
"2024-01-26T10:22:26.947416Z INFO info",
58+
"2024-01-26T10:22:26.947416Z WARN warn",
59+
"2024-01-26T10:22:26.947416Z ERROR error",
60+
)
61+
),
62+
colorationMode = ColorationMode.RustLogs,
4463
)
4564
)
4665
}
4766

4867
fun aViewFileState(
4968
name: String = "aName",
5069
lines: AsyncData<List<String>> = AsyncData.Uninitialized,
70+
colorationMode: ColorationMode = ColorationMode.None,
5171
) = ViewFileState(
5272
name = name,
5373
lines = lines,
74+
colorationMode = colorationMode,
5475
eventSink = {},
5576
)

features/viewfolder/impl/src/main/kotlin/io/element/android/features/viewfolder/impl/file/ViewFileView.kt

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ fun ViewFileView(
114114
is AsyncData.Success -> FileContent(
115115
modifier = Modifier.weight(1f),
116116
lines = state.lines.data.toImmutableList(),
117+
colorationMode = state.colorationMode,
117118
)
118119
is AsyncData.Failure -> AsyncFailure(throwable = state.lines.error, onRetry = null)
119120
}
@@ -125,6 +126,7 @@ fun ViewFileView(
125126
@Composable
126127
private fun FileContent(
127128
lines: ImmutableList<String>,
129+
colorationMode: ColorationMode,
128130
modifier: Modifier = Modifier,
129131
) {
130132
LazyColumn(
@@ -147,6 +149,7 @@ private fun FileContent(
147149
LineRow(
148150
lineNumber = index + 1,
149151
line = line,
152+
colorationMode = colorationMode,
150153
)
151154
}
152155
}
@@ -157,6 +160,7 @@ private fun FileContent(
157160
private fun LineRow(
158161
lineNumber: Int,
159162
line: String,
163+
colorationMode: ColorationMode,
160164
) {
161165
val context = LocalContext.current
162166
Row(
@@ -195,28 +199,49 @@ private fun LineRow(
195199
}
196200
.padding(horizontal = 4.dp),
197201
text = line,
198-
color = line.toColor(),
202+
color = line.toColor(colorationMode),
199203
style = ElementTheme.typography.fontBodyMdRegular
200204
)
201205
}
202206
}
203207

204208
/**
205-
* Convert a logcat line to a color.
206-
* Ex: `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81`
209+
* Convert a line to a color.
210+
* Ex for logcat:
211+
* `01-23 13:14:50.740 25818 25818 D org.matrix.rust.sdk: elementx: SyncIndicator = Hide | RustRoomListService.kt:81`
212+
* ^ use this char to determine the color
213+
* Ex for Rust logs:
214+
* `2024-01-26T10:22:26.947416Z WARN elementx: Restore with non-empty map | MatrixClientsHolder.kt:68`
215+
* ^ use this char to determine the color, see [LogLevel]
207216
*/
208217
@Composable
209-
private fun String.toColor(): Color {
210-
return when (getOrNull(31)) {
211-
'D' -> Color(0xFF299999)
212-
'I' -> Color(0xFFABC023)
213-
'W' -> Color(0xFFBBB529)
214-
'E' -> Color(0xFFFF6B68)
215-
'A' -> Color(0xFFFF6B68)
216-
else -> ElementTheme.colors.textPrimary
218+
private fun String.toColor(colorationMode: ColorationMode): Color {
219+
return when (colorationMode) {
220+
ColorationMode.Logcat -> when (getOrNull(31)) {
221+
'D' -> colorDebug
222+
'I' -> colorInfo
223+
'W' -> colorWarning
224+
'E' -> colorError
225+
'A' -> colorError
226+
else -> ElementTheme.colors.textPrimary
227+
}
228+
ColorationMode.RustLogs -> when (getOrNull(32)) {
229+
'E' -> ElementTheme.colors.textPrimary
230+
'G' -> colorDebug
231+
'O' -> colorInfo
232+
'N' -> colorWarning
233+
'R' -> colorError
234+
else -> ElementTheme.colors.textPrimary
235+
}
236+
ColorationMode.None -> ElementTheme.colors.textPrimary
217237
}
218238
}
219239

240+
private val colorDebug = Color(0xFF299999)
241+
private val colorInfo = Color(0xFFABC023)
242+
private val colorWarning = Color(0xFFBBB529)
243+
private val colorError = Color(0xFFFF6B68)
244+
220245
@PreviewsDayNight
221246
@Composable
222247
internal fun ViewFileViewPreview(@PreviewParameter(ViewFileStateProvider::class) state: ViewFileState) = ElementPreview {

features/viewfolder/impl/src/test/kotlin/io/element/android/features/viewfolder/test/file/ViewFilePresenterTest.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import app.cash.molecule.RecompositionMode
2020
import app.cash.molecule.moleculeFlow
2121
import app.cash.turbine.test
2222
import com.google.common.truth.Truth.assertThat
23+
import io.element.android.features.viewfolder.impl.file.ColorationMode
2324
import io.element.android.features.viewfolder.impl.file.FileContentReader
2425
import io.element.android.features.viewfolder.impl.file.FileSave
2526
import io.element.android.features.viewfolder.impl.file.FileShare
@@ -48,13 +49,38 @@ class ViewFilePresenterTest {
4849
val initialState = awaitItem()
4950
assertThat(initialState.name).isEqualTo("aName")
5051
assertThat(initialState.lines).isInstanceOf(AsyncData.Loading::class.java)
52+
assertThat(initialState.colorationMode).isEqualTo(ColorationMode.None)
5153
val loadedState = awaitItem()
5254
val lines = (loadedState.lines as AsyncData.Success).data
5355
assertThat(lines.size).isEqualTo(1)
5456
assertThat(lines.first()).isEqualTo("aLine")
5557
}
5658
}
5759

60+
@Test
61+
fun `present - coloration mode for logcat`() = runTest {
62+
val presenter = createPresenter(name = "logcat.log")
63+
moleculeFlow(RecompositionMode.Immediate) {
64+
presenter.present()
65+
}.test {
66+
val initialState = awaitItem()
67+
assertThat(initialState.colorationMode).isEqualTo(ColorationMode.Logcat)
68+
cancelAndConsumeRemainingEvents()
69+
}
70+
}
71+
72+
@Test
73+
fun `present - coloration mode for logs`() = runTest {
74+
val presenter = createPresenter(name = "logs.date")
75+
moleculeFlow(RecompositionMode.Immediate) {
76+
presenter.present()
77+
}.test {
78+
val initialState = awaitItem()
79+
assertThat(initialState.colorationMode).isEqualTo(ColorationMode.RustLogs)
80+
cancelAndConsumeRemainingEvents()
81+
}
82+
}
83+
5884
@Test
5985
fun `present - share should not have any side effect`() = runTest {
6086
val fileContentReader = FakeFileContentReader().apply {
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)