diff --git a/app/src/main/java/com/kosbarokah/sshclient/ui/ConnectActivity.kt b/app/src/main/java/com/kosbarokah/sshclient/ui/ConnectActivity.kt index ee45dfd..e05f7a9 100644 --- a/app/src/main/java/com/kosbarokah/sshclient/ui/ConnectActivity.kt +++ b/app/src/main/java/com/kosbarokah/sshclient/ui/ConnectActivity.kt @@ -6,7 +6,9 @@ import android.view.LayoutInflater import android.view.ViewGroup import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.floatingactionbutton.FloatingActionButton @@ -29,16 +31,47 @@ class ConnectActivity : AppCompatActivity() { setContentView(R.layout.activity_connect) store = SecureStore(this) - adapter = ProfileAdapter { profile -> - val intent = Intent(this, TerminalActivity::class.java) - intent.putExtra("profile_id", profile.id) - startActivity(intent) - } + adapter = ProfileAdapter( + onOpen = { profile -> + val intent = Intent(this, TerminalActivity::class.java) + intent.putExtra("profile_id", profile.id) + startActivity(intent) + }, + onEdit = { profile -> openEditor(profile.id) } + ) val list = findViewById(R.id.profileList) list.layoutManager = LinearLayoutManager(this) list.adapter = adapter + // Swipe: kiri = hapus, kanan = edit. + ItemTouchHelper(object : ItemTouchHelper.Callback() { + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int = + makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) + + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean = false + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val pos = viewHolder.bindingAdapterPosition + val profile = adapter.itemAt(pos) ?: return + if (direction == ItemTouchHelper.LEFT) { + confirmDelete(profile) + } else { + openEditor(profile.id) + } + // Selalu kembalikan item ke tempatnya; hapus hanya setelah konfirmasi, + // edit hanya memindahkan ke layar editor. + adapter.notifyItemChanged(pos) + } + }).attachToRecyclerView(list) + findViewById(R.id.fabAdd).setOnClickListener { editorLauncher.launch(Intent(this, ProfileEditorActivity::class.java)) } @@ -51,6 +84,27 @@ class ConnectActivity : AppCompatActivity() { refresh() } + private fun openEditor(profileId: String) { + val intent = Intent(this, ProfileEditorActivity::class.java) + intent.putExtra("profile_id", profileId) + editorLauncher.launch(intent) + } + + private fun confirmDelete(profile: ServerProfile) { + AlertDialog.Builder(this) + .setTitle("Hapus profil") + .setMessage( + "Hapus profil \"${profile.name}\" (${profile.host})?\n" + + "Kredensial tersimpan juga akan ikut terhapus." + ) + .setPositiveButton("Hapus") { _, _ -> + store.deleteProfile(profile.id) + refresh() + } + .setNegativeButton("Batal", null) + .show() + } + private fun refresh() { adapter.submit(store.getProfiles()) findViewById(R.id.emptyHint).visibility = @@ -59,7 +113,8 @@ class ConnectActivity : AppCompatActivity() { } private class ProfileAdapter( - private val onOpen: (ServerProfile) -> Unit + private val onOpen: (ServerProfile) -> Unit, + private val onEdit: (ServerProfile) -> Unit ) : RecyclerView.Adapter() { private var items: List = emptyList() @@ -69,6 +124,9 @@ class ConnectActivity : AppCompatActivity() { notifyDataSetChanged() } + fun itemAt(position: Int): ServerProfile? = + if (position in items.indices) items[position] else null + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH { val v = LayoutInflater.from(parent.context) .inflate(R.layout.item_profile, parent, false)