Skip to content

Commit ca654ef

Browse files
committed
Update
1 parent 9d4608a commit ca654ef

2 files changed

Lines changed: 94 additions & 32 deletions

File tree

app/src/main/java/com/omarea/krscript/ui/ActionParamsLayoutRender.kt

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,18 @@ class ActionParamsLayoutRender(private var linearLayout: LinearLayout, activity:
271271
// Ví dụ: depend-on="mode|cam" depend-value="a|b" depend-mode="show|hide"
272272
// -> hiện khi mode = a VÀ cam khác b
273273
// - "priority" / "or": hỗ trợ MỨC ƯU TIÊN, xét theo thứ tự khai báo trong depend-on, TỪ
274-
// TRÁI SANG PHẢI. Điều kiện nào thỏa trước (đã tính cả depend-mode riêng của điều kiện
275-
// đó) sẽ quyết định luôn là "show", không cần xét tiếp các điều kiện còn lại. Nếu không
276-
// có điều kiện nào thỏa thì "hide".
277-
// Ví dụ: depend-on="mode|level" depend-value="b|7" depend-mode="show|show"
278-
// depend-logic="priority"
279-
// -> Nếu "mode" khớp "b" thì show luôn.
280-
// -> Nếu "mode" không khớp mà "level" khớp "7" thì vẫn show.
281-
// -> Nếu cả hai đều không khớp thì hide.
274+
// TRÁI SANG PHẢI. Điều kiện nào KHỚP depend-value trước (bất kể depend-mode riêng của
275+
// điều kiện đó là "show" hay "hide") sẽ QUYẾT ĐỊNH LUÔN kết quả cuối cùng (theo đúng
276+
// depend-mode của chính điều kiện đó) và dừng lại ngay, không xét tiếp các điều kiện còn
277+
// lại. Điều kiện không khớp thì coi như chưa quyết định được gì, chuyển sang xét điều
278+
// kiện kế tiếp. Nếu đi hết mà không điều kiện nào khớp thì mặc định "hide".
279+
// Ví dụ: depend-on="IMAGES|dinh_dang" depend-value="(erofs)|(EROFS)"
280+
// depend-mode="hide|show" depend-logic="priority"
281+
// -> Nếu "IMAGES" khớp "(erofs)" thì HIDE luôn (vì depend-mode của điều kiện
282+
// này là "hide"), không xét tiếp "dinh_dang".
283+
// -> Nếu "IMAGES" KHÔNG khớp "(erofs)", chuyển sang xét "dinh_dang": nếu khớp
284+
// "(EROFS)" thì SHOW (vì depend-mode của điều kiện này là "show").
285+
// -> Nếu cả hai điều kiện đều không khớp thì HIDE (mặc định).
282286
// - "priority-rtl" / "or-rtl": giống "priority" nhưng xét thứ tự ưu tiên TỪ PHẢI SANG TRÁI
283287
// (điều kiện cuối cùng khai báo trong depend-on được xét trước tiên).
284288
//
@@ -303,10 +307,16 @@ class ActionParamsLayoutRender(private var linearLayout: LinearLayout, activity:
303307
val dependValueList = (info.dependValue ?: "").split("|")
304308
val dependModeList = info.dependMode.split("|")
305309

306-
// Đánh giá điều kiện thứ i (theo đúng thứ tự khai báo trong dependOnList),
307-
// trả về null nếu không rõ param cha (bỏ qua điều kiện này), ngược lại trả về
308-
// true/false là kết quả "muốn show" của riêng điều kiện đó.
309-
fun evalCondition(i: Int): Boolean? {
310+
// Đánh giá điều kiện thứ i (theo đúng thứ tự khai báo trong dependOnList).
311+
// Trả về null nếu không rõ param cha (bỏ qua điều kiện này, coi như không áp dụng).
312+
// Ngược lại trả về Pair(matched, wantShow):
313+
// - matched: giá trị hiện tại của param cha có KHỚP depend-value ở vị trí i hay
314+
// không (chưa tính đến depend-mode). Dùng để biết điều kiện này có "áp dụng
315+
// được" hay không (priority-logic cần biết để quyết định dừng lại hay xét tiếp
316+
// điều kiện kế).
317+
// - wantShow: sau khi đã áp depend-mode ("hide" thì đảo ngược) - kết quả show/hide
318+
// mà điều kiện này "muốn" một khi nó khớp.
319+
fun evalCondition(i: Int): Pair<Boolean, Boolean>? {
310320
val parentName = dependOnList[i]
311321
val controllerInfo = currentParamInfos.find { it.name == parentName }
312322
val reader = valueReaders[parentName]
@@ -328,41 +338,47 @@ class ActionParamsLayoutRender(private var linearLayout: LinearLayout, activity:
328338
val matched = wanted.isEmpty() || wanted.any { currentIdentifiers.contains(it) }
329339

330340
val mode = (dependModeList.getOrNull(i) ?: dependModeList.lastOrNull() ?: "show").trim()
331-
return if (mode == "hide") !matched else matched
341+
val wantShow = if (mode == "hide") !matched else matched
342+
return Pair(matched, wantShow)
332343
}
333344

334345
val logic = info.dependLogic.trim().lowercase()
335346
val shouldShow: Boolean = when (logic) {
336347
"priority", "or", "priority-ltr", "or-ltr" -> {
337-
// Ưu tiên trái -> phải: điều kiện đầu tiên thỏa sẽ quyết định show luôn.
348+
// Ưu tiên trái -> phải: điều kiện nào KHỚP trước sẽ quyết định luôn (show hay
349+
// hide tuỳ depend-mode riêng của điều kiện đó) và dừng lại ngay, không xét
350+
// tiếp các điều kiện còn lại. Điều kiện không khớp (matched = false) coi như
351+
// "chưa quyết định được gì" -> chuyển sang xét điều kiện kế tiếp. Nếu không
352+
// điều kiện nào khớp thì mặc định hide.
338353
var result = false
339354
for (i in dependOnList.indices) {
340-
val conditionShow = evalCondition(i) ?: continue
341-
if (conditionShow) {
342-
result = true
355+
val (matched, wantShow) = evalCondition(i) ?: continue
356+
if (matched) {
357+
result = wantShow
343358
break
344359
}
345360
}
346361
result
347362
}
348363
"priority-rtl", "or-rtl" -> {
349-
// Ưu tiên phải -> trái: xét từ điều kiện cuối cùng trở về đầu.
364+
// Giống "priority" nhưng xét từ điều kiện cuối cùng trở về đầu.
350365
var result = false
351366
for (i in dependOnList.indices.reversed()) {
352-
val conditionShow = evalCondition(i) ?: continue
353-
if (conditionShow) {
354-
result = true
367+
val (matched, wantShow) = evalCondition(i) ?: continue
368+
if (matched) {
369+
result = wantShow
355370
break
356371
}
357372
}
358373
result
359374
}
360375
else -> {
361-
// "and" (mặc định): tất cả điều kiện phải cùng thỏa.
376+
// "and" (mặc định): tất cả điều kiện phải cùng thỏa (dựa trên wantShow, đã
377+
// tính cả depend-mode riêng của từng điều kiện).
362378
var result = true
363379
for (i in dependOnList.indices) {
364-
val conditionShow = evalCondition(i) ?: continue
365-
if (!conditionShow) {
380+
val (_, wantShow) = evalCondition(i) ?: continue
381+
if (!wantShow) {
366382
result = false
367383
break // AND: chỉ cần 1 điều kiện không thỏa là đủ để ẩn
368384
}

app/src/main/java/com/tool/tree/SplashActivity.kt

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,34 +232,80 @@ class SplashActivity : AppCompatActivity() {
232232

233233
// Nhận diện am:[...] (mở activity, ẩn khỏi log) và tự resolve @string/ten_resource cho các
234234
// dòng log thông thường còn lại trước khi hiển thị lên màn hình splash.
235+
// currentLineIsProgress được set ngay trước khi gọi processOutput() (luôn trên main thread,
236+
// đồng bộ) để onReader() biết dòng hiện tại có phải là cập nhật thanh tiến trình (\r) hay không.
237+
private var currentLineIsProgress = false
238+
235239
private inner class SplashLogOutputHandler : SilentShellOutputHandler(this@SplashActivity) {
236240
override fun onReader(msg: Any?) {
237241
val line = msg?.toString() ?: return
238-
onLogOutput(StringResRef.resolve(this@SplashActivity, line))
242+
onLogOutput(StringResRef.resolve(this@SplashActivity, line), currentLineIsProgress)
239243
}
240244
}
241245

246+
// Đọc stream theo từng ký tự thay vì dùng reader.forEachLine()/readLine(), vì readLine() coi
247+
// \r, \n và \r\n là tương đương nên không phân biệt được đâu là dòng log bình thường (kết
248+
// thúc bằng \n) và đâu là cập nhật thanh tiến trình tại chỗ (kết thúc bằng \r, không có \n,
249+
// ví dụ "Copying... 10%\rCopying... 20%\r..."). Ở đây ta giữ lại thông tin ký tự kết thúc để
250+
// xử lý đúng: \r -> ghi đè dòng cuối, \n -> thêm dòng mới. \r\n (CRLF) vẫn được gộp lại thành
251+
// một dòng duy nhất như bình thường.
242252
private fun readStreamAsync(reader: BufferedReader) {
243253
try {
244-
reader.forEachLine { line -> handleRawLogLine(line) }
254+
val buffer = StringBuilder()
255+
var lastWasCR = false
256+
var c: Int
257+
while (reader.read().also { c = it } != -1) {
258+
when (c) {
259+
'\r'.code -> {
260+
handleRawLogLine(buffer.toString(), isProgress = true)
261+
buffer.setLength(0)
262+
lastWasCR = true
263+
}
264+
'\n'.code -> {
265+
if (lastWasCR) {
266+
// Đây là \n của một cặp \r\n vừa xử lý ở nhánh \r phía trên, bỏ qua.
267+
lastWasCR = false
268+
} else {
269+
handleRawLogLine(buffer.toString(), isProgress = false)
270+
buffer.setLength(0)
271+
}
272+
}
273+
else -> {
274+
buffer.append(c.toChar())
275+
lastWasCR = false
276+
}
277+
}
278+
}
279+
if (buffer.isNotEmpty()) {
280+
handleRawLogLine(buffer.toString(), isProgress = false)
281+
}
245282
} catch (e: Exception) {}
246283
}
247284

248285
// Luôn xử lý trên main thread: vừa để an toàn cho SilentShellOutputHandler (cần Looper),
249286
// vừa vì onAm() bên trong có thể gọi startActivity().
250-
private fun handleRawLogLine(line: String) {
287+
private fun handleRawLogLine(line: String, isProgress: Boolean) {
251288
handler.post {
289+
currentLineIsProgress = isProgress
252290
splashLogHandler.processOutput(line)
253291
}
254292
}
255293

256-
private fun onLogOutput(log: String) {
294+
private fun onLogOutput(log: String, isProgress: Boolean) {
257295
synchronized(rows) {
258-
if (rows.size >= maxLines) {
259-
rows.removeAt(0)
260-
ignored = true
296+
if (isProgress && rows.isNotEmpty()) {
297+
// Bỏ qua các cú \r rỗng liên tiếp (không có nội dung mới) để tránh xoá dòng cuối.
298+
if (log.isEmpty()) return
299+
// Cập nhật (ghi đè) dòng cuối cùng thay vì thêm dòng mới -> thanh tiến trình
300+
// đứng yên một dòng và chỉ thay đổi nội dung.
301+
rows[rows.size - 1] = log
302+
} else {
303+
if (rows.size >= maxLines) {
304+
rows.removeAt(0)
305+
ignored = true
306+
}
307+
rows.add(log)
261308
}
262-
rows.add(log)
263309
binding.startStateText.text = rows.joinToString("\n", if (ignored) "…......…\n" else "")
264310
}
265311
}

0 commit comments

Comments
 (0)