|
@@ -21,6 +21,7 @@ import kotlinx.coroutines.delay
|
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.launch
|
|
|
import kotlinx.coroutines.withContext
|
|
import kotlinx.coroutines.withContext
|
|
|
import java.io.File
|
|
import java.io.File
|
|
|
|
|
+import java.util.ArrayList
|
|
|
import android.os.Environment
|
|
import android.os.Environment
|
|
|
import android.util.Log
|
|
import android.util.Log
|
|
|
import android.widget.Toast
|
|
import android.widget.Toast
|
|
@@ -41,6 +42,11 @@ class FileBrowserViewModel(private val context: Context) : ViewModel() {
|
|
|
private set
|
|
private set
|
|
|
var localUpEnabled by mutableStateOf(false)
|
|
var localUpEnabled by mutableStateOf(false)
|
|
|
private set
|
|
private set
|
|
|
|
|
+ var localBackHistory by mutableStateOf<List<String>>(emptyList())
|
|
|
|
|
+ var localForwardHistory by mutableStateOf<List<String>>(emptyList())
|
|
|
|
|
+
|
|
|
|
|
+ var sftpBackHistory by mutableStateOf<List<String>>(emptyList())
|
|
|
|
|
+ var sftpForwardHistory by mutableStateOf<List<String>>(emptyList())
|
|
|
|
|
|
|
|
// --- SFTP ---
|
|
// --- SFTP ---
|
|
|
val sftpManager = SftpManager()
|
|
val sftpManager = SftpManager()
|
|
@@ -169,18 +175,45 @@ class FileBrowserViewModel(private val context: Context) : ViewModel() {
|
|
|
// ======================== LOCAL ========================
|
|
// ======================== LOCAL ========================
|
|
|
fun refreshLocal(path: String? = null) {
|
|
fun refreshLocal(path: String? = null) {
|
|
|
val dir = File(path ?: localCurrentPath)
|
|
val dir = File(path ?: localCurrentPath)
|
|
|
- localCurrentPath = dir.absolutePath
|
|
|
|
|
|
|
+ val newPath = dir.absolutePath
|
|
|
|
|
+ if (newPath != localCurrentPath) {
|
|
|
|
|
+ localBackHistory = localBackHistory + localCurrentPath
|
|
|
|
|
+ localForwardHistory = emptyList()
|
|
|
|
|
+ }
|
|
|
|
|
+ localCurrentPath = newPath
|
|
|
localFiles = FileUtils.listLocalFiles(dir)
|
|
localFiles = FileUtils.listLocalFiles(dir)
|
|
|
localUpEnabled = dir.parentFile != null
|
|
localUpEnabled = dir.parentFile != null
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ fun goBackLocal() {
|
|
|
|
|
+ if (localBackHistory.isEmpty()) return
|
|
|
|
|
+ val prev = localBackHistory.last()
|
|
|
|
|
+ localBackHistory = localBackHistory.dropLast(1)
|
|
|
|
|
+ localForwardHistory = listOf(localCurrentPath) + localForwardHistory
|
|
|
|
|
+ refreshLocal(prev)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun goForwardLocal() {
|
|
|
|
|
+ if (localForwardHistory.isEmpty()) return
|
|
|
|
|
+ val next = localForwardHistory.first()
|
|
|
|
|
+ localForwardHistory = localForwardHistory.drop(1)
|
|
|
|
|
+ localBackHistory = localBackHistory + localCurrentPath
|
|
|
|
|
+ refreshLocal(next)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
fun navigateLocal(item: FileItem) {
|
|
fun navigateLocal(item: FileItem) {
|
|
|
if (isSelectionMode) { toggleSelection(item.path); return }
|
|
if (isSelectionMode) { toggleSelection(item.path); return }
|
|
|
- if (item.isDirectory) { refreshLocal(item.path) }
|
|
|
|
|
- else { selectedFile = FileOpTarget.Local(item); selectedFiles = setOf(item.path) }
|
|
|
|
|
|
|
+ if (item.isDirectory) {
|
|
|
|
|
+ refreshLocal(item.path)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ selectedFile = FileOpTarget.Local(item)
|
|
|
|
|
+ selectedFiles = setOf(item.path)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- fun goUpLocal() { File(localCurrentPath).parentFile?.let { refreshLocal(it.absolutePath) } }
|
|
|
|
|
|
|
+ fun goUpLocal() {
|
|
|
|
|
+ File(localCurrentPath).parentFile?.let { refreshLocal(it.absolutePath) }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// ======================== SFTP ========================
|
|
// ======================== SFTP ========================
|
|
|
fun connectSsh(cfg: SshConfig) {
|
|
fun connectSsh(cfg: SshConfig) {
|
|
@@ -206,6 +239,10 @@ class FileBrowserViewModel(private val context: Context) : ViewModel() {
|
|
|
fun refreshSftp(path: String? = null) {
|
|
fun refreshSftp(path: String? = null) {
|
|
|
viewModelScope.launch(Dispatchers.IO) {
|
|
viewModelScope.launch(Dispatchers.IO) {
|
|
|
val p = path ?: sftpCurrentPath
|
|
val p = path ?: sftpCurrentPath
|
|
|
|
|
+ if (p != sftpCurrentPath) {
|
|
|
|
|
+ sftpBackHistory = sftpBackHistory + sftpCurrentPath
|
|
|
|
|
+ sftpForwardHistory = emptyList()
|
|
|
|
|
+ }
|
|
|
val result = sftpManager.listDirectory(p)
|
|
val result = sftpManager.listDirectory(p)
|
|
|
if (result.isSuccess) {
|
|
if (result.isSuccess) {
|
|
|
sftpCurrentPath = p
|
|
sftpCurrentPath = p
|
|
@@ -216,6 +253,26 @@ class FileBrowserViewModel(private val context: Context) : ViewModel() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ fun goBackSftp() {
|
|
|
|
|
+ if (sftpBackHistory.isEmpty()) return
|
|
|
|
|
+ viewModelScope.launch {
|
|
|
|
|
+ val prev = sftpBackHistory.last()
|
|
|
|
|
+ sftpBackHistory = sftpBackHistory.dropLast(1)
|
|
|
|
|
+ sftpForwardHistory = listOf(sftpCurrentPath) + sftpForwardHistory
|
|
|
|
|
+ refreshSftp(prev)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun goForwardSftp() {
|
|
|
|
|
+ if (sftpForwardHistory.isEmpty()) return
|
|
|
|
|
+ viewModelScope.launch {
|
|
|
|
|
+ val next = sftpForwardHistory.first()
|
|
|
|
|
+ sftpForwardHistory = sftpForwardHistory.drop(1)
|
|
|
|
|
+ sftpBackHistory = sftpBackHistory + sftpCurrentPath
|
|
|
|
|
+ refreshSftp(next)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
fun navigateSftp(item: SftpFile) {
|
|
fun navigateSftp(item: SftpFile) {
|
|
|
if (item.isDirectory) { refreshSftp(item.path) }
|
|
if (item.isDirectory) { refreshSftp(item.path) }
|
|
|
else { selectedFile = FileOpTarget.Sftp(item); selectedFiles = setOf(item.path) }
|
|
else { selectedFile = FileOpTarget.Sftp(item); selectedFiles = setOf(item.path) }
|
|
@@ -281,6 +338,17 @@ class FileBrowserViewModel(private val context: Context) : ViewModel() {
|
|
|
operationState = UiState.Error("操作异常: ${e.message}")
|
|
operationState = UiState.Error("操作异常: ${e.message}")
|
|
|
}
|
|
}
|
|
|
currentOperation = null
|
|
currentOperation = null
|
|
|
|
|
+ clearOperationState()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun clearOperationState() {
|
|
|
|
|
+ viewModelScope.launch {
|
|
|
|
|
+ delay(1000)
|
|
|
|
|
+ if (operationState !is UiState.Idle) {
|
|
|
|
|
+ operationState = UiState.Idle
|
|
|
|
|
+ selectedFile = null
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -329,6 +397,7 @@ class FileBrowserViewModel(private val context: Context) : ViewModel() {
|
|
|
clearSelection()
|
|
clearSelection()
|
|
|
}
|
|
}
|
|
|
currentOperation = null
|
|
currentOperation = null
|
|
|
|
|
+ clearOperationState()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|