@@ -57,7 +57,14 @@ class TextEditorActivity : AppCompatActivity() {
5757 " ksh" to " ksh"
5858 )
5959
60- fun start (context : Context , file : String , title : String? = null, desc : String? = null, wrap : Boolean = true, dir : String? = null) {
60+ fun start (
61+ context : Context ,
62+ file : String ,
63+ title : String? = null,
64+ desc : String? = null,
65+ wrap : Boolean = true,
66+ dir : String? = null
67+ ) {
6168 val intent = Intent (context, TextEditorActivity ::class .java).apply {
6269 putExtra(EXTRA_FILE , file)
6370 putExtra(EXTRA_TITLE , title ? : " " )
@@ -105,6 +112,7 @@ class TextEditorActivity : AppCompatActivity() {
105112 finish()
106113 return
107114 }
115+
108116 filePath = extraFile
109117 configDir = intent.getStringExtra(EXTRA_DIR ).orEmpty()
110118 absoluteFilePath = resolveAbsolutePath(configDir, filePath)
@@ -181,7 +189,10 @@ class TextEditorActivity : AppCompatActivity() {
181189 val visibleBottom = visibleTop + scrollView.height - scrollView.paddingBottom
182190
183191 when {
184- lineBottom > visibleBottom -> scrollView.smoothScrollTo(0 , lineBottom - scrollView.height + scrollView.paddingBottom)
192+ lineBottom > visibleBottom -> scrollView.smoothScrollTo(
193+ 0 ,
194+ lineBottom - scrollView.height + scrollView.paddingBottom
195+ )
185196 lineTop < visibleTop -> scrollView.smoothScrollTo(0 , lineTop)
186197 }
187198 }
@@ -195,7 +206,11 @@ class TextEditorActivity : AppCompatActivity() {
195206 private fun fileExtension (): String {
196207 val name = File (absoluteFilePath).name
197208 val dotIndex = name.lastIndexOf(" ." )
198- return if (dotIndex >= 0 && dotIndex < name.length - 1 ) name.substring(dotIndex + 1 ).lowercase() else " "
209+ return if (dotIndex >= 0 && dotIndex < name.length - 1 ) {
210+ name.substring(dotIndex + 1 ).lowercase()
211+ } else {
212+ " "
213+ }
199214 }
200215
201216 private fun runnableInterpreter (): String? = RUNNABLE_EXTENSIONS [fileExtension()]
@@ -220,7 +235,11 @@ class TextEditorActivity : AppCompatActivity() {
220235 isNewFile = newFile
221236 savedContent = content
222237 binding.editorContent.setText(content)
223- binding.editorContent.hint = if (newFile) getString(R .string.editor_hint_new_file) else getString(R .string.editor_hint_empty)
238+ binding.editorContent.hint = if (newFile) {
239+ getString(R .string.editor_hint_new_file)
240+ } else {
241+ getString(R .string.editor_hint_empty)
242+ }
224243 }
225244 }
226245 }
@@ -263,7 +282,10 @@ class TextEditorActivity : AppCompatActivity() {
263282 )
264283 hsv.removeAllViews()
265284 hsv.addView(editText)
266- hsv.layoutParams = ViewGroup .LayoutParams (ViewGroup .LayoutParams .MATCH_PARENT , ViewGroup .LayoutParams .WRAP_CONTENT )
285+ hsv.layoutParams = ViewGroup .LayoutParams (
286+ ViewGroup .LayoutParams .MATCH_PARENT ,
287+ ViewGroup .LayoutParams .WRAP_CONTENT
288+ )
267289 hsv.scrollTo(0 , 0 )
268290 scrollView.addView(hsv)
269291 }
@@ -272,7 +294,10 @@ class TextEditorActivity : AppCompatActivity() {
272294 // Layout nội bộ theo chiều rộng mới (văn bản đã dàn trang trước đó bị giữ nguyên), nên
273295 // phải set lại text để buộc nó dựng lại layout rồi khôi phục vị trí con trỏ.
274296 editText.setText(currentText)
275- editText.setSelection(cursorStart.coerceAtMost(currentText.length), cursorEnd.coerceAtMost(currentText.length))
297+ editText.setSelection(
298+ cursorStart.coerceAtMost(currentText.length),
299+ cursorEnd.coerceAtMost(currentText.length)
300+ )
276301 }
277302
278303 private fun hasUnsavedChanges (): Boolean {
@@ -289,12 +314,18 @@ class TextEditorActivity : AppCompatActivity() {
289314 this ,
290315 title = getString(R .string.editor_unsaved_title),
291316 message = getString(R .string.editor_unsaved_message),
292- onConfirm = DialogHelper .DialogButton (getString(R .string.editor_save), onClick = Runnable {
293- saveFile { success -> if (success) finish() }
294- }),
295- onCancel = DialogHelper .DialogButton (getString(R .string.editor_discard), onClick = Runnable {
296- finish()
297- })
317+ onConfirm = DialogHelper .DialogButton (
318+ getString(R .string.editor_save),
319+ onClick = Runnable {
320+ saveFile { success -> if (success) finish() }
321+ }
322+ ),
323+ onCancel = DialogHelper .DialogButton (
324+ getString(R .string.editor_discard),
325+ onClick = Runnable {
326+ finish()
327+ }
328+ )
298329 )
299330 }
300331
@@ -330,28 +361,53 @@ class TextEditorActivity : AppCompatActivity() {
330361 }
331362
332363 /* *
333- * Lưu nội dung hiện tại xuống file. Thử ghi trực tiếp trước, nếu không được (thiếu quyền)
334- * thì ghi ra file cache riêng của ứng dụng rồi copy đè bằng quyền root.
364+ * Lưu nội dung hiện tại xuống file.
365+ *
366+ * showProgress = false: không hiện màn hình "vui lòng chờ"
367+ * showToast = false: không hiện toast thành công/thất bại
335368 */
336- private fun saveFile (onResult : ((Boolean ) -> Unit )? = null) {
369+ private fun saveFile (
370+ showProgress : Boolean = true,
371+ showToast : Boolean = true,
372+ onResult : ((Boolean ) -> Unit )? = null
373+ ) {
337374 if (isSaving) return
338375 isSaving = true
376+
339377 val content = binding.editorContent.text?.toString().orEmpty()
340- progressBarDialog.showDialog(getString(R .string.editor_saving))
378+ if (showProgress) {
379+ progressBarDialog.showDialog(getString(R .string.editor_saving))
380+ }
341381
342382 lifecycleScope.launch(Dispatchers .IO ) {
343383 val success = writeFileContent(absoluteFilePath, content)
344384
345385 withContext(Dispatchers .Main ) {
346- progressBarDialog.hideDialog()
386+ if (showProgress) {
387+ progressBarDialog.hideDialog()
388+ }
347389 isSaving = false
390+
348391 if (success) {
349392 savedContent = content
350393 isNewFile = false
351- Toast .makeText(this @TextEditorActivity, R .string.editor_save_success, Toast .LENGTH_SHORT ).show()
394+ if (showToast) {
395+ Toast .makeText(
396+ this @TextEditorActivity,
397+ R .string.editor_save_success,
398+ Toast .LENGTH_SHORT
399+ ).show()
400+ }
352401 } else {
353- Toast .makeText(this @TextEditorActivity, R .string.editor_save_fail, Toast .LENGTH_LONG ).show()
402+ if (showToast) {
403+ Toast .makeText(
404+ this @TextEditorActivity,
405+ R .string.editor_save_fail,
406+ Toast .LENGTH_LONG
407+ ).show()
408+ }
354409 }
410+
355411 onResult?.invoke(success)
356412 }
357413 }
@@ -391,6 +447,7 @@ class TextEditorActivity : AppCompatActivity() {
391447 chmod 644 "$path "
392448 if [ -f "$path " ]; then echo EDITOR_SAVE_OK; fi
393449 """ .trimIndent()
450+
394451 val result = KeepShellPublic .doCmdSync(command)
395452 cacheFile.delete()
396453 result.trim().contains(" EDITOR_SAVE_OK" )
@@ -400,9 +457,19 @@ class TextEditorActivity : AppCompatActivity() {
400457 }
401458
402459 private fun saveAndRun (interpreter : String ) {
403- saveFile { success ->
460+ // Lưu im lặng rồi chạy ngay, không hiện progress/toast lưu file
461+ saveFile(
462+ showProgress = false ,
463+ showToast = false
464+ ) { success ->
404465 if (success) {
405466 runScript(interpreter)
467+ } else {
468+ Toast .makeText(
469+ this ,
470+ R .string.editor_save_fail,
471+ Toast .LENGTH_LONG
472+ ).show()
406473 }
407474 }
408475 }
@@ -413,6 +480,7 @@ class TextEditorActivity : AppCompatActivity() {
413480 interruptable = true
414481 shell = RunnableNode .shellModeDefault
415482 }
483+
416484 val script = " chmod 755 \" $absoluteFilePath \" 2>/dev/null\n $interpreter \" $absoluteFilePath \"\n "
417485
418486 val dialog = DialogLogFragment .create(
0 commit comments