List profil: swipe-kiri hapus (dengan konfirmasi), swipe-kanan edit

- ItemTouchHelper: swipe kiri -> dialog konfirmasi hapus profil (+kredensial)
- Swipe kanan -> buka ProfileEditorActivity untuk edit
- Item kembali ke posisi semula setelah swipe (hapus menunggu konfirmasi,
  edit pindah ke layar editor)
- ConnectActivity refactor: callback onEdit, helper openEditor(profileId)
This commit is contained in:
2026-08-30 23:27:44 +07:00
parent c0c6dab473
commit e9ded3d17a

View File

@@ -6,7 +6,9 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
@@ -29,16 +31,47 @@ class ConnectActivity : AppCompatActivity() {
setContentView(R.layout.activity_connect) setContentView(R.layout.activity_connect)
store = SecureStore(this) store = SecureStore(this)
adapter = ProfileAdapter { profile -> adapter = ProfileAdapter(
onOpen = { profile ->
val intent = Intent(this, TerminalActivity::class.java) val intent = Intent(this, TerminalActivity::class.java)
intent.putExtra("profile_id", profile.id) intent.putExtra("profile_id", profile.id)
startActivity(intent) startActivity(intent)
} },
onEdit = { profile -> openEditor(profile.id) }
)
val list = findViewById<RecyclerView>(R.id.profileList) val list = findViewById<RecyclerView>(R.id.profileList)
list.layoutManager = LinearLayoutManager(this) list.layoutManager = LinearLayoutManager(this)
list.adapter = adapter 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<FloatingActionButton>(R.id.fabAdd).setOnClickListener { findViewById<FloatingActionButton>(R.id.fabAdd).setOnClickListener {
editorLauncher.launch(Intent(this, ProfileEditorActivity::class.java)) editorLauncher.launch(Intent(this, ProfileEditorActivity::class.java))
} }
@@ -51,6 +84,27 @@ class ConnectActivity : AppCompatActivity() {
refresh() 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() { private fun refresh() {
adapter.submit(store.getProfiles()) adapter.submit(store.getProfiles())
findViewById<TextView>(R.id.emptyHint).visibility = findViewById<TextView>(R.id.emptyHint).visibility =
@@ -59,7 +113,8 @@ class ConnectActivity : AppCompatActivity() {
} }
private class ProfileAdapter( private class ProfileAdapter(
private val onOpen: (ServerProfile) -> Unit private val onOpen: (ServerProfile) -> Unit,
private val onEdit: (ServerProfile) -> Unit
) : RecyclerView.Adapter<ProfileAdapter.VH>() { ) : RecyclerView.Adapter<ProfileAdapter.VH>() {
private var items: List<ServerProfile> = emptyList() private var items: List<ServerProfile> = emptyList()
@@ -69,6 +124,9 @@ class ConnectActivity : AppCompatActivity() {
notifyDataSetChanged() notifyDataSetChanged()
} }
fun itemAt(position: Int): ServerProfile? =
if (position in items.indices) items[position] else null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
val v = LayoutInflater.from(parent.context) val v = LayoutInflater.from(parent.context)
.inflate(R.layout.item_profile, parent, false) .inflate(R.layout.item_profile, parent, false)