diff --git a/app/src/main/java/com/itsaky/androidide/fragments/CloneRepositoryFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/CloneRepositoryFragment.kt
index 6cdf18215f..b462f08995 100644
--- a/app/src/main/java/com/itsaky/androidide/fragments/CloneRepositoryFragment.kt
+++ b/app/src/main/java/com/itsaky/androidide/fragments/CloneRepositoryFragment.kt
@@ -82,12 +82,11 @@ class CloneRepositoryFragment : BaseFragment() {
}
cloneButton.setOnClickListener {
- val url = repoUrl.text.toString()
- val path = localPath.text.toString()
- val username = if (authCheckbox.isChecked) username.text.toString() else null
- val password = if (authCheckbox.isChecked) password.text.toString() else null
-
- viewModel.cloneRepository(url, path, username, password)
+ cloneRepo()
+ }
+
+ retryButton.setOnClickListener {
+ cloneRepo()
}
exitButton.setOnClickListener {
@@ -110,6 +109,15 @@ class CloneRepositoryFragment : BaseFragment() {
}
}
+ private fun FragmentCloneRepositoryBinding.cloneRepo() {
+ val url = repoUrl.text.toString()
+ val path = localPath.text.toString()
+ val mUsername = if (authCheckbox.isChecked) username.text.toString() else null
+ val mPassword = if (authCheckbox.isChecked) password.text.toString() else null
+
+ viewModel.cloneRepository(url, path, mUsername, mPassword)
+ }
+
private fun observeViewModel() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -140,14 +148,17 @@ class CloneRepositoryFragment : BaseFragment() {
when (state) {
is CloneRepoUiState.Idle -> {
cloneButton.isEnabled = state.isCloneButtonEnabled
+ retryButton.visibility = View.GONE
statusText.text = ""
}
is CloneRepoUiState.Cloning -> {
cloneButton.isEnabled = false
+ retryButton.visibility = View.GONE
statusText.text = getString(R.string.cloning_repo)
}
is CloneRepoUiState.Error -> {
cloneButton.isEnabled = true
+ retryButton.visibility = View.VISIBLE
val statusMessage = state.errorResId?.let { getString(it) } ?: state.errorMessage
statusText.text = statusMessage
}
diff --git a/app/src/main/java/com/itsaky/androidide/viewmodel/CloneRepositoryViewModel.kt b/app/src/main/java/com/itsaky/androidide/viewmodel/CloneRepositoryViewModel.kt
index f6379ddcb7..650652921a 100644
--- a/app/src/main/java/com/itsaky/androidide/viewmodel/CloneRepositoryViewModel.kt
+++ b/app/src/main/java/com/itsaky/androidide/viewmodel/CloneRepositoryViewModel.kt
@@ -4,7 +4,6 @@ import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.application
import androidx.lifecycle.viewModelScope
-import com.itsaky.androidide.R
import com.itsaky.androidide.git.core.GitRepositoryManager
import com.itsaky.androidide.git.core.models.CloneRepoUiState
import kotlinx.coroutines.Dispatchers
@@ -16,7 +15,12 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.eclipse.jgit.lib.ProgressMonitor
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider
+import org.eclipse.jgit.api.errors.TransportException
+import java.net.UnknownHostException
+import java.io.EOFException
import java.io.File
+import com.blankj.utilcode.util.NetworkUtils
+import com.itsaky.androidide.resources.R
class CloneRepositoryViewModel(application: Application) : AndroidViewModel(application) {
@@ -67,6 +71,17 @@ class CloneRepositoryViewModel(application: Application) : AndroidViewModel(appl
return
}
+ if (!NetworkUtils.isConnected()) {
+ _uiState.update {
+ CloneRepoUiState.Error(
+ url = url,
+ localPath = localPath,
+ errorResId = R.string.no_internet_connection
+ )
+ }
+ return
+ }
+
viewModelScope.launch {
var hasCloned = false
_uiState.update {
@@ -143,12 +158,28 @@ class CloneRepositoryViewModel(application: Application) : AndroidViewModel(appl
CloneRepoUiState.Success(localPath = localPath)
}
} catch (e: Exception) {
- val errorMessage = e.message ?: application.getString(R.string.unknown_error)
+ // Error handling
+ val isNetworkError = e is TransportException && e.cause is UnknownHostException
+ val isConnectionDrop = e.cause is EOFException ||
+ e.message?.contains("Unexpected end of stream") == true ||
+ e.message?.contains("Software caused connection abort") == true
+
+ val errorResId = when {
+ isNetworkError -> R.string.no_internet_connection
+ isConnectionDrop -> R.string.connection_lost
+ else -> null
+ }
+
+ val errorMessage = if (errorResId == null) {
+ e.message ?: application.getString(R.string.unknown_error)
+ } else null
+
_uiState.update {
CloneRepoUiState.Error(
url = url,
localPath = localPath,
- errorMessage = application.getString(R.string.clone_failed, errorMessage)
+ errorResId = errorResId,
+ errorMessage = errorMessage?.let { application.getString(R.string.clone_failed, it) }
)
}
} finally {
diff --git a/app/src/main/res/layout/fragment_clone_repository.xml b/app/src/main/res/layout/fragment_clone_repository.xml
index 8b6b90b732..7b2e9e863a 100644
--- a/app/src/main/res/layout/fragment_clone_repository.xml
+++ b/app/src/main/res/layout/fragment_clone_repository.xml
@@ -1,156 +1,175 @@
-
-
-
-
+ android:layout_margin="16dp">
-
-
-
-
-
-
-
+
+
+ android:layout_marginTop="12dp"
+ android:hint="@string/repository_url"
+ app:layout_constraintTop_toBottomOf="@id/tv_download_project">
-
+
-
-
-
+
-
+ android:layout_marginTop="16dp"
+ android:hint="@string/local_path"
+ app:endIconContentDescription="@string/pick_folder"
+ app:endIconDrawable="@drawable/ic_folder"
+ app:endIconMode="custom"
+ app:layout_constraintTop_toBottomOf="@id/repoUrlLayout">
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
-
-
+ android:layout_marginTop="16dp"
+ android:hint="@string/personal_access_token"
+ app:endIconMode="password_toggle"
+ app:layout_constraintTop_toBottomOf="@id/usernameLayout">
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e728ab5e68..563068d8d0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -19,10 +19,4 @@
Code on the Go
Use simplified prompt
- File added
- File modified
- File deleted
- File untracked
- File renamed
- File conflicted
diff --git a/resources/src/main/res/values/strings.xml b/resources/src/main/res/values/strings.xml
index 5c286cf69e..ce66925024 100644
--- a/resources/src/main/res/values/strings.xml
+++ b/resources/src/main/res/values/strings.xml
@@ -1167,4 +1167,12 @@
Unable to load diff
Diff Viewer
Loading Git Diff…
+ No internet connection. Please check your network and try again.
+ Connection lost during download. Please check your internet connection and try again.
+ File added
+ File modified
+ File deleted
+ File untracked
+ File renamed
+ Conflicted File