Skip to content

Commit 8394585

Browse files
committed
#1890 feat: add button to save log to file and share it
1 parent 9e25597 commit 8394585

File tree

5 files changed

+65
-6
lines changed

5 files changed

+65
-6
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
#### TO BE RELEASED
44

5+
## Added
6+
7+
- #1890 add button to save log to file and share it. The clipboard button now cuts off older entries and keeps newest ones.
8+
59
## Fixed
610

711
- Only autostart PRO mode with Shizuku if Shizuku permission is granted. Otherwise fallback to method with Wireless Debugging and WRITE_SECURE_SETTINGS permission.
812
- Starting system bridge for the first time would be janky because granting READ_LOGS kills the app process. Only grant for READ_LOGS when sharing logcat from settings.
9-
- #1886 mobile data actions work in PRO mode
13+
- #1886 mobile data actions work in PRO mode.
1014

1115
## [4.0.0 Beta 1](https://github.com/sds100/KeyMapper/releases/tag/v4.0.0-beta.01)
1216

base/src/main/java/io/github/sds100/keymapper/base/logging/DisplayLogUseCase.kt

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
11
package io.github.sds100.keymapper.base.logging
22

3+
import android.content.Context
4+
import androidx.core.net.toUri
5+
import dagger.hilt.android.qualifiers.ApplicationContext
36
import io.github.sds100.keymapper.base.R
7+
import io.github.sds100.keymapper.base.utils.ShareUtils
48
import io.github.sds100.keymapper.base.utils.ui.ResourceProvider
9+
import io.github.sds100.keymapper.common.BuildConfigProvider
510
import io.github.sds100.keymapper.data.entities.LogEntryEntity
611
import io.github.sds100.keymapper.data.repositories.LogRepository
712
import io.github.sds100.keymapper.system.clipboard.ClipboardAdapter
813
import io.github.sds100.keymapper.system.files.FileAdapter
14+
import io.github.sds100.keymapper.system.files.FileUtils
15+
import io.github.sds100.keymapper.system.files.IFile
916
import java.text.SimpleDateFormat
1017
import java.util.Date
1118
import java.util.Locale
1219
import javax.inject.Inject
20+
import kotlinx.coroutines.CoroutineScope
1321
import kotlinx.coroutines.Dispatchers
1422
import kotlinx.coroutines.flow.Flow
1523
import kotlinx.coroutines.flow.first
1624
import kotlinx.coroutines.flow.flowOn
1725
import kotlinx.coroutines.flow.map
26+
import kotlinx.coroutines.launch
27+
import kotlinx.coroutines.withContext
1828

1929
class DisplayLogUseCaseImpl @Inject constructor(
30+
@ApplicationContext private val ctx: Context,
31+
private val coroutineScope: CoroutineScope,
2032
private val repository: LogRepository,
2133
private val resourceProvider: ResourceProvider,
2234
private val clipboardAdapter: ClipboardAdapter,
2335
private val fileAdapter: FileAdapter,
36+
private val buildConfigProvider: BuildConfigProvider,
2437
) : DisplayLogUseCase {
2538
private val dateFormat = SimpleDateFormat("MM/dd HH:mm:ss.SSS", Locale.getDefault())
2639
private val severityString: Map<Int, String> = mapOf(
@@ -56,12 +69,37 @@ class DisplayLogUseCaseImpl @Inject constructor(
5669

5770
logEntries
5871
.reversed()
59-
.joinToString(separator = "\n") { entry ->
60-
val date = dateFormat.format(Date(entry.time))
72+
.joinToString(separator = "\n", transform = ::entryToString)
73+
.also { append(it) }
74+
}
75+
}
76+
77+
private fun entryToString(entry: LogEntryEntity): String {
78+
val date = dateFormat.format(Date(entry.time))
79+
80+
return "$date ${severityString[entry.severity]} ${entry.message}"
81+
}
6182

62-
return@joinToString "$date ${severityString[entry.severity]} ${entry.message}"
83+
override fun shareFile() {
84+
val fileName = "logs/key_mapper_log_${FileUtils.createFileDate()}.txt"
85+
86+
coroutineScope.launch {
87+
withContext(Dispatchers.IO) {
88+
val logEntries = repository.log.first()
89+
val logText = logEntries.joinToString(separator = "\n", transform = ::entryToString)
90+
91+
val file: IFile = fileAdapter.getPrivateFile(fileName)
92+
file.createFile()
93+
94+
with(file.outputStream()?.bufferedWriter()) {
95+
this?.write(logText)
96+
this?.flush()
6397
}
64-
.also { append(it) }
98+
99+
val publicUri = fileAdapter.getPublicUriForPrivateFile(file)
100+
101+
ShareUtils.shareFile(ctx, publicUri.toUri(), buildConfigProvider.packageName)
102+
}
65103
}
66104
}
67105
}
@@ -70,4 +108,5 @@ interface DisplayLogUseCase {
70108
val log: Flow<List<LogEntry>>
71109
fun clearLog()
72110
suspend fun copyToClipboard()
111+
fun shareFile()
73112
}

base/src/main/java/io/github/sds100/keymapper/base/logging/LogScreen.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState
1616
import androidx.compose.material.icons.Icons
1717
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
1818
import androidx.compose.material.icons.outlined.ContentCopy
19+
import androidx.compose.material.icons.outlined.Share
1920
import androidx.compose.material3.BottomAppBar
2021
import androidx.compose.material3.ExperimentalMaterial3Api
2122
import androidx.compose.material3.Icon
@@ -53,6 +54,7 @@ fun LogScreen(
5354
modifier = modifier,
5455
onBackClick = onBackClick,
5556
onCopyToClipboardClick = viewModel::onCopyToClipboardClick,
57+
onShareClick = viewModel::onShareFileClick,
5658
onClearLogClick = viewModel::onClearLogClick,
5759
content = {
5860
Content(
@@ -69,6 +71,7 @@ private fun LogScreen(
6971
modifier: Modifier = Modifier,
7072
onBackClick: () -> Unit = {},
7173
onCopyToClipboardClick: () -> Unit = {},
74+
onShareClick: () -> Unit = {},
7275
onClearLogClick: () -> Unit = {},
7376
content: @Composable () -> Unit,
7477
) {
@@ -96,6 +99,13 @@ private fun LogScreen(
9699
)
97100
}
98101
Spacer(Modifier.weight(1f))
102+
IconButton(onClick = onShareClick) {
103+
Icon(
104+
imageVector = Icons.Outlined.Share,
105+
contentDescription = stringResource(R.string.action_share_log),
106+
)
107+
}
108+
99109
IconButton(onClick = onCopyToClipboardClick) {
100110
Icon(
101111
imageVector = Icons.Outlined.ContentCopy,

base/src/main/java/io/github/sds100/keymapper/base/logging/LogViewModel.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ class LogViewModel @Inject constructor(private val displayLogUseCase: DisplayLog
4242
}
4343
}
4444

45+
fun onShareFileClick() {
46+
viewModelScope.launch {
47+
displayLogUseCase.shareFile()
48+
}
49+
}
50+
4551
fun onClearLogClick() {
4652
displayLogUseCase.clearLog()
4753
}

base/src/main/res/values/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@
388388
<string name="action_backup_everything">Back up everything</string>
389389
<string name="action_tap_to_pause_keymaps">Tap to pause</string>
390390
<string name="action_tap_to_resume_keymaps">Tap to resume</string>
391-
<string name="action_save_log">Save</string>
391+
<string name="action_share_log">Share</string>
392392
<string name="action_short_log_message">Toggle short messages</string>
393393
<string name="action_copy_log">Copy</string>
394394
<string name="action_clear_log">Clear</string>

0 commit comments

Comments
 (0)