Skip to content

Commit d0c535a

Browse files
committed
feat: new deploy user experience
A notification will be created on deploy failure to guide user to view error logs.
1 parent b391e89 commit d0c535a

File tree

8 files changed

+115
-24
lines changed

8 files changed

+115
-24
lines changed

app/src/main/java/com/osfans/trime/daemon/RimeDaemon.kt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,29 @@ package com.osfans.trime.daemon
66

77
import android.app.NotificationChannel
88
import android.app.NotificationManager
9+
import android.app.PendingIntent
10+
import android.content.Intent
911
import android.os.Build
1012
import androidx.core.app.NotificationCompat
13+
import androidx.core.content.ContextCompat
1114
import com.osfans.trime.R
1215
import com.osfans.trime.TrimeApplication
1316
import com.osfans.trime.core.Rime
1417
import com.osfans.trime.core.RimeApi
1518
import com.osfans.trime.core.RimeLifecycle
19+
import com.osfans.trime.core.RimeMessage
1620
import com.osfans.trime.core.lifecycleScope
1721
import com.osfans.trime.core.whenReady
22+
import com.osfans.trime.ui.main.LogActivity
1823
import com.osfans.trime.util.appContext
24+
import com.osfans.trime.util.toast
1925
import kotlinx.coroutines.CoroutineScope
26+
import kotlinx.coroutines.Dispatchers
27+
import kotlinx.coroutines.flow.launchIn
28+
import kotlinx.coroutines.flow.onEach
2029
import kotlinx.coroutines.launch
2130
import kotlinx.coroutines.runBlocking
31+
import kotlinx.coroutines.withContext
2232
import splitties.systemservices.notificationManager
2333
import java.util.concurrent.locks.ReentrantLock
2434
import kotlin.concurrent.withLock
@@ -120,6 +130,7 @@ object RimeDaemon {
120130
}
121131

122132
private const val CHANNEL_ID = "rime-daemon"
133+
private const val MESSAGE_ID = 2331
123134
private var restartId = 0
124135

125136
/**
@@ -140,11 +151,66 @@ object RimeDaemon {
140151
.let { notificationManager.notify(id, it) }
141152
realRime.finalize()
142153
realRime.startup(fullCheck)
154+
realRime.messageFlow
155+
.onEach(::handleRimeMessage)
156+
.launchIn(TrimeApplication.getInstance().coroutineScope)
143157
TrimeApplication.getInstance().coroutineScope.launch {
144158
// cancel notification on ready
145159
realRime.lifecycle.whenReady {
146160
notificationManager.cancel(id)
147161
}
148162
}
149163
}
164+
165+
private suspend fun handleRimeMessage(it: RimeMessage<*>) {
166+
if (it is RimeMessage.DeployMessage) {
167+
when (it.data) {
168+
RimeMessage.DeployMessage.State.Start -> {
169+
withContext(Dispatchers.IO) {
170+
Runtime.getRuntime().exec(arrayOf("logcat", "-c"))
171+
}
172+
}
173+
RimeMessage.DeployMessage.State.Success -> {
174+
ContextCompat.getMainExecutor(appContext).execute {
175+
appContext.toast(R.string.deploy_finish)
176+
}
177+
}
178+
RimeMessage.DeployMessage.State.Failure -> {
179+
val intent =
180+
Intent(appContext, LogActivity::class.java).apply {
181+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
182+
val log =
183+
withContext(Dispatchers.IO) {
184+
Runtime
185+
.getRuntime()
186+
.exec(
187+
arrayOf("logcat", "-d", "-v", "brief", "-s", "rime.trime:W"),
188+
).inputStream
189+
.bufferedReader()
190+
.readText()
191+
}
192+
putExtra(LogActivity.FROM_DEPLOY, true)
193+
putExtra(LogActivity.DEPLOY_FAILURE_TRACE, log)
194+
}
195+
NotificationCompat
196+
.Builder(appContext, CHANNEL_ID)
197+
.setSmallIcon(R.drawable.ic_baseline_warning_24)
198+
.setContentTitle(appContext.getString(R.string.rime_daemon))
199+
.setContentText(appContext.getString(R.string.view_deploy_failure_log))
200+
.setContentIntent(
201+
PendingIntent.getActivity(
202+
appContext,
203+
0,
204+
intent,
205+
PendingIntent.FLAG_UPDATE_CURRENT,
206+
),
207+
).setOngoing(false)
208+
.setAutoCancel(true)
209+
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
210+
.build()
211+
.let { notificationManager.notify(MESSAGE_ID, it) }
212+
}
213+
}
214+
}
215+
}
150216
}

app/src/main/java/com/osfans/trime/ui/components/log/LogView.kt

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@ package com.osfans.trime.ui.components.log
66

77
import android.content.Context
88
import android.util.AttributeSet
9-
import android.view.ViewGroup
109
import android.widget.HorizontalScrollView
1110
import androidx.core.content.ContextCompat
1211
import androidx.core.text.buildSpannedString
1312
import androidx.core.text.color
1413
import androidx.lifecycle.findViewTreeLifecycleOwner
1514
import androidx.lifecycle.lifecycleScope
16-
import androidx.recyclerview.widget.LinearLayoutManager
17-
import androidx.recyclerview.widget.RecyclerView
1815
import com.osfans.trime.R
1916
import com.osfans.trime.util.Logcat
2017
import kotlinx.coroutines.flow.launchIn
2118
import kotlinx.coroutines.flow.onEach
2219
import splitties.resources.styledColor
20+
import splitties.views.dsl.core.add
21+
import splitties.views.dsl.core.lParams
22+
import splitties.views.dsl.core.matchParent
23+
import splitties.views.dsl.core.wrapContent
24+
import splitties.views.dsl.recyclerview.recyclerView
25+
import splitties.views.recyclerview.verticalLayoutManager
2326

2427
/**
2528
* A scroll view to look up the app log.
@@ -39,21 +42,15 @@ class LogView
3942
private val logAdapter = LogAdapter()
4043

4144
private val recyclerView =
42-
RecyclerView(context).apply {
45+
recyclerView {
4346
adapter = logAdapter
44-
layoutManager =
45-
LinearLayoutManager(context).apply {
46-
orientation = LinearLayoutManager.VERTICAL
47-
}
47+
layoutManager = verticalLayoutManager()
4848
}
4949

5050
init {
51-
addView(
51+
add(
5252
recyclerView,
53-
LayoutParams(
54-
ViewGroup.LayoutParams.WRAP_CONTENT,
55-
ViewGroup.LayoutParams.MATCH_PARENT,
56-
),
53+
lParams(wrapContent, matchParent),
5754
)
5855
}
5956

@@ -62,12 +59,6 @@ class LogView
6259
super.onDetachedFromWindow()
6360
}
6461

65-
fun fromCustomLogLines(lines: List<String>) {
66-
lines.onEach {
67-
dyeAndAppendString(it)
68-
}
69-
}
70-
7162
fun append(content: String) {
7263
logAdapter.append(
7364
buildSpannedString {
@@ -80,12 +71,11 @@ class LogView
8071
this.logcat = logcat
8172
logcat.initLogFlow()
8273
logcat.logFlow
83-
.onEach {
84-
dyeAndAppendString(it)
85-
}.launchIn(findViewTreeLifecycleOwner()!!.lifecycleScope)
74+
.onEach(::buildColoredString)
75+
.launchIn(findViewTreeLifecycleOwner()!!.lifecycleScope)
8676
}
8777

88-
private fun dyeAndAppendString(str: String) {
78+
private fun buildColoredString(str: String) {
8979
val color =
9080
ContextCompat.getColor(
9181
context,

app/src/main/java/com/osfans/trime/ui/main/LogActivity.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package com.osfans.trime.ui.main
66

7+
import android.content.ClipData
78
import android.os.Bundle
89
import android.view.View
910
import android.view.ViewGroup
@@ -28,6 +29,7 @@ import com.osfans.trime.util.toast
2829
import kotlinx.coroutines.Dispatchers
2930
import kotlinx.coroutines.NonCancellable
3031
import kotlinx.coroutines.launch
32+
import splitties.systemservices.clipboardManager
3133

3234
/**
3335
* The activity to show [LogView].
@@ -41,7 +43,9 @@ class LogActivity : AppCompatActivity() {
4143

4244
companion object {
4345
const val FROM_CRASH = "from_crash"
46+
const val FROM_DEPLOY = "from_deploy"
4447
const val CRASH_STACK_TRACE = "crash_stack_trace"
48+
const val DEPLOY_FAILURE_TRACE = "deploy_failure_trace"
4549
}
4650

4751
private fun registerLauncher() {
@@ -88,6 +92,7 @@ class LogActivity : AppCompatActivity() {
8892
if (intent.hasExtra(FROM_CRASH)) {
8993
supportActionBar!!.setTitle(R.string.crash_logs)
9094
clearButton.visibility = View.GONE
95+
copyButton.visibility = View.GONE
9196
AlertDialog
9297
.Builder(this@LogActivity)
9398
.setTitle(R.string.app_crash)
@@ -97,11 +102,16 @@ class LogActivity : AppCompatActivity() {
97102
logView.append("--------- Crash stacktrace")
98103
logView.append(intent.getStringExtra(CRASH_STACK_TRACE) ?: "<empty>")
99104
logView.setLogcat(Logcat(TrimeApplication.getLastPid()))
105+
} else if (intent.hasExtra(FROM_DEPLOY)) {
106+
supportActionBar!!.setTitle(R.string.deploy_failure)
107+
clearButton.visibility = View.GONE
108+
logView.append(intent.getStringExtra(DEPLOY_FAILURE_TRACE) ?: "<empty>")
100109
} else {
101110
supportActionBar!!.apply {
102111
setDisplayHomeAsUpEnabled(true)
103112
setTitle(R.string.real_time_logs)
104113
}
114+
copyButton.visibility = View.GONE
105115
logView.setLogcat(Logcat())
106116
}
107117
clearButton.setOnClickListener {
@@ -110,6 +120,13 @@ class LogActivity : AppCompatActivity() {
110120
exportButton.setOnClickListener {
111121
launcher.launch("$packageName-${iso8601UTCDateTime()}.txt")
112122
}
123+
copyButton.setOnClickListener {
124+
val data = ClipData.newPlainText("log", logView.currentLog)
125+
clipboardManager.setPrimaryClip(data)
126+
if (clipboardManager.hasPrimaryClip()) {
127+
toast(R.string.copy_done)
128+
}
129+
}
113130
jumpToBottomButton.setOnClickListener {
114131
logView.scrollToBottom()
115132
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
2+
3+
<path android:fillColor="@android:color/white" android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
4+
5+
</vector>

app/src/main/res/layout/activity_log.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
5454
android:layout_height="wrap_content"
5555
android:text="@string/export" />
5656

57+
<Button
58+
android:id="@+id/copyButton"
59+
style="?android:attr/buttonBarButtonStyle"
60+
android:layout_width="wrap_content"
61+
android:layout_height="wrap_content"
62+
android:text="@android:string/copy" />
63+
5764
<Button
5865
android:id="@+id/jumpToBottomButton"
5966
style="?android:attr/buttonBarButtonStyle"
@@ -62,4 +69,4 @@ SPDX-License-Identifier: GPL-3.0-or-later
6269
android:text="@string/scroll_to_bottom" />
6370
</LinearLayout>
6471

65-
</androidx.constraintlayout.widget.ConstraintLayout>
72+
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/values-zh-rCN/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
241241
<string name="top_left">左上</string>
242242
<string name="top_right">右上</string>
243243
<string name="display_position">显示位置</string>
244+
<string name="deploy_failure">部署失败</string>
245+
<string name="view_deploy_failure_log">部署失败。点此查看错误日志。</string>
244246
</resources>

app/src/main/res/values-zh-rTW/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
241241
<string name="top_left">左上</string>
242242
<string name="top_right">右上</string>
243243
<string name="display_position">顯示位置</string>
244+
<string name="deploy_failure">部署失敗</string>
245+
<string name="view_deploy_failure_log">部署失敗。點此檢視錯誤日誌。</string>
244246
</resources>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
241241
<string name="top_left">Top left</string>
242242
<string name="top_right">Top right</string>
243243
<string name="display_position">Display position</string>
244+
<string name="deploy_failure">Deploy failure</string>
245+
<string name="view_deploy_failure_log">Deploy failure. Click here to view error log.</string>
244246
</resources>

0 commit comments

Comments
 (0)