@@ -102,7 +102,7 @@ class DialogLogFragment : DialogFragment() {
102102 binding.btnCopy.setOnClickListener {
103103 try {
104104 val clipboard = requireContext().getSystemService(Context .CLIPBOARD_SERVICE ) as ClipboardManager
105- // Lấy toàn bộ text từ StringBuilder của handler (không bị giới hạn bởi ListView )
105+ // Copy toàn bộ log từ StringBuilder (không giới hạn)
106106 val fullLog = currentHandler?.getAllLogText() ? : " "
107107 val clip = ClipData .newPlainText(" shell_log" , fullLog)
108108 clipboard.setPrimaryClip(clip)
@@ -125,8 +125,20 @@ class DialogLogFragment : DialogFragment() {
125125
126126 binding.actionProgress.isIndeterminate = true
127127
128- // Khởi tạo Handler với ListView
129128 val handler = MyShellHandler (requireContext().applicationContext, object : IActionEventHandler {
129+ override fun onStart (forceStop : Runnable ? ) {
130+ running = true
131+ canceled = false
132+ forceStopRunnable = forceStop
133+ dialog?.window?.addFlags(WindowManager .LayoutParams .FLAG_KEEP_SCREEN_ON )
134+ binding.btnExit.visibility = View .GONE
135+ binding.btnCancel.visibility = if (nodeInfo.interruptable && forceStop != null ) View .VISIBLE else View .GONE
136+ }
137+
138+ override fun onSuccess () {
139+ if (nodeInfo.autoOff) closeView()
140+ }
141+
130142 override fun onCompleted () {
131143 running = false
132144 onExit.run ()
@@ -139,19 +151,6 @@ class DialogLogFragment : DialogFragment() {
139151 }
140152 isCancelable = true
141153 }
142-
143- override fun onSuccess () {
144- if (nodeInfo.autoOff) closeView()
145- }
146-
147- override fun onStart (forceStop : Runnable ? ) {
148- running = true
149- canceled = false
150- forceStopRunnable = forceStop
151- dialog?.window?.addFlags(WindowManager .LayoutParams .FLAG_KEEP_SCREEN_ON )
152- binding.btnExit.visibility = View .GONE
153- binding.btnCancel.visibility = if (nodeInfo.interruptable && forceStop != null ) View .VISIBLE else View .GONE
154- }
155154 }, binding.shellOutputList, binding.actionProgress)
156155
157156 this .currentHandler = handler
@@ -174,14 +173,17 @@ class DialogLogFragment : DialogFragment() {
174173
175174 private val listViewRef = WeakReference (listView)
176175 private val progressRef = WeakReference (shellProgress)
177-
178- // Dữ liệu cho hiển thị (Giới hạn 5k dòng)
179176 private val logData = mutableListOf<SpannableString >()
180- private val adapter = ArrayAdapter <SpannableString >(context, android.R .layout.simple_list_item_1, logData)
181-
182- // Dữ liệu cho Copy (Không giới hạn)
183177 private val fullLogBuilder = StringBuilder ()
184178
179+ // SỬ DỤNG log_item.xml CỦA BẠN TẠI ĐÂY
180+ private val adapter = ArrayAdapter <SpannableString >(
181+ context,
182+ R .layout.log_item,
183+ android.R .id.text1,
184+ logData
185+ )
186+
185187 private val errorColor = getColor(R .color.kr_shell_log_error)
186188 private val basicColor = getColor(R .color.kr_shell_log_basic)
187189 private val scriptColor = getColor(R .color.kr_shell_log_script)
@@ -190,6 +192,7 @@ class DialogLogFragment : DialogFragment() {
190192
191193 init {
192194 listView?.adapter = adapter
195+ listView?.divider = null // Xóa gạch ngang giữa các dòng log
193196 }
194197
195198 private fun getColor (resId : Int ): Int {
@@ -228,15 +231,16 @@ class DialogLogFragment : DialogFragment() {
228231 override fun onProgress (current : Int , total : Int ) {
229232 val shellProgress = progressRef.get() ? : return
230233 shellProgress.post {
231- when {
232- current < 0 -> { shellProgress.visibility = View .VISIBLE ; shellProgress.isIndeterminate = true }
233- current >= total -> shellProgress.visibility = View .GONE
234- else -> {
235- shellProgress.visibility = View .VISIBLE
236- shellProgress.isIndeterminate = false
237- shellProgress.max = total
238- shellProgress.progress = current
239- }
234+ if (current < 0 ) {
235+ shellProgress.visibility = View .VISIBLE
236+ shellProgress.isIndeterminate = true
237+ } else if (current >= total) {
238+ shellProgress.visibility = View .GONE
239+ } else {
240+ shellProgress.visibility = View .VISIBLE
241+ shellProgress.isIndeterminate = false
242+ shellProgress.max = total
243+ shellProgress.progress = current
240244 }
241245 }
242246 }
@@ -257,12 +261,21 @@ class DialogLogFragment : DialogFragment() {
257261 override fun updateLog (msg : SpannableString ? ) {
258262 val listView = listViewRef.get() ? : return
259263 msg?.let {
260- // Thêm vào Builder cho việc Copy (Không giới hạn)
261- fullLogBuilder.append(it.toString()).append(" \n " )
264+ val rawStr = it.toString()
265+ // Lưu vào Builder để Copy (giữ nguyên gốc)
266+ fullLogBuilder.append(rawStr).append(" \n " )
267+
268+ // XỬ LÝ HIỂN THỊ: Xóa bỏ ký tự ngắt dòng thừa để log khít nhau
269+ val displayStr = rawStr.replace(" \n " , " " ).replace(" \r " , " " )
270+ if (displayStr.isEmpty()) return @let
271+
272+ // Ở đây ta dùng lại object 'it' nhưng xóa bỏ ký tự xuống dòng nếu cần giữ Span màu sắc
273+ // Hoặc đơn giản là tạo Spannable mới từ chuỗi đã làm sạch
274+ val cleanSpannable = SpannableString (displayStr)
262275
263- // Cập nhật giao diện (Giới hạn 5000 dòng cuối)
264276 listView.post {
265- logData.add(it)
277+ logData.add(cleanSpannable)
278+ // Giới hạn 5000 dòng trên giao diện để tránh lag
266279 if (logData.size > 5000 ) {
267280 logData.subList(0 , logData.size - 5000 ).clear()
268281 }
0 commit comments